From 2fc6f709d9ae124470fad658d0e7cab7d542de3d Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Fri, 28 Feb 2025 18:47:58 +0700
Subject: [PATCH 01/53] [*] Condition owner collect & check corrections

---
 dap-sdk                                       |   2 +-
 modules/net/dap_chain_ledger.c                | 304 ++++++------------
 modules/net/include/dap_chain_ledger.h        |  22 +-
 .../service/voting/dap_chain_net_srv_voting.c |  65 ++--
 4 files changed, 133 insertions(+), 260 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index d9b03ffb93..3491640b76 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit d9b03ffb93d4003cb1a33c6470612a7f88ad6005
+Subproject commit 3491640b76de5715eb3936ccd377abd51d88b99e
diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c
index 1a883dd8dd..03fcb33ba6 100644
--- a/modules/net/dap_chain_ledger.c
+++ b/modules/net/dap_chain_ledger.c
@@ -288,8 +288,6 @@ typedef struct dap_ledger_private {
 
 #define PVT(a) ( (dap_ledger_private_t *) a->_internal )
 
-static  dap_ledger_tx_item_t* tx_item_find_by_addr(dap_ledger_t *a_ledger,
-        const dap_chain_addr_t *a_addr, const char * a_token, dap_chain_hash_fast_t *a_tx_first_hash);
 static void s_threshold_emissions_proc( dap_ledger_t * a_ledger);
 static void s_threshold_txs_proc( dap_ledger_t * a_ledger);
 static void s_threshold_txs_free(dap_ledger_t *a_ledger);
@@ -5273,8 +5271,8 @@ uint256_t dap_ledger_calc_balance_full(dap_ledger_t *a_ledger, const dap_chain_a
  * a_public_key_size[in] public key size
  * a_tx_first_hash [in/out] hash of the initial transaction/ found transaction, if 0 start from the beginning
  */
-static dap_ledger_tx_item_t *tx_item_find_by_addr(dap_ledger_t *a_ledger, const dap_chain_addr_t *a_addr,
-                                                        const char * a_token, dap_chain_hash_fast_t *a_tx_first_hash)
+dap_chain_datum_tx_t *dap_ledger_tx_find_by_addr(dap_ledger_t *a_ledger, const char *a_token,
+                                                 const dap_chain_addr_t *a_addr, dap_chain_hash_fast_t *a_tx_first_hash)
 {
     if(!a_addr || !a_tx_first_hash)
         return NULL;
@@ -5331,20 +5329,7 @@ static dap_ledger_tx_item_t *tx_item_find_by_addr(dap_ledger_t *a_ledger, const
             break;
     }
     pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock);
-    return is_tx_found ? l_iter_current : NULL;
-}
-
-/**
- * @brief dap_ledger_tx_find_by_addr
- * @param a_addr
- * @param a_tx_first_hash
- * @return
- */
- dap_chain_datum_tx_t* dap_ledger_tx_find_by_addr(dap_ledger_t *a_ledger , const char * a_token ,
-         const dap_chain_addr_t *a_addr, dap_chain_hash_fast_t *a_tx_first_hash)
-{
-    dap_ledger_tx_item_t* l_tx_item = tx_item_find_by_addr(a_ledger, a_addr, a_token, a_tx_first_hash);
-    return (l_tx_item) ? l_tx_item->tx : NULL;
+    return is_tx_found ? l_iter_current->tx : NULL;
 }
 
  bool dap_ledger_tx_check_recipient(dap_ledger_t* a_ledger, dap_chain_hash_fast_t* a_tx_prev_hash, dap_chain_addr_t *a_addr)
@@ -5374,52 +5359,6 @@ static dap_ledger_tx_item_t *tx_item_find_by_addr(dap_ledger_t *a_ledger, const
     return false;
  }
 
-/**
- * Get the transaction in the cache by the public key that signed the transaction,
- * starting from the next hash after a_tx_first_hash
- *
- * a_public_key[in] public key that signed the transaction
- * a_public_key_size[in] public key size
- * a_tx_first_hash [in/out] hash of the initial transaction/ found transaction, if 0 start from the beginning
- */
-const dap_chain_datum_tx_t* dap_ledger_tx_find_by_pkey(dap_ledger_t *a_ledger,
-        char *a_public_key, size_t a_public_key_size, dap_chain_hash_fast_t *a_tx_first_hash)
-{
-    if(!a_public_key || !a_tx_first_hash)
-        return NULL;
-    dap_ledger_private_t *l_ledger_pvt = 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);
-    bool is_search_enable = is_null_hash;
-    dap_ledger_tx_item_t *l_iter_current, *l_item_tmp;
-    pthread_rwlock_rdlock(&l_ledger_pvt->ledger_rwlock);
-    HASH_ITER(hh, l_ledger_pvt->ledger_items , l_iter_current, l_item_tmp) {
-        dap_chain_datum_tx_t *l_tx_tmp = l_iter_current->tx;
-        dap_chain_hash_fast_t *l_tx_hash_tmp = &l_iter_current->tx_hash_fast;
-        // start searching from the next hash after a_tx_first_hash
-        if (!is_search_enable) {
-            is_search_enable = dap_hash_fast_compare(l_tx_hash_tmp, a_tx_first_hash);
-            continue;
-        }
-        // Get sign item from transaction
-        dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(l_tx_tmp, NULL,
-                NULL, TX_ITEM_TYPE_SIG, NULL);
-        // Get dap_sign_t from item
-        dap_sign_t *l_sig = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
-        if(l_sig) {
-            // compare public key in transaction with a_public_key
-            if(a_public_key_size == l_sig->header.sign_pkey_size &&
-                    !memcmp(a_public_key, l_sig->pkey_n_sign, a_public_key_size)) {
-                l_cur_tx = l_tx_tmp;
-                memcpy(a_tx_first_hash, l_tx_hash_tmp, sizeof(dap_chain_hash_fast_t));
-                break;
-            }
-        }
-    }
-    pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock);
-    return l_cur_tx;
-}
-
 /**
  * @brief Get all transactions from the cache with the out_cond item
  * @param a_ledger
@@ -5442,93 +5381,6 @@ dap_list_t* dap_ledger_tx_cache_find_out_cond_all(dap_ledger_t *a_ledger, dap_ch
     return l_ret;
 }
 
-
-/**
- * Get the transaction in the cache with the out_cond item
- *
- * a_addr[in] wallet address, whose owner can use the service
- */
-dap_chain_datum_tx_t* dap_ledger_tx_cache_find_out_cond(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type,
-        dap_chain_hash_fast_t *a_tx_first_hash, dap_chain_tx_out_cond_t **a_out_cond, int *a_out_cond_idx, char *a_token_ticker)
-{
-    if (!a_tx_first_hash)
-        return NULL;
-    dap_ledger_private_t *l_ledger_pvt = 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);
-    bool is_search_enable = is_null_hash;
-    dap_ledger_tx_item_t *l_iter_current = NULL, *l_item_tmp = NULL;
-    dap_chain_tx_out_cond_t *l_tx_out_cond = NULL;
-    int l_tx_out_cond_idx = 0;
-    pthread_rwlock_rdlock(&l_ledger_pvt->ledger_rwlock);
-    HASH_ITER(hh, l_ledger_pvt->ledger_items, l_iter_current, l_item_tmp) {
-        dap_chain_datum_tx_t *l_tx_tmp = l_iter_current->tx;
-        dap_chain_hash_fast_t *l_tx_hash_tmp = &l_iter_current->tx_hash_fast;
-        // start searching from the next hash after a_tx_first_hash
-        if (!is_search_enable) {
-            is_search_enable = dap_hash_fast_compare(l_tx_hash_tmp, a_tx_first_hash);
-            continue;
-        }
-        // Get out_cond item from transaction
-        l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_tmp, a_cond_type, &l_tx_out_cond_idx);
-
-        if(l_tx_out_cond) {
-            l_cur_tx = l_tx_tmp;
-            memcpy(a_tx_first_hash, l_tx_hash_tmp, sizeof(dap_chain_hash_fast_t));
-            if (a_token_ticker) {
-                strcpy(a_token_ticker, l_iter_current->cache_data.token_ticker);
-            }
-            break;
-        }
-    }
-    pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock);
-    if (a_out_cond) {
-        *a_out_cond = l_tx_out_cond;
-    }
-    if (a_out_cond_idx) {
-        *a_out_cond_idx = l_tx_out_cond_idx;
-    }
-    return l_cur_tx;
-}
-
-/**
- * Get the value from all transactions in the cache with out_cond item
- *
- * a_addr[in] wallet address, whose owner can use the service
- * a_sign [in] signature of a_addr hash for check valid key
- * a_sign_size [in] signature size
- *
- * a_public_key[in] public key that signed the transaction
- * a_public_key_size[in] public key size
- */
-uint256_t dap_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type,
-                                                       dap_chain_addr_t *a_addr, dap_chain_tx_out_cond_t **tx_out_cond)
-
-{
-    uint256_t l_ret_value = {};
-
-    dap_chain_datum_tx_t *l_tx_tmp;
-    dap_chain_hash_fast_t l_tx_first_hash = { 0 }; // start hash
-    /* size_t l_pub_key_size = a_key_from->pub_key_data_size;
-     uint8_t *l_pub_key = dap_enc_key_serialize_pub_key(a_key_from, &l_pub_key_size);*/
-    dap_chain_tx_out_cond_t *l_tx_out_cond;
-    // Find all transactions
-    do {
-        l_tx_tmp = dap_ledger_tx_cache_find_out_cond(a_ledger, a_cond_type, &l_tx_first_hash, &l_tx_out_cond, NULL, NULL);
-        // Get out_cond item from transaction
-        if(l_tx_tmp) {
-            UNUSED(a_addr);
-            // TODO check relations a_addr with cond_data and public key
-            if(l_tx_out_cond) {
-                l_ret_value = l_tx_out_cond->header.value;
-                if(tx_out_cond)
-                    *tx_out_cond = l_tx_out_cond;
-            }
-        }
-    } while(l_tx_tmp);
-    return l_ret_value;
-}
-
 /**
  * @brief dap_ledger_get_list_tx_outs_with_val
  * @param a_ledger
@@ -5784,7 +5636,7 @@ dap_chain_datum_tx_t *dap_ledger_datum_iter_get_last(dap_ledger_datum_iter_t *a_
 {
     dap_ledger_private_t *l_ledger_pvt = PVT(a_iter->net->pub.ledger);
     pthread_rwlock_rdlock(&l_ledger_pvt->ledger_rwlock);
-    a_iter->cur_ledger_tx_item = l_ledger_pvt->ledger_items->hh.prev;
+    a_iter->cur_ledger_tx_item = HASH_LAST(l_ledger_pvt->ledger_items);
     a_iter->cur = ((dap_ledger_tx_item_t *)(a_iter->cur_ledger_tx_item))->tx;
     a_iter->cur_hash = ((dap_ledger_tx_item_t *)(a_iter->cur_ledger_tx_item))->tx_hash_fast;
     a_iter->is_unspent = ((dap_ledger_tx_item_t *)(a_iter->cur_ledger_tx_item))->cache_data.ts_spent ? false : true;
@@ -5793,72 +5645,116 @@ dap_chain_datum_tx_t *dap_ledger_datum_iter_get_last(dap_ledger_datum_iter_t *a_
     return a_iter->cur;
 }
 
-
 /**
- * @brief dap_ledger_get_list_tx_cond_outs_with_val
- * @param a_ledger
- * @param a_token_ticker
- * @param a_addr_from
- * @param a_subtype
- * @param a_value_need
- * @param a_value_transfer
- * @return
+ * Get the transaction in the cache by the addr in sig item
+ *
+ * a_addr[in] public key that signed the transaction
+ * a_tx_first_hash [in/out] hash of the initial transaction/ found transaction, if 0 start from the beginning
  */
-dap_list_t *dap_ledger_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledger, const char *a_token_ticker,  const dap_chain_addr_t *a_addr_from,
-        dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t a_value_need, uint256_t *a_value_transfer)
+dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t *a_ledger, const char *a_token, dap_chain_tx_out_cond_subtype_t a_subtype,
+                                                                  const dap_chain_addr_t *a_addr, dap_chain_hash_fast_t *a_tx_first_hash, int *a_out_idx)
 {
-    dap_list_t *l_list_used_out = NULL; // list of transaction with 'out' items
-    dap_chain_hash_fast_t l_tx_cur_hash = { 0 };
-    uint256_t l_value_transfer = { };
-    dap_chain_datum_tx_t *l_tx;
-    while( compare256(l_value_transfer, a_value_need) == -1 
-        && ( l_tx = dap_ledger_tx_find_by_addr(a_ledger, a_token_ticker, a_addr_from, &l_tx_cur_hash)) )
-    {
-        byte_t *it; size_t l_size; int i, l_out_idx_tmp = -1;
-        TX_ITEM_ITER_TX_TYPE(it, TX_ITEM_TYPE_OUT_COND, l_size, i, l_tx) {
-            ++l_out_idx_tmp;
-            dap_chain_tx_out_cond_t *l_out_cond = (dap_chain_tx_out_cond_t*) it;
-            if (a_subtype != l_out_cond->header.subtype || IS_ZERO_256(l_out_cond->header.value) )
-                continue;
-            dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t);
-            *l_item = (dap_chain_tx_used_out_item_t) { l_tx_cur_hash, (uint32_t)l_out_idx_tmp, l_out_cond->header.value };
-            l_list_used_out = dap_list_append(l_list_used_out, l_item);
-            SUM_256_256(l_value_transfer, l_item->value, &l_value_transfer);
-            // already accumulated the required value, finish the search for 'out' items
-            if ( compare256(l_value_transfer, a_value_need) != -1 ) {
+    if (!a_addr || !a_token)
+        return NULL;
+    dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
+    dap_chain_tx_out_cond_t *ret = NULL;
+    dap_ledger_tx_item_t *l_iter_start = NULL, *it;
+    pthread_rwlock_rdlock(&l_ledger_pvt->ledger_rwlock);
+    if (a_tx_first_hash && !dap_hash_fast_is_blank(a_tx_first_hash)) {
+        HASH_FIND(hh, l_ledger_pvt->ledger_items, a_tx_first_hash, sizeof(dap_hash_t), l_iter_start);
+        if (!l_iter_start || !l_iter_start->hh.next) {
+            pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock);
+            return NULL;
+        }
+        // start searching from the next hash after a_tx_first_hash
+        l_iter_start = l_iter_start->hh.next;
+    } else
+        l_iter_start = l_ledger_pvt->ledger_items;
+    for (it = l_iter_start; it; it = it->hh.next) {
+        // If a_token is setup we check if its not our token - miss it
+        if (*it->cache_data.token_ticker && dap_strcmp(it->cache_data.token_ticker, a_token))
+            continue;
+        ret = NULL;
+        // Get 'out_cond' item from transaction
+        byte_t *l_item; size_t l_size; int i, l_out_idx = 0;
+        TX_ITEM_ITER_TX_TYPE(l_item, TX_ITEM_TYPE_OUT_ALL, l_size, i, it->tx) {
+            if (*l_item == TX_ITEM_TYPE_OUT_COND &&
+                    ((dap_chain_tx_out_cond_t *)l_item)->header.subtype == a_subtype) {
+                ret = (dap_chain_tx_out_cond_t *)l_item;
                 break;
             }
+            l_out_idx++;
+        }
+        // Don't return regular tx or spent conditions
+        if (!ret || !dap_hash_fast_is_blank(&it->cache_data.tx_hash_spent_fast[l_out_idx]))
+            continue;
+        dap_hash_fast_t l_owner_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, it->tx, a_subtype);
+        dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_ledger, &l_owner_tx_hash);
+        if (!l_tx) {
+            log_it(L_ERROR, "Can't find owner for tx %s", dap_hash_fast_to_str_static(&it->tx_hash_fast));
+            continue;
+        }
+        // Get sign item from transaction
+        dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_SIG, NULL);
+        // Get dap_sign_t from item
+        dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
+        // compare public key in transaction with a_public_key
+        dap_chain_hash_fast_t l_sign_hash = {};
+        dap_sign_get_pkey_hash(l_sign, &l_sign_hash);
+        if (dap_hash_fast_compare(&l_sign_hash, &a_addr->data.hash_fast)) {
+            if (a_tx_first_hash)
+                *a_tx_first_hash = it->tx_hash_fast;
+            if (a_out_idx)
+                *a_out_idx = l_out_idx;
+            break;
         }
     }
-    return compare256(l_value_transfer, a_value_need) > -1 && l_list_used_out
-        ? ({ if (a_value_transfer) *a_value_transfer = l_value_transfer; l_list_used_out; })
-        : ( dap_list_free_full(l_list_used_out, NULL), NULL );
+    pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock);
+    return ret;
 }
 
-dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, const char *a_token_ticker,  const dap_chain_addr_t *a_addr_from,
-                                             dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t *a_value_transfer)
+dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_subtype,
+                                             const char *a_token_ticker,  const dap_chain_addr_t *a_addr_from)
 {
     dap_list_t *l_list_used_out = NULL; // list of transaction with 'out' items
     dap_chain_hash_fast_t l_tx_cur_hash = { };
-    uint256_t l_value_transfer = { };
-    dap_chain_datum_tx_t *l_tx;
-    while(( l_tx = dap_ledger_tx_find_by_addr(a_ledger, a_token_ticker, a_addr_from, &l_tx_cur_hash) )) {
-        byte_t *it; size_t l_size; int i, l_out_idx_tmp = -1;
-        TX_ITEM_ITER_TX_TYPE(it, TX_ITEM_TYPE_OUT_COND, l_size, i, l_tx) {
-            ++l_out_idx_tmp;
-            dap_chain_tx_out_cond_t *l_out_cond = (dap_chain_tx_out_cond_t*)it;
-            if ( a_subtype != l_out_cond->header.subtype || IS_ZERO_256(l_out_cond->header.value) )
-                continue;
-            dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t);
-            *l_item = (dap_chain_tx_used_out_item_t) { l_tx_cur_hash, (uint32_t)l_out_idx_tmp, l_out_cond->header.value };
-            l_list_used_out = dap_list_append(l_list_used_out, l_item);
-            SUM_256_256(l_value_transfer, l_item->value, &l_value_transfer);
-        }
+    int l_out_idx;
+    dap_chain_tx_out_cond_t *l_cond;
+    while ( (l_cond = dap_ledger_out_cond_unspent_find_by_addr(a_ledger, a_token_ticker, a_subtype, a_addr_from, &l_tx_cur_hash, &l_out_idx)) ) {
+        dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t);
+        *l_item = (dap_chain_tx_used_out_item_t) { l_tx_cur_hash, (uint32_t)l_out_idx, l_cond->header.value };
+        l_list_used_out = dap_list_append(l_list_used_out, l_item);
     }
+    return l_list_used_out;
+}
 
-    return l_list_used_out
-        ? ({ if (a_value_transfer) *a_value_transfer = l_value_transfer; l_list_used_out; })
-        : ( dap_list_free_full(l_list_used_out, NULL), NULL );
+bool dap_ledger_check_condition_owner(dap_ledger_t *a_ledger, dap_hash_fast_t *a_tx_hash, dap_chain_tx_out_cond_subtype_t a_cond_subtype,
+                                      int a_out_idx, dap_sign_t *a_owner_sign)
+{
+    dap_return_val_if_fail(a_ledger && a_tx_hash && a_owner_sign, false);
+    // Get first tx
+    dap_chain_datum_tx_t *l_check_tx = dap_ledger_tx_find_by_hash(a_ledger, a_tx_hash);
+    if (!l_check_tx) {
+        log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(a_tx_hash));
+        return false;
+    }
+    dap_hash_fast_t l_first_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, l_check_tx, a_cond_subtype);
+    if (dap_hash_fast_is_blank(&l_first_tx_hash)) {
+        log_it(L_ERROR, "Can't find owner for tx %s", dap_hash_fast_to_str_static(a_tx_hash));
+        return false;
+    }
+    dap_chain_datum_tx_t *l_first_tx = dap_ledger_tx_find_by_hash(a_ledger, &l_first_tx_hash);
+    if (!l_first_tx) {
+        log_it(L_ERROR, "Can't find owner tx %s", dap_hash_fast_to_str_static(&l_first_tx_hash));
+        return false;
+    }
+    dap_chain_tx_sig_t *l_first_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_first_tx, NULL, 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_first_tx_sig);
+    if (!l_sign) {
+        log_it(L_ERROR, "Can't find signature for tx %s", dap_hash_fast_to_str_static(&l_first_tx_hash));
+        return false;
+    }
+    return dap_sign_compare_pkeys(a_owner_sign, l_sign);
 }
 
 void dap_ledger_tx_add_notify(dap_ledger_t *a_ledger, dap_ledger_tx_add_notify_t a_callback, void *a_arg) {
diff --git a/modules/net/include/dap_chain_ledger.h b/modules/net/include/dap_chain_ledger.h
index f2e43d962d..059b3142ee 100644
--- a/modules/net/include/dap_chain_ledger.h
+++ b/modules/net/include/dap_chain_ledger.h
@@ -418,21 +418,11 @@ dap_chain_datum_tx_t* dap_ledger_tx_find_by_addr(dap_ledger_t *a_ledger, const c
 
 bool dap_ledger_tx_check_recipient(dap_ledger_t* a_ledger, dap_chain_hash_fast_t* a_tx_prev_hash, dap_chain_addr_t *a_addr);
 
-// Get the transaction in the cache by the public key that signed the transaction, starting with a_tx_first_hash
-const dap_chain_datum_tx_t* dap_ledger_tx_find_by_pkey(dap_ledger_t *a_ledger,
-        char *a_public_key, size_t a_public_key_size, dap_chain_hash_fast_t *a_tx_first_hash);
-
-// Get the transaction in the cache with the out_cond item
-dap_chain_datum_tx_t* dap_ledger_tx_cache_find_out_cond(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type,
-                                                              dap_chain_hash_fast_t *a_tx_first_hash, dap_chain_tx_out_cond_t **a_out_cond,
-                                                              int *a_out_cond_idx, char *a_token_ticker);
-
 // Get all transactions from the cache with the specified out_cond items
 dap_list_t* dap_ledger_tx_cache_find_out_cond_all(dap_ledger_t *a_ledger, dap_chain_net_srv_uid_t a_srv_uid);
 
-// Get the value from all transactions in the cache with out_cond item
-uint256_t dap_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_addr_t *a_addr,
-                                                       dap_chain_tx_out_cond_t **tx_out_cond);
+dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t *a_ledger, const char *a_token, dap_chain_tx_out_cond_subtype_t a_subtype,
+                                                                  const dap_chain_addr_t *a_addr, dap_chain_hash_fast_t *a_tx_first_hash, int *a_out_idx);
 
 // Get the list of 'out' items from previous transactions with summary value >= than a_value_need
 // Put this summary value to a_value_transfer
@@ -440,12 +430,8 @@ dap_list_t *dap_ledger_get_list_tx_outs_with_val(dap_ledger_t *a_ledger, const c
                                                        uint256_t a_value_need, uint256_t *a_value_transfer);
 dap_list_t *dap_ledger_get_list_tx_outs(dap_ledger_t *a_ledger, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from,
                                         uint256_t *a_value_transfer);
-// Get the list of 'out_cond' items with summary value >= than a_value_need
-dap_list_t *dap_ledger_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledger, const char *a_token_ticker,  const dap_chain_addr_t *a_addr_from,
-        dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t a_value_need, uint256_t *a_value_transfer);
-
-dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, const char *a_token_ticker,  const dap_chain_addr_t *a_addr_from,
-                                             dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t *a_value_transfer);
+dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_subtype, const char *a_token_ticker,  const dap_chain_addr_t *a_addr_from);
+bool dap_ledger_check_condition_owner(dap_ledger_t *a_ledger, dap_hash_fast_t *a_tx_hash, dap_chain_tx_out_cond_subtype_t a_cond_subtype, int a_out_idx, dap_sign_t *a_owner_sign);
 // Add new verificator callback with associated subtype. Returns 1 if callback replaced, overwise returns 0
 int dap_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_ledger_verificator_callback_t a_callback,
                                      dap_ledger_updater_callback_t a_callback_added, dap_ledger_delete_callback_t a_callback_deleted);
diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index c74cf6fd33..3734ed953c 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -290,16 +290,9 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
     }
 
     dap_hash_fast_t pkey_hash = {};
-    int l_item_cnt = 0;
-    dap_list_t *l_signs_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_SIG, &l_item_cnt);
-
-    if (!l_signs_list) {
-        log_it(L_WARNING, "Can't get signs from tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
-        return -9;
-    }
-    dap_chain_tx_sig_t *l_vote_sig = (dap_chain_tx_sig_t *)(dap_list_last(l_signs_list)->data);
-    dap_sign_get_pkey_hash((dap_sign_t*)l_vote_sig->sig, &pkey_hash);
-    dap_list_free(l_signs_list);
+    // Get sign item from transaction
+    dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(a_tx_in, NULL, NULL, TX_ITEM_TYPE_SIG, NULL);
+    dap_sign_get_pkey_hash((dap_sign_t *)l_tx_sig->sig, &pkey_hash);
 
     if (!a_apply) {
         if (l_vote_tx_item->answer_idx > dap_list_length(l_voting->voting_params.option_offsets_list)) {
@@ -345,25 +338,27 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
         dap_tsd_t *l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t*)it->data)->tsd;
         dap_hash_fast_t l_hash = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->tx_hash;
         int l_out_idx = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->out_idx;
-        if (l_tsd->type == VOTING_TSD_TYPE_VOTE_TX_COND) {
-            if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx))
-                continue;
-            dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash);
-            dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t*)dap_chain_datum_tx_item_get(l_tx_prev_temp, &l_out_idx, NULL, TX_ITEM_TYPE_OUT_COND, NULL);
-            if (!l_prev_out || l_prev_out->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK)
-                continue;
-            if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) {
-                log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
-                return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW;
-            }
-
-            dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY);
-            l_item->tx_hash = l_hash;
-            l_item->out_idx = l_out_idx;
-            pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock);
-            HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item);
-            pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock);
-        }
+        if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND)
+            return -14;
+        if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx))
+            return -15;
+        dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash);
+        dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t*)dap_chain_datum_tx_item_get(l_tx_prev_temp, &l_out_idx, NULL, TX_ITEM_TYPE_OUT_COND, NULL);
+        if (!l_prev_out || l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
+            return -16;
+        if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, (dap_sign_t *)l_tx_sig->sig))
+            return -17;
+        if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) {
+            log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
+            return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW;
+        }
+
+        dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY);
+        l_item->tx_hash = l_hash;
+        l_item->out_idx = l_out_idx;
+        pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock);
+        HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item);
+        pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock);
     }
     dap_list_free(l_tsd_list);
     // check inputs
@@ -379,7 +374,7 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
             dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash);
             dap_chain_tx_out_t *l_prev_out_union = (dap_chain_tx_out_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_tx_in->header.tx_out_prev_idx);
             if (!l_prev_out_union)
-                continue;
+                return -18;
             if ((l_prev_out_union->header.type == TX_ITEM_TYPE_OUT || l_prev_out_union->header.type == TX_ITEM_TYPE_OUT_EXT) &&
                     SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) {
                 log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
@@ -1487,14 +1482,11 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
     DAP_DEL_Z(l_vote_item);
 
     // add stake out conds items
-    dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, a_net->pub.native_ticker,  l_addr_from,
-                                                          DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, NULL);
-    dap_list_t *l_temp = l_outs;
-    while(l_temp){
-        dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)l_temp->data;
+    dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, a_net->pub.native_ticker, l_addr_from);
+    for (dap_list_t *it = l_outs; it; it = it->next) {
+        dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data;
         if (dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_out_item->tx_hash_fast, l_out_item->num_idx_out, NULL) ||
             s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out ) != 0){
-            l_temp = l_temp->next;
             continue;
         }
         dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out);
@@ -1506,7 +1498,6 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
         }
         dap_chain_datum_tx_add_item(&l_tx, l_item);
         DAP_DEL_Z(l_item);
-        l_temp = l_temp->next;
     }
     dap_list_free_full(l_outs, NULL);
 
-- 
GitLab


From 34fcfbb3fd337bbacca15e91460fef0d5a258ff8 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Mon, 3 Mar 2025 18:16:09 +0700
Subject: [PATCH 02/53] [*] Voting with non-native token partial debug

---
 modules/common/dap_chain_datum_tx_voting.c    |  15 +
 .../include/dap_chain_datum_tx_voting.h       |   9 +-
 .../consensus/esbocs/dap_chain_cs_esbocs.c    |   5 +-
 modules/net/dap_chain_ledger.c                |  21 +-
 modules/net/dap_chain_net_tx.c                |   4 +-
 .../service/voting/dap_chain_net_srv_voting.c | 332 +++++++++++-------
 .../voting/include/dap_chain_net_srv_voting.h |   6 +-
 7 files changed, 246 insertions(+), 146 deletions(-)

diff --git a/modules/common/dap_chain_datum_tx_voting.c b/modules/common/dap_chain_datum_tx_voting.c
index 2a161dd3a9..eb2ab0320c 100644
--- a/modules/common/dap_chain_datum_tx_voting.c
+++ b/modules/common/dap_chain_datum_tx_voting.c
@@ -124,6 +124,18 @@ dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_changing_allowed_tsd_create(bool
     return l_tsd;
 }
 
+dap_chain_tx_tsd_t *dap_chain_datum_voting_token_tsd_create(const char *a_token_ticker)
+{
+    dap_return_val_if_fail(a_token_ticker && *a_token_ticker, NULL);
+    size_t l_ticker_len = strlen(a_token_ticker);
+    if (l_ticker_len >= DAP_CHAIN_TICKER_SIZE_MAX) {
+        log_it(L_ERROR, "Ticker len %zu is too big", l_ticker_len);
+        return NULL;
+    }
+    dap_chain_tx_tsd_t *l_tsd = dap_chain_datum_tx_item_tsd_create((char *)a_token_ticker, VOTING_TSD_TYPE_TOKEN, l_ticker_len);
+    return l_tsd;
+}
+
 dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_tx_cond_tsd_create(dap_chain_hash_fast_t a_tx_hash, int a_out_idx)
 {
     dap_chain_tx_voting_tx_cond_t l_temp = {
@@ -176,6 +188,9 @@ json_object *dap_chain_datum_tx_item_voting_tsd_to_json(dap_chain_datum_tx_t* a_
         case VOTING_TSD_TYPE_ANSWER:
             json_object_array_add(l_answer_array_object, json_object_new_string_len((char*)l_tsd->data, l_tsd->size));
             break;
+        case VOTING_TSD_TYPE_TOKEN:
+            json_object_object_add(l_object, "token", json_object_new_string_len((char*)l_tsd->data, l_tsd->size));
+            break;
         case VOTING_TSD_TYPE_EXPIRE:
             json_object_object_add(l_object, "exired", json_object_new_uint64(*(uint64_t*)l_tsd->data));
             break;
diff --git a/modules/common/include/dap_chain_datum_tx_voting.h b/modules/common/include/dap_chain_datum_tx_voting.h
index a87c67824c..add632997a 100644
--- a/modules/common/include/dap_chain_datum_tx_voting.h
+++ b/modules/common/include/dap_chain_datum_tx_voting.h
@@ -43,7 +43,8 @@ typedef enum dap_chain_datum_voting_tsd_type {
     VOTING_TSD_TYPE_MAX_VOTES_COUNT,
     VOTING_TSD_TYPE_DELEGATED_KEY_REQUIRED,
     VOTING_TSD_TYPE_VOTE_CHANGING_ALLOWED,
-    VOTING_TSD_TYPE_VOTE_TX_COND
+    VOTING_TSD_TYPE_VOTE_TX_COND,
+    VOTING_TSD_TYPE_TOKEN
 } dap_chain_datum_voting_tsd_type_t;
 
 typedef struct dap_chain_tx_voting {
@@ -63,13 +64,14 @@ typedef struct dap_chain_tx_vote {
 
 
 typedef struct dap_chain_datum_tx_voting_params {
-    char *voting_question;
+    char       *voting_question;
     dap_list_t *answers_list;
     uint8_t    answers_count;
     dap_time_t voting_expire;
     uint64_t   votes_max_count;
     bool       delegate_key_required;
     bool       vote_changing_allowed;
+    char       token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
 } dap_chain_datum_tx_voting_params_t;
 
 #ifdef __cplusplus
@@ -86,6 +88,7 @@ dap_chain_tx_tsd_t* dap_chain_datum_voting_max_votes_count_tsd_create(uint64_t a
 dap_chain_tx_tsd_t *dap_chain_datum_voting_delegated_key_required_tsd_create(bool a_delegated_key_required);
 dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_changing_allowed_tsd_create(bool a_vote_changing_allowed);
 dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_tx_cond_tsd_create(dap_chain_hash_fast_t a_tx_hash, int a_out_idx);
+dap_chain_tx_tsd_t *dap_chain_datum_voting_token_tsd_create(const char *a_token_ticker);
 
 dap_chain_tx_voting_t *dap_chain_datum_tx_item_voting_create(void);
 json_object *dap_chain_datum_tx_item_voting_tsd_to_json(dap_chain_datum_tx_t* a_tx);
@@ -96,4 +99,4 @@ json_object *dap_chain_datum_tx_item_vote_to_json(dap_chain_tx_vote_t *a_vote, d
 
 #ifdef __cplusplus
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index 88546b2272..f7c088e54b 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -837,7 +837,7 @@ static dap_list_t *s_get_validators_list(dap_chain_esbocs_t *a_esbocs, dap_hash_
     dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_esbocs);
     dap_list_t *l_ret = NULL;
     dap_list_t *l_validators = NULL;
-    if (!l_esbocs_pvt->poa_mode) {
+    if (l_esbocs_pvt->poa_mode) {   // UNDO it after debug
         if (a_excluded_list_size) {
             l_validators =  dap_chain_net_srv_stake_get_validators(a_esbocs->chain->net_id, false, NULL);
             uint16_t l_excluded_num = *a_excluded_list;
@@ -2774,6 +2774,9 @@ static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_b
 
 static uint64_t s_get_precached_key_hash(dap_list_t **a_precached_keys_list, dap_sign_t *a_source_sign, dap_hash_fast_t *a_result)
 {
+    if (DAP_SIGN_GET_PKEY_HASHING_FLAG(a_source_sign->header.hash_type))
+        return !dap_sign_get_pkey_hash(a_source_sign, a_result);
+
     bool l_found = false;
     struct precached_key *l_key = NULL;
     dap_list_t *l_cur;
diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c
index 03fcb33ba6..deaac956e7 100644
--- a/modules/net/dap_chain_ledger.c
+++ b/modules/net/dap_chain_ledger.c
@@ -5678,10 +5678,13 @@ dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t *
         // Get 'out_cond' item from transaction
         byte_t *l_item; size_t l_size; int i, l_out_idx = 0;
         TX_ITEM_ITER_TX_TYPE(l_item, TX_ITEM_TYPE_OUT_ALL, l_size, i, it->tx) {
-            if (*l_item == TX_ITEM_TYPE_OUT_COND &&
-                    ((dap_chain_tx_out_cond_t *)l_item)->header.subtype == a_subtype) {
-                ret = (dap_chain_tx_out_cond_t *)l_item;
-                break;
+            if (*l_item == TX_ITEM_TYPE_OUT_COND) {
+                dap_chain_tx_out_cond_subtype_t l_subtype = ((dap_chain_tx_out_cond_t *)l_item)->header.subtype;
+                if (l_subtype == a_subtype ||
+                        (a_subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL && l_subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)) {
+                    ret = (dap_chain_tx_out_cond_t *)l_item;
+                    break;
+                }
             }
             l_out_idx++;
         }
@@ -5689,7 +5692,8 @@ dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t *
         if (!ret || !dap_hash_fast_is_blank(&it->cache_data.tx_hash_spent_fast[l_out_idx]))
             continue;
         dap_hash_fast_t l_owner_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, it->tx, a_subtype);
-        dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_ledger, &l_owner_tx_hash);
+        dap_chain_datum_tx_t *l_tx = dap_hash_fast_is_blank(&l_owner_tx_hash) ? it->tx
+                                                                              : dap_ledger_tx_find_by_hash(a_ledger, &l_owner_tx_hash);
         if (!l_tx) {
             log_it(L_ERROR, "Can't find owner for tx %s", dap_hash_fast_to_str_static(&it->tx_hash_fast));
             continue;
@@ -5738,12 +5742,13 @@ bool dap_ledger_check_condition_owner(dap_ledger_t *a_ledger, dap_hash_fast_t *a
         log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(a_tx_hash));
         return false;
     }
-    dap_hash_fast_t l_first_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, l_check_tx, a_cond_subtype);
-    if (dap_hash_fast_is_blank(&l_first_tx_hash)) {
+    if (!dap_chain_datum_tx_out_cond_get(l_check_tx, a_cond_subtype, NULL)) {
         log_it(L_ERROR, "Can't find owner for tx %s", dap_hash_fast_to_str_static(a_tx_hash));
         return false;
     }
-    dap_chain_datum_tx_t *l_first_tx = dap_ledger_tx_find_by_hash(a_ledger, &l_first_tx_hash);
+    dap_hash_fast_t l_first_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, l_check_tx, a_cond_subtype);
+    dap_chain_datum_tx_t *l_first_tx = dap_hash_fast_is_blank(&l_first_tx_hash) ? l_check_tx
+                                                                                : dap_ledger_tx_find_by_hash(a_ledger, &l_first_tx_hash);
     if (!l_first_tx) {
         log_it(L_ERROR, "Can't find owner tx %s", dap_hash_fast_to_str_static(&l_first_tx_hash));
         return false;
diff --git a/modules/net/dap_chain_net_tx.c b/modules/net/dap_chain_net_tx.c
index addcb27c56..937c0464f5 100644
--- a/modules/net/dap_chain_net_tx.c
+++ b/modules/net/dap_chain_net_tx.c
@@ -1633,7 +1633,7 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json
             json_object_object_add(json_obj_item,"type", json_object_new_string("voting"));
             json_object_object_add(json_obj_item,"voting_question", json_object_new_string(l_voting_params->voting_question));
             json_object_object_add(json_obj_item,"answer_options", json_object_new_string(""));
-            
+            json_object_object_add(json_obj_item, "token", json_object_new_string(l_voting_params->token_ticker));
             dap_list_t *l_temp = l_voting_params->answers_list;
             uint8_t l_index = 0;
             while (l_temp) {
@@ -1643,7 +1643,7 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json
             }
             if (l_voting_params->voting_expire) {
                 dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_voting_params->voting_expire);
-                json_object_object_add(json_obj_item,"Voting expire", json_object_new_string(l_tmp_buf));                
+                json_object_object_add(json_obj_item, "Voting expire", json_object_new_string(l_tmp_buf));
             }
             if (l_voting_params->votes_max_count) {
                 json_object_object_add(json_obj_item, "Votes max count", json_object_new_uint64(l_voting_params->votes_max_count));
diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index 3734ed953c..6f55e66960 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -50,6 +50,7 @@ typedef struct dap_chain_net_voting_params_offsets{
     uint64_t votes_max_count;
     bool delegate_key_required;
     bool vote_changing_allowed;
+    char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
 } dap_chain_net_voting_params_offsets_t;
 
 typedef struct dap_chain_net_vote_option {
@@ -115,7 +116,8 @@ int dap_chain_net_srv_voting_init()
     pthread_rwlock_init(&s_votings_rwlock, NULL);
     dap_chain_ledger_voting_verificator_add(s_datum_tx_voting_verification_callback, s_datum_tx_voting_verification_delete_callback);
     dap_cli_server_cmd_add("voting", s_cli_voting, "Voting commands.", ""
-                            "voting create -net <net_name> -question <\"Question_string\"> -options <\"Option0\", \"Option1\" ... \"OptionN\"> [-expire <voting_expire_time_in_RCF822>] [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name>\n"
+                            "voting create -net <net_name> -question <\"Question_string\"> -options <\"Option0\", \"Option1\" ... \"OptionN\"> [-expire <voting_expire_time_in_RCF822>]"
+                                           " [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name> -token <ticker>\n"
                             "voting vote -net <net_name> -hash <voting_hash> -option_idx <option_index> [-cert <delegate_cert_name>] -fee <value_datoshi> -w <fee_wallet_name>\n"
                             "voting list -net <net_name>\n"
                             "voting dump -net <net_name> -hash <voting_hash>\n");
@@ -218,14 +220,29 @@ static int s_voting_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t
 
     dap_list_t* l_tsd_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_TSD, NULL);
     for (dap_list_t *it = l_tsd_list; it; it = it->next) {
-        dap_tsd_t* l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t*)it->data)->tsd;
+        dap_chain_tx_tsd_t *l_tx_tsd = it->data;
+        dap_tsd_t *l_tsd = (dap_tsd_t *)l_tx_tsd->tsd;
+        if (l_tx_tsd->header.size < sizeof(dap_tsd_t) ||
+                l_tx_tsd->header.size != dap_tsd_size(l_tsd)) {
+            log_it(L_WARNING, "Incorrect size %" DAP_UINT64_FORMAT_U " of TX_TSD item for voting %s",
+                   l_tx_tsd->header.size, dap_hash_fast_to_str_static(a_tx_hash));
+            return -DAP_LEDGER_CHECK_INVALID_SIZE;
+        }
         dap_chain_net_vote_option_t *l_vote_option = NULL;
         switch(l_tsd->type){
         case VOTING_TSD_TYPE_QUESTION:
+            if (!l_tsd->size) {
+                log_it(L_WARNING, "Incorrect size %u of TSD section QUESTION for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
+                return -DAP_LEDGER_CHECK_INVALID_SIZE;
+            }
             l_item->voting_params.voting_question_offset = (size_t)(l_tsd->data - (byte_t*)l_item->voting_params.voting_tx);
             l_item->voting_params.voting_question_length = l_tsd->size;
             break;
         case VOTING_TSD_TYPE_ANSWER:
+            if (!l_tsd->size) {
+                log_it(L_WARNING, "Incorrect size %u of TSD section ANSWER for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
+                return -DAP_LEDGER_CHECK_INVALID_SIZE;
+            }
             l_vote_option = DAP_NEW_Z(dap_chain_net_vote_option_t);
             l_vote_option->vote_option_offset = (size_t)(l_tsd->data - (byte_t*)l_item->voting_params.voting_tx);
             l_vote_option->vote_option_length = l_tsd->size;
@@ -233,41 +250,50 @@ static int s_voting_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t
             break;
         case VOTING_TSD_TYPE_EXPIRE:
             if (l_tsd->size != sizeof(dap_time_t)) {
-                log_it(L_WARNING, "Incorrect size %u of TSD section EXPIRE vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
+                log_it(L_WARNING, "Incorrect size %u of TSD section EXPIRE for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
                 return -DAP_LEDGER_CHECK_INVALID_SIZE;
             }
             l_item->voting_params.voting_expire = *(dap_time_t *)l_tsd->data;
             break;
         case VOTING_TSD_TYPE_MAX_VOTES_COUNT:
             if (l_tsd->size != sizeof(uint64_t)) {
-                log_it(L_WARNING, "Incorrect size %u of TSD section MAX_VOTES_COUNT vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
+                log_it(L_WARNING, "Incorrect size %u of TSD section MAX_VOTES_COUNT for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
                 return -DAP_LEDGER_CHECK_INVALID_SIZE;
             }
             l_item->voting_params.votes_max_count = *(uint64_t *)l_tsd->data;
             break;
         case VOTING_TSD_TYPE_DELEGATED_KEY_REQUIRED:
             if (l_tsd->size != sizeof(byte_t)) {
-                log_it(L_WARNING, "Incorrect size %u of TSD section DELEGATED_KEY_REQUIRED vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
+                log_it(L_WARNING, "Incorrect size %u of TSD section DELEGATED_KEY_REQUIRED for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
                 return -DAP_LEDGER_CHECK_INVALID_SIZE;
             }
             l_item->voting_params.delegate_key_required = *(byte_t *)l_tsd->data;
             break;
         case VOTING_TSD_TYPE_VOTE_CHANGING_ALLOWED:
             if (l_tsd->size != sizeof(byte_t)) {
-                log_it(L_WARNING, "Incorrect size %u of TSD section VOTE_CHANGING_ALLOWED vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
+                log_it(L_WARNING, "Incorrect size %u of TSD section VOTE_CHANGING_ALLOWED for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
                 return -DAP_LEDGER_CHECK_INVALID_SIZE;
             }
             l_item->voting_params.vote_changing_allowed = *(byte_t *)l_tsd->data;
             break;
+        case VOTING_TSD_TYPE_TOKEN:
+            if (!l_tsd->size || l_tsd->size >= DAP_CHAIN_TICKER_SIZE_MAX) {
+                log_it(L_WARNING, "Incorrect size %u of TSD section TOKEN for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash));
+                return -DAP_LEDGER_CHECK_INVALID_SIZE;
+            }
+            strcpy(l_item->voting_params.token_ticker, (char *)l_tsd->data);
         default:
             break;
         }
     }
     dap_list_free(l_tsd_list);
 
+    if (!*l_item->voting_params.token_ticker)
+        strcpy(l_item->voting_params.token_ticker, a_ledger->net->pub.native_ticker);
     pthread_rwlock_wrlock(&s_votings_rwlock);
     HASH_ADD(hh, s_votings, voting_hash, sizeof(dap_hash_fast_t), l_item);
     pthread_rwlock_unlock(&s_votings_rwlock);
+    log_it(L_NOTICE, "Voting with hash %s succefully added to ledger", dap_hash_fast_to_str_static(a_tx_hash));
     return DAP_LEDGER_CHECK_OK;
 }
 
@@ -340,25 +366,26 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
         int l_out_idx = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->out_idx;
         if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND)
             return -14;
-        if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx))
-            return -15;
         dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash);
-        dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t*)dap_chain_datum_tx_item_get(l_tx_prev_temp, &l_out_idx, NULL, TX_ITEM_TYPE_OUT_COND, NULL);
-        if (!l_prev_out || l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
+        dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_out_idx);
+        if (!l_prev_out || l_prev_out->header.item_type != TX_ITEM_TYPE_OUT_COND || l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
             return -16;
         if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, (dap_sign_t *)l_tx_sig->sig))
             return -17;
+        if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx))
+            return -15;
         if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) {
             log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
             return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW;
         }
-
-        dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY);
-        l_item->tx_hash = l_hash;
-        l_item->out_idx = l_out_idx;
-        pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock);
-        HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item);
-        pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock);
+        if (a_apply) {
+            dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY);
+            l_item->tx_hash = l_hash;
+            l_item->out_idx = l_out_idx;
+            pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock);
+            HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item);
+            pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock);
+        }
     }
     dap_list_free(l_tsd_list);
     // check inputs
@@ -369,17 +396,34 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
     }
     for (dap_list_t *it = l_ins_list; it; it = it->next) {
         dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)it->data;
-        if (!s_datum_tx_voting_coin_check_spent(a_ledger->net, l_vote_tx_item->voting_hash,
+        dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash);
+        dap_chain_tx_out_ext_t *l_prev_out_union = (dap_chain_tx_out_ext_t *)dap_chain_datum_tx_out_get_by_out_idx(
+                                                    l_tx_prev_temp, l_tx_in->header.tx_out_prev_idx);
+        if (!l_prev_out_union)
+            return -18;
+        const char *l_ticker_in = NULL;
+        switch (l_prev_out_union->header.type) {
+        case TX_ITEM_TYPE_OUT:
+            l_ticker_in = dap_ledger_tx_get_token_ticker_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash);
+            break;
+        case TX_ITEM_TYPE_OUT_EXT:
+            l_ticker_in = l_prev_out_union->token;
+            break;
+        default:
+            log_it(L_WARNING, "Unexpected tx item %d in vote tx %s", l_prev_out_union->header.type, dap_hash_fast_to_str_static(a_tx_hash));
+            return -19;
+        }
+        if (dap_strcmp(l_ticker_in, l_voting->voting_params.token_ticker))
+            continue;
+        if (s_datum_tx_voting_coin_check_spent(a_ledger->net, l_vote_tx_item->voting_hash,
                                                 l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx, &pkey_hash)) {
-            dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash);
-            dap_chain_tx_out_t *l_prev_out_union = (dap_chain_tx_out_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_tx_in->header.tx_out_prev_idx);
-            if (!l_prev_out_union)
-                return -18;
-            if ((l_prev_out_union->header.type == TX_ITEM_TYPE_OUT || l_prev_out_union->header.type == TX_ITEM_TYPE_OUT_EXT) &&
-                    SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) {
-                log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
-                return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW;
-            }
+            log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx,
+                                        dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash));
+            return -20;
+        }
+        if (SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) {
+            log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
+            return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW;
         }
     }
     dap_list_free(l_ins_list);
@@ -436,14 +480,14 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
                 char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE];
                 dap_hash_fast_to_str(&((dap_chain_net_vote_t *)it->data)->vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE);
                 DAP_DELETE(it->data);
-                log_it(L_INFO, "Vote %s of voting %s has been changed", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash));
+                log_it(L_NOTICE, "Vote %s of voting %s has been changed", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash));
                 return DAP_LEDGER_CHECK_OK;
             }
         }
         l_voting->votes = dap_list_append(l_voting->votes, l_vote_item);
         char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE];
         dap_hash_fast_to_str(a_tx_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE);
-        log_it(L_INFO, "Vote %s of voting %s has been accepted", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash));
+        log_it(L_NOTICE, "Vote %s of voting %s has been accepted", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash));
     }
     return DAP_LEDGER_CHECK_OK;
 }
@@ -503,7 +547,7 @@ static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledge
             return false;
         }
 
-        dap_chain_net_votings_t * l_voting = NULL;
+        dap_chain_net_votings_t *l_voting = NULL;
         pthread_rwlock_wrlock(&s_votings_rwlock);
         HASH_FIND(hh, s_votings, &l_vote_tx_item->voting_hash, sizeof(dap_hash_fast_t), l_voting);
         pthread_rwlock_unlock(&s_votings_rwlock);
@@ -615,6 +659,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
         const char* l_max_votes_count_str = NULL;
         const char* l_fee_str = NULL;
         const char* l_wallet_str = NULL;
+        const char *l_token_str = NULL;
 
         dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str);
         if (!l_question_str){
@@ -647,8 +692,6 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
             return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS;
         }
 
-        dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str);
-        dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str);
         dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str);
         if (!l_fee_str){
             dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID, "Voting requires paramete -fee to be valid.");
@@ -662,6 +705,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
             return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID;
         }
 
+        dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str);
         dap_time_t l_time_expire = 0;
         if (l_voting_expire_str)
             l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str);
@@ -670,6 +714,8 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
                                     "Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"");
             return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT;
         }
+
+        dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str);
         uint64_t l_max_count = 0;
         if (l_max_votes_count_str)
             l_max_count = strtoul(l_max_votes_count_str, NULL, 10);
@@ -683,8 +729,26 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
             return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
         }
 
+
+        dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str);
+        if (l_token_str && !dap_ledger_token_ticker_check(l_net->pub.ledger, l_token_str)) {
+            dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN, "Token %s does not exist", l_token_str);
+            return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN;
+        }
+
         char *l_hash_ret = NULL;
-        int res = dap_chain_net_vote_create(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net, l_hash_out_type, &l_hash_ret);
+        int res = dap_chain_net_vote_create(l_question_str,
+                                            l_options_list,
+                                            l_time_expire,
+                                            l_max_count,
+                                            l_value_fee,
+                                            l_is_delegated_key,
+                                            l_is_vote_changing_allowed,
+                                            l_wallet_fee,
+                                            l_net,
+                                            l_token_str,
+                                            l_hash_out_type,
+                                            &l_hash_ret);
         dap_list_free(l_options_list);
         dap_chain_wallet_close(l_wallet_fee);
 
@@ -812,8 +876,8 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
         }
 
         const char *c_wallets_path = dap_chain_wallet_get_path(g_config);
-        dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, c_wallets_path,NULL);
-        if (!l_wallet_fee) {
+        dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path,NULL);
+        if (!l_wallet) {
             dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST, "Wallet %s does not exist", l_wallet_str);
             return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST;
         }
@@ -822,9 +886,9 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
 
         char *l_hash_tx;
 
-        int res = dap_chain_net_vote_voting(l_cert, l_value_fee, l_wallet_fee, l_voting_hash, l_option_idx_count,
+        int res = dap_chain_net_vote_voting(l_cert, l_value_fee, l_wallet, l_voting_hash, l_option_idx_count,
                                             l_net, l_hash_out_type, &l_hash_tx);
-        dap_chain_wallet_close(l_wallet_fee);
+        dap_chain_wallet_close(l_wallet);
 
         switch (res) {
             case DAP_CHAIN_NET_VOTE_VOTING_OK: {
@@ -918,6 +982,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
             char* l_voting_question = (char*)l_voting->voting_params.voting_tx + l_voting->voting_params.voting_question_offset;
             json_object_object_add( json_obj_vote, "question", 
                                     json_object_new_string_len(l_voting_question, l_voting->voting_params.voting_question_length) );
+            json_object_object_add(json_obj_vote, "token", json_object_new_string(l_voting->voting_params.token_ticker));
             json_object_array_add(json_arr_voting_out, json_obj_vote);
         }
         pthread_rwlock_unlock(&s_votings_rwlock);
@@ -968,6 +1033,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
         json_object_object_add(json_vote_out, "question", 
                                json_object_new_string_len((char*)l_voting->voting_params.voting_tx + l_voting->voting_params.voting_question_offset,
                                l_voting->voting_params.voting_question_length));
+        json_object_object_add(json_vote_out, "token", json_object_new_string(l_voting->voting_params.token_ticker));
         if (l_voting->voting_params.voting_expire) {
             char l_tmp_buf[DAP_TIME_STR_SIZE];
             dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_voting->voting_params.voting_expire);
@@ -1028,21 +1094,26 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
 {
     int l_coin_is_spent = 0;
 
-
-    dap_ledger_t *l_ledger = a_net->pub.ledger;
-    if(!l_ledger){
-        log_it(L_ERROR, "Can't find ledger");
+    dap_chain_net_votings_t *l_voting = NULL;
+    pthread_rwlock_wrlock(&s_votings_rwlock);
+    HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting);
+    pthread_rwlock_unlock(&s_votings_rwlock);
+    if (!l_voting) {
+        log_it(L_ERROR, "Can't find voting %s", dap_hash_fast_to_str_static(&a_voting_hash));
         return -1;
     }
+    const char *l_token_ticker = l_voting->voting_params.token_ticker;
 
+    dap_ledger_t *l_ledger = a_net->pub.ledger;
     dap_chain_datum_tx_t *l_voting_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_voting_hash);
-    const char *l_native_ticker = a_net->pub.native_ticker;
-
-    dap_list_t *l_tx_list = NULL; // "stack" for saving txs on up level
+    if (!l_voting_tx) {
+        log_it(L_ERROR, "Can't find voting tx %s", dap_hash_fast_to_str_static(&a_voting_hash));
+        return -2;
+    }
     dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_tx_prev_hash);
-    if (!l_tx){
-        log_it(L_ERROR, "Can't find tx");
-        return -1;
+    if (!l_tx) {
+        log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(&a_tx_prev_hash));
+        return -3;
     }
 
     if (l_tx->header.ts_created < l_voting_tx->header.ts_created){
@@ -1055,25 +1126,18 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
 
     dap_chain_tx_vote_t *l_vote = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL);
     if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)) {
-        dap_chain_net_votings_t *l_voting = NULL;
-        pthread_rwlock_wrlock(&s_votings_rwlock);
-        HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting);
-        pthread_rwlock_unlock(&s_votings_rwlock);
-        if (l_voting) {
-            for (dap_list_t *it = l_voting->votes; it; it = it->next) {
-                dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data;
-                if (dap_hash_fast_compare(&l_vote->vote_hash, &a_tx_prev_hash)) {
-                    if (l_voting->voting_params.vote_changing_allowed &&
-                            !dap_hash_fast_is_blank(a_pkey_hash) &&
-                            dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash))
-                        break;  // it's vote changing, allow it
-                    return 1;
-                }
+        for (dap_list_t *it = l_voting->votes; it; it = it->next) {
+            dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data;
+            if (dap_hash_fast_compare(&l_vote->vote_hash, &a_tx_prev_hash)) {
+                if (l_voting->voting_params.vote_changing_allowed &&
+                        !dap_hash_fast_is_blank(a_pkey_hash) &&
+                        dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash))
+                    break;  // it's vote changing, allow it
+                return 1;
             }
         }
     }
 
-
     dap_list_t *l_ins_list_temp = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
     dap_list_t *l_cond_ins_list = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_COND, NULL);
     if (!l_ins_list_temp && !l_cond_ins_list){
@@ -1081,12 +1145,9 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
         return -1;
     }
 
-    dap_list_t *l_ins_list = NULL;
-    l_ins_list = dap_list_concat(l_ins_list, l_ins_list_temp);
-    l_ins_list = dap_list_concat(l_ins_list, l_cond_ins_list);
-
-    l_tx_list = dap_list_append(l_tx_list, l_ins_list);
-    dap_list_t* l_tx_temp = dap_list_last(l_tx_list);
+    dap_list_t *l_ins_list = dap_list_concat(l_ins_list_temp, l_cond_ins_list);
+    dap_list_t *l_tx_list = dap_list_append(NULL, l_ins_list); // "stack" for saving txs on up level
+    dap_list_t *l_tx_temp = dap_list_last(l_tx_list);
 
     while(l_tx_temp && !l_coin_is_spent){
         if (l_tx_temp->data == NULL){
@@ -1118,22 +1179,24 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
             l_tx_token = l_temp_out->token;
         }break;
         case TX_ITEM_TYPE_OUT_COND:{
-            dap_chain_tx_out_cond_t *l_temp_out = (dap_chain_tx_out_cond_t*)l_prev_out_union;
-            if (l_temp_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK ||
-                s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, l_temp_in->header.tx_prev_hash, l_temp_in->header.tx_out_prev_idx) == 0)
+            dap_chain_tx_out_cond_t *l_temp_out = (dap_chain_tx_out_cond_t *)l_prev_out_union;
+            if (l_temp_out->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) {
+                l_tx_token = a_net->pub.native_ticker;
                 break;
+            }
+            if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, l_temp_in->header.tx_prev_hash,
+                                                      l_temp_in->header.tx_out_prev_idx) != 0) {
+                l_coin_is_spent = 1;
+                continue;
+            }
+            l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_temp_in->header.tx_prev_hash);
         }
         default:
-            l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in);
-            if (l_tx_temp->data == NULL){
-                l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp);
-                l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL;
-            }
-            continue;
+            break;
         }
 
         if (l_tx_prev_temp->header.ts_created < l_voting_tx->header.ts_created ||
-            dap_strcmp(l_tx_token, l_native_ticker)){
+            dap_strcmp(l_tx_token, l_token_ticker)){
             l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in);
             if (l_tx_temp->data == NULL){
                 l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp);
@@ -1142,13 +1205,8 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
             continue;
         }
 
-
         dap_chain_tx_vote_t *l_vote =(dap_chain_tx_vote_t *) dap_chain_datum_tx_item_get(l_tx_prev_temp, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL);
         if(l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)){
-            dap_chain_net_votings_t *l_voting = NULL;
-            pthread_rwlock_wrlock(&s_votings_rwlock);
-            HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting);
-            pthread_rwlock_unlock(&s_votings_rwlock);
             dap_list_t *l_temp = NULL;
             while (l_temp){
                 dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)l_temp->data;
@@ -1160,12 +1218,10 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
             }
         }
 
-
         l_ins_list = dap_chain_datum_tx_items_get(l_tx_prev_temp, TX_ITEM_TYPE_IN, NULL);
         l_tx_list = dap_list_append(l_tx_list, l_ins_list);
         l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in);
         l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL;
-
     }
 
     if(l_tx_list){
@@ -1209,7 +1265,8 @@ static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_has
 int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
-                              dap_chain_net_t *a_net, const char *a_hash_out_type, char **a_hash_output) {
+                              dap_chain_net_t *a_net, const char *a_token_ticker,
+                              const char *a_hash_out_type, char **a_hash_output) {
 
     if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
         return DAP_CHAIN_NET_VOTE_CREATE_LENGTH_QUESTION_OVERSIZE_MAX;
@@ -1243,8 +1300,7 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap
     dap_ledger_t* l_ledger = a_net->pub.ledger;
     dap_list_t *l_list_used_out = NULL;
     if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, l_addr_from, &l_list_used_out, l_total_fee, &l_value_transfer) == -101)
-        l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker,
-                                                                       l_addr_from, l_total_fee, &l_value_transfer);
+        l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, l_addr_from, l_total_fee, &l_value_transfer);
     if (!l_list_used_out) {
         return DAP_CHAIN_NET_VOTE_CREATE_NOT_ENOUGH_FUNDS_TO_TRANSFER;
     }
@@ -1327,6 +1383,16 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap
         DAP_DEL_Z(l_vote_changing_item);
     }
 
+    if (a_token_ticker) {
+        dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker);
+        if (!l_voting_token_item) {
+            dap_chain_datum_tx_delete(l_tx);
+            return DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_TOKEN;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item);
+        DAP_DEL_Z(l_voting_token_item);
+    }
+
     // add 'in' items
     uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
     assert(EQUAL_256(l_value_to_items, l_value_transfer));
@@ -1334,7 +1400,7 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap
     uint256_t l_value_pack = {};
     // Network fee
     if (l_net_fee_used) {
-        if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) == 1)
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, l_native_ticker) == 1)
             SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
         else {
             dap_chain_datum_tx_delete(l_tx);
@@ -1354,7 +1420,7 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap
     uint256_t l_value_back;
     SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
     if(!IS_ZERO_256(l_value_back)) {
-        if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) {
+        if(dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_native_ticker) != 1) {
             dap_chain_datum_tx_delete(l_tx);
             return DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
         }
@@ -1433,15 +1499,18 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
     if (!l_addr_from)
         return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID;
 
-    const char *l_native_ticker = a_net->pub.native_ticker;
-    uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer;
+    const char *l_token_ticker = l_voting->voting_params.token_ticker;
+    uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer;
     dap_chain_addr_t l_addr_fee = {};
     bool l_net_fee_used = dap_chain_net_tx_get_fee(a_net->pub.id, &l_net_fee, &l_addr_fee);
-    SUM_256_256(l_net_fee, a_fee, &l_total_fee);
+    if (l_net_fee_used)
+        SUM_256_256(l_net_fee, a_fee, &l_total_fee);
 
-    dap_ledger_t* l_ledger = dap_ledger_by_net_name(a_net->pub.name);
-    dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs(l_ledger, l_native_ticker, l_addr_from, &l_value_transfer);
-    if (!l_list_used_out || compare256(l_value_transfer, l_total_fee) <= 0) {
+    bool l_native_tx = !dap_strcmp(l_token_ticker, a_net->pub.native_ticker);
+    dap_ledger_t *l_ledger = a_net->pub.ledger;
+    dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs(l_ledger, l_token_ticker, l_addr_from, &l_value_transfer);
+    if (!l_list_used_out || (l_native_tx && compare256(l_value_transfer, l_total_fee) < 0)) {
+        dap_list_free_full(l_list_used_out, NULL);
         return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER;
     }
 
@@ -1459,15 +1528,33 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
             return DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW;
     }
 
-    if (IS_ZERO_256(l_value_transfer_new) || compare256(l_value_transfer_new, l_total_fee) <= 0){
+    if (IS_ZERO_256(l_value_transfer_new) || (l_native_tx && compare256(l_value_transfer_new, l_total_fee) <= 0))
         return DAP_CHAIN_NET_VOTE_VOTING_UNSPENT_UTX0_FOR_PARTICIPATION_THIS_VOTING;
-    }
 
     l_value_transfer = l_value_transfer_new;
 
     // create empty transaction
     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
+    uint256_t l_value_back = l_value_transfer, l_fee_back = {};
+    if (!l_native_tx) {
+        dap_list_t *l_list_fee_outs = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_net->pub.native_ticker, l_addr_from, l_total_fee, &l_fee_transfer);
+        if (!l_list_fee_outs) {
+            dap_chain_datum_tx_delete(l_tx);
+            return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER;
+        }
+        uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_outs);
+        assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+        dap_list_free_full(l_list_fee_outs, NULL);
+        SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_back);
+    } else
+        SUBTRACT_256_256(l_value_transfer, l_total_fee, &l_value_back);
+
+    // add 'in' items
+    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+    assert(EQUAL_256(l_value_to_items, l_value_transfer));
+    dap_list_free_full(l_list_used_out, NULL);
+
     // Add vote item
     if (a_option_idx > dap_list_length(l_voting->voting_params.option_offsets_list)){
         dap_chain_datum_tx_delete(l_tx);
@@ -1481,14 +1568,12 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
     dap_chain_datum_tx_add_item(&l_tx, l_vote_item);
     DAP_DEL_Z(l_vote_item);
 
-    // add stake out conds items
-    dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, a_net->pub.native_ticker, l_addr_from);
+    // add out conds items
+    dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from);
     for (dap_list_t *it = l_outs; it; it = it->next) {
         dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data;
-        if (dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_out_item->tx_hash_fast, l_out_item->num_idx_out, NULL) ||
-            s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out ) != 0){
+        if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out) != 0)
             continue;
-        }
         dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out);
         if(!l_item){
             dap_chain_datum_tx_delete(l_tx);
@@ -1501,37 +1586,26 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
     }
     dap_list_free_full(l_outs, NULL);
 
-    // add 'in' items
-    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-    assert(EQUAL_256(l_value_to_items, l_value_transfer));
-    dap_list_free_full(l_list_used_out, NULL);
-    uint256_t l_value_pack = {};
     // Network fee
-    if (l_net_fee_used) {
-        if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) == 1)
-            SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-        else {
-            dap_chain_datum_tx_delete(l_tx);
-            return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT;
-        }
+    if (l_net_fee_used && dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, a_net->pub.native_ticker) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT;
     }
+
     // Validator's fee
-    if (!IS_ZERO_256(a_fee)) {
-        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1)
-            SUM_256_256(l_value_pack, a_fee, &l_value_pack);
-        else {
-            dap_chain_datum_tx_delete(l_tx);
-            return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT;
-        }
+    if (!IS_ZERO_256(a_fee) && dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT;
     }
+
     // coin back
-    uint256_t l_value_back;
-    SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-    if(!IS_ZERO_256(l_value_back)) {
-        if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) {
-            dap_chain_datum_tx_delete(l_tx);
-            return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
-        }
+    if (!IS_ZERO_256(l_value_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_token_ticker) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
+    }
+    if (!IS_ZERO_256(l_fee_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_fee_back, a_net->pub.native_ticker) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
     }
 
     // add 'sign' items with wallet sign
diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h
index 4bd1f71694..6252b37771 100644
--- a/modules/service/voting/include/dap_chain_net_srv_voting.h
+++ b/modules/service/voting/include/dap_chain_net_srv_voting.h
@@ -94,13 +94,14 @@ enum DAP_CHAIN_NET_VOTE_CREATE_ERROR {
     DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID,
     DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST,
     DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT,
-
+    DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN,
+    DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_TOKEN,
     DAP_CHAIN_NET_VOTE_CREATE_UNKNOWN_ERR
 };
 int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
                              uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                              bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
-                             dap_chain_net_t *a_net, const char *a_hash_out_type, char **a_hash_output);
+                             dap_chain_net_t *a_net, const char *a_token_ticker, const char *a_hash_out_type, char **a_hash_output);
 
 enum DAP_CHAIN_NET_VOTE_VOTING_ERROR{
     DAP_CHAIN_NET_VOTE_VOTING_OK,
@@ -131,7 +132,6 @@ enum DAP_CHAIN_NET_VOTE_VOTING_ERROR{
     DAP_CHAIN_NET_VOTE_VOTING_WALLET_PARAM_NOT_VALID,
     DAP_CHAIN_NET_VOTE_VOTING_OPTION_IDX_PARAM_NOT_VALID,
     DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST,
-    
 
     DAP_CHAIN_NET_VOTE_VOTING_UNKNOWN_ERR,
     DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW
-- 
GitLab


From 680aaeeb264c584be8f389934fb936900398eb3d Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Tue, 4 Mar 2025 15:52:24 +0700
Subject: [PATCH 03/53] [*] Voting bugfixes

---
 .../service/voting/dap_chain_net_srv_voting.c | 328 ++++++++----------
 .../voting/include/dap_chain_net_srv_voting.h |   1 -
 2 files changed, 152 insertions(+), 177 deletions(-)

diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index 6f55e66960..a447a584e3 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -61,7 +61,7 @@ typedef struct dap_chain_net_vote_option {
 typedef struct dap_chain_net_voting_cond_outs {
     dap_chain_hash_fast_t tx_hash;
     int out_idx;
-
+    dap_hash_fast_t pkey_hash;
     UT_hash_handle hh;
 } dap_chain_net_voting_cond_outs_t;
 
@@ -87,9 +87,10 @@ typedef struct dap_chain_net_votings {
 static dap_chain_net_votings_t *s_votings;
 static pthread_rwlock_t s_votings_rwlock;
 
-static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx);
+static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx, dap_hash_fast_t *a_vote_hash);
 /// -1 error, 0 - unspent, 1 - spent
-static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash);
+static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash,
+                                              dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash);
 static int s_datum_tx_voting_verification_callback(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in, dap_hash_fast_t *a_tx_hash, bool a_apply);
 static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in);
 static int s_cli_voting(int argc, char **argv, void **a_str_reply);
@@ -174,7 +175,6 @@ uint64_t* dap_chain_net_voting_get_result(dap_ledger_t* a_ledger, dap_chain_hash
     return l_voting_results;
 }
 
-
 static int s_voting_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in, dap_hash_fast_t *a_tx_hash, bool a_apply)
 {
     if (!a_apply) {
@@ -315,79 +315,57 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
         return -5;
     }
 
-    dap_hash_fast_t pkey_hash = {};
-    // Get sign item from transaction
-    dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(a_tx_in, NULL, NULL, TX_ITEM_TYPE_SIG, NULL);
-    dap_sign_get_pkey_hash((dap_sign_t *)l_tx_sig->sig, &pkey_hash);
+    // Get last sign item from transaction
+    dap_hash_fast_t l_pkey_hash = {};
+    dap_sign_t *l_pkey_sign = NULL;
+    uint8_t *l_tx_item = NULL; size_t l_size; int i, l_sign_num = 0;
+    TX_ITEM_ITER_TX_TYPE(l_tx_item, TX_ITEM_TYPE_SIG, l_size, i, a_tx_in) {
+        l_pkey_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_item);
+        l_sign_num++;
+    }
+    dap_sign_get_pkey_hash(l_pkey_sign, &l_pkey_hash);
+    if (--l_sign_num && dap_chain_datum_tx_verify_sign(a_tx_in, l_sign_num)) {
+        log_it(L_WARNING, "Last vote tx %s sign verification failed", dap_chain_hash_fast_to_str_static(a_tx_hash));
+        return -22;
+    }
 
-    if (!a_apply) {
-        if (l_vote_tx_item->answer_idx > dap_list_length(l_voting->voting_params.option_offsets_list)) {
-            log_it(L_WARNING, "Invalid vote option index %" DAP_UINT64_FORMAT_U " for vote tx %s",
-                                                    l_vote_tx_item->answer_idx, dap_chain_hash_fast_to_str_static(a_tx_hash));
-            return -6;
-        }
-        if (l_voting->voting_params.votes_max_count && dap_list_length(l_voting->votes) >= l_voting->voting_params.votes_max_count){
-            log_it(L_WARNING, "The required number of votes has been collected for voting %s", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash));
-            return -7;
-        }
-        if (l_voting->voting_params.voting_expire && l_voting->voting_params.voting_expire <= a_tx_in->header.ts_created) {
-            log_it(L_WARNING, "The voting %s has been expired", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash));
-            return -8;
-        }
+    if (l_vote_tx_item->answer_idx > dap_list_length(l_voting->voting_params.option_offsets_list)) {
+        log_it(L_WARNING, "Invalid vote option index %" DAP_UINT64_FORMAT_U " for vote tx %s",
+                                                l_vote_tx_item->answer_idx, dap_chain_hash_fast_to_str_static(a_tx_hash));
+        return -6;
+    }
+    if (l_voting->voting_params.votes_max_count && dap_list_length(l_voting->votes) >= l_voting->voting_params.votes_max_count){
+        log_it(L_WARNING, "The required number of votes has been collected for voting %s", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash));
+        return -7;
+    }
+    if (l_voting->voting_params.voting_expire && l_voting->voting_params.voting_expire <= a_tx_in->header.ts_created) {
+        log_it(L_WARNING, "The voting %s has been expired", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash));
+        return -8;
+    }
 
-        if (l_voting->voting_params.delegate_key_required &&
-                !dap_chain_net_srv_stake_check_pkey_hash(a_ledger->net->pub.id, &pkey_hash)){
-            log_it(L_WARNING, "Voting %s required a delegated key", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash));
-            return -10;
-        }
+    if (l_voting->voting_params.delegate_key_required &&
+            !dap_chain_net_srv_stake_check_pkey_hash(a_ledger->net->pub.id, &l_pkey_hash)){
+        log_it(L_WARNING, "Voting %s required a delegated key", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash));
+        return -10;
+    }
 
-        for (dap_list_t *it = l_voting->votes; it; it = it->next) {
-            if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &pkey_hash)) {
-                dap_hash_fast_t *l_vote_hash = &((dap_chain_net_vote_t *)it->data)->vote_hash;
-                if (!l_voting->voting_params.vote_changing_allowed) {
-                    char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE];
-                    dap_hash_fast_to_str(l_vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE);
-                    log_it(L_WARNING, "The voting %s don't allow change your vote %s",
-                           dap_hash_fast_to_str_static(&l_voting->voting_hash), l_vote_hash_str);
-                    return -11;
-                }
-                break;
+    dap_list_t *l_old_vote = NULL;
+    for (dap_list_t *it = l_voting->votes; it; it = it->next) {
+        if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &l_pkey_hash)) {
+            dap_hash_fast_t *l_vote_hash = &((dap_chain_net_vote_t *)it->data)->vote_hash;
+            if (!l_voting->voting_params.vote_changing_allowed) {
+                char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE];
+                dap_hash_fast_to_str(l_vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE);
+                log_it(L_WARNING, "The voting %s don't allow change your vote %s",
+                       dap_hash_fast_to_str_static(&l_voting->voting_hash), l_vote_hash_str);
+                return -11;
             }
+            l_old_vote = it;
+            break;
         }
     }
 
     uint256_t l_weight = {};
-
-    // check out conds
-    dap_list_t *l_tsd_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_TSD, NULL);
-    for (dap_list_t *it = l_tsd_list; it; it = it->next) {
-        dap_tsd_t *l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t*)it->data)->tsd;
-        dap_hash_fast_t l_hash = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->tx_hash;
-        int l_out_idx = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->out_idx;
-        if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND)
-            return -14;
-        dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash);
-        dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_out_idx);
-        if (!l_prev_out || l_prev_out->header.item_type != TX_ITEM_TYPE_OUT_COND || l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
-            return -16;
-        if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, (dap_sign_t *)l_tx_sig->sig))
-            return -17;
-        if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx))
-            return -15;
-        if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) {
-            log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
-            return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW;
-        }
-        if (a_apply) {
-            dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY);
-            l_item->tx_hash = l_hash;
-            l_item->out_idx = l_out_idx;
-            pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock);
-            HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item);
-            pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock);
-        }
-    }
-    dap_list_free(l_tsd_list);
     // check inputs
     dap_list_t *l_ins_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_IN, NULL);
     if (!l_ins_list) {
@@ -416,7 +394,7 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
         if (dap_strcmp(l_ticker_in, l_voting->voting_params.token_ticker))
             continue;
         if (s_datum_tx_voting_coin_check_spent(a_ledger->net, l_vote_tx_item->voting_hash,
-                                                l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx, &pkey_hash)) {
+                                               l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx, &l_pkey_hash)) {
             log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx,
                                         dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash));
             return -20;
@@ -433,62 +411,75 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
         return -13;
     }
 
+    // check out conds
+    dap_list_t *l_tsd_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_TSD, NULL);
+    for (dap_list_t *it = l_tsd_list; it; it = it->next) {
+        dap_tsd_t *l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t*)it->data)->tsd;
+        dap_hash_fast_t l_hash = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->tx_hash;
+        int l_out_idx = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->out_idx;
+        if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND)
+            return -14;
+        dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash);
+        dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_out_idx);
+        if (!l_prev_out || l_prev_out->header.item_type != TX_ITEM_TYPE_OUT_COND ||
+                l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
+            return -16;
+        if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, l_pkey_sign))
+            return -17;
+        if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx, &l_pkey_hash))
+            return -15;
+        if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) {
+            log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
+            return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW;
+        }
+    }
+
     if (a_apply) {
+        // Mark conditional outs
+        pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock);
+        if (l_old_vote) {
+            dap_hash_fast_t *l_vote_hash = &((dap_chain_net_vote_t *)l_old_vote->data)->vote_hash;
+            dap_chain_net_voting_cond_outs_t *it = NULL, *tmp;
+            HASH_ITER(hh, l_voting->voting_spent_cond_outs, it, tmp) {
+                if (!dap_hash_fast_compare(l_vote_hash, &it->pkey_hash))
+                    continue;
+                HASH_DEL(l_voting->voting_spent_cond_outs, it);
+                DAP_DELETE(it);
+            }
+        }
+        for (dap_list_t *it = l_tsd_list; it; it = it->next) {
+            dap_tsd_t *l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t *)it->data)->tsd;
+            if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND)
+                continue;
+            dap_chain_net_voting_cond_outs_t *l_tx_out = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY);
+            l_tx_out->tx_hash = ((dap_chain_tx_voting_tx_cond_t *)l_tsd->data)->tx_hash;
+            l_tx_out->out_idx = ((dap_chain_tx_voting_tx_cond_t *)l_tsd->data)->out_idx;
+            l_tx_out->pkey_hash = l_pkey_hash;
+            HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_tx_out);
+        }
+        pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock);
+
         dap_chain_net_vote_t *l_vote_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_vote_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY);
         l_vote_item->vote_hash = *a_tx_hash;
-        l_vote_item->pkey_hash = pkey_hash;
+        l_vote_item->pkey_hash = l_pkey_hash;
         l_vote_item->answer_idx = l_vote_tx_item->answer_idx;
         l_vote_item->weight = l_weight;
 
-        // cycle is safe cause return after link deletion
-        for (dap_list_t *it = l_voting->votes; it; it = it->next) {
-            if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &pkey_hash)){
-                if (!l_voting->voting_params.vote_changing_allowed) {
-                    char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE];
-                    dap_hash_fast_to_str(a_tx_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE);
-                    log_it(L_WARNING, "The voting %s don't allow change your vote %s",
-                           dap_hash_fast_to_str_static(&l_voting->voting_hash), l_vote_hash_str);
-                    DAP_DELETE(l_vote_item);
-                    return -11;
-                }
-                dap_hash_fast_t *l_vote_hash = &((dap_chain_net_vote_t *)it->data)->vote_hash;
-                //delete conditional outputs
-                dap_chain_datum_tx_t *l_old_tx = dap_ledger_tx_find_by_hash(a_ledger, l_vote_hash);
-                if (!l_old_tx) {
-                    char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE];
-                    dap_hash_fast_to_str(l_vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE);
-                    log_it(L_ERROR, "Can't find old vote %s of voting %s in ledger",
-                           l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash));
-                }
-                dap_list_t* l_tsd_list = dap_chain_datum_tx_items_get(l_old_tx, TX_ITEM_TYPE_TSD, NULL);
-                for (dap_list_t *it_tsd = l_tsd_list; it_tsd; it_tsd = it_tsd->next) {
-                    dap_tsd_t* l_tsd = (dap_tsd_t*)((dap_chain_tx_tsd_t*)it_tsd->data)->tsd;
-                    dap_hash_fast_t *l_hash = &((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->tx_hash;
-                    if (l_tsd->type == VOTING_TSD_TYPE_VOTE_TX_COND) {
-                        dap_chain_net_voting_cond_outs_t *l_tx_outs = NULL;
-                        pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock);
-                        HASH_FIND(hh, l_voting->voting_spent_cond_outs, l_hash, sizeof(dap_hash_fast_t), l_tx_outs);
-                        if(l_tx_outs)
-                            HASH_DELETE(hh, l_voting->voting_spent_cond_outs, l_tx_outs);
-                        pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock);
-                    }
-                }
-                dap_list_free(l_tsd_list);
-                // change vote & move it to the end of list
-                l_voting->votes = dap_list_remove_link(l_voting->votes, it);
-                l_voting->votes = dap_list_append(l_voting->votes, l_vote_item);
-                char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE];
-                dap_hash_fast_to_str(&((dap_chain_net_vote_t *)it->data)->vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE);
-                DAP_DELETE(it->data);
-                log_it(L_NOTICE, "Vote %s of voting %s has been changed", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash));
-                return DAP_LEDGER_CHECK_OK;
-            }
+        if (l_old_vote) {
+            // change vote & move it to the end of list
+            const char *l_vote_hash_str = dap_hash_fast_to_str_static(&((dap_chain_net_vote_t *)l_old_vote->data)->vote_hash);
+            DAP_DELETE(l_old_vote->data);
+            l_voting->votes = dap_list_delete_link(l_voting->votes, l_old_vote);
+            log_it(L_NOTICE, "Vote %s of voting %s has been changed", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash));
+        } else {
+            const char *l_vote_hash_str = dap_hash_fast_to_str_static(a_tx_hash);
+            log_it(L_NOTICE, "Vote %s of voting %s has been accepted", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash));
         }
+
         l_voting->votes = dap_list_append(l_voting->votes, l_vote_item);
-        char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE];
-        dap_hash_fast_to_str(a_tx_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE);
-        log_it(L_NOTICE, "Vote %s of voting %s has been accepted", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash));
     }
+    dap_list_free(l_tsd_list);
+
     return DAP_LEDGER_CHECK_OK;
 }
 
@@ -916,11 +907,6 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
                 dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED, 
                                                     "This voting required a delegated key. Parameter -cert must contain a valid certificate name");
             } break;
-            case DAP_CHAIN_NET_VOTE_VOTING_NO_PUBLIC_KEY_IN_CERT: {
-                dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_NO_PUBLIC_KEY_IN_CERT, 
-                                                    "Can't serialize public key of certificate \"%s\"",
-                                                    l_cert_name);
-            } break;
             case DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED: {
                 dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED, "Your key is not delegated.");
             } break;
@@ -1090,7 +1076,8 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
     return 0;
 }
 
-static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash)
+static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash,
+                                              dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash)
 {
     int l_coin_is_spent = 0;
 
@@ -1120,7 +1107,7 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
         return 0;
     }
 
-    if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, a_tx_prev_hash, a_out_idx) != 0){
+    if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, a_tx_prev_hash, a_out_idx, a_pkey_hash) != 0){
         return 1;
     }
 
@@ -1140,10 +1127,8 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
 
     dap_list_t *l_ins_list_temp = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
     dap_list_t *l_cond_ins_list = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_COND, NULL);
-    if (!l_ins_list_temp && !l_cond_ins_list){
-        log_it(L_ERROR, "Can't get inputs from tx");
-        return -1;
-    }
+    if (!l_ins_list_temp && !l_cond_ins_list) // it's emisssion or reward TX, not marked yet
+        return 0;
 
     dap_list_t *l_ins_list = dap_list_concat(l_ins_list_temp, l_cond_ins_list);
     dap_list_t *l_tx_list = dap_list_append(NULL, l_ins_list); // "stack" for saving txs on up level
@@ -1185,7 +1170,7 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
                 break;
             }
             if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, l_temp_in->header.tx_prev_hash,
-                                                      l_temp_in->header.tx_out_prev_idx) != 0) {
+                                                      l_temp_in->header.tx_out_prev_idx, a_pkey_hash) != 0) {
                 l_coin_is_spent = 1;
                 continue;
             }
@@ -1205,16 +1190,18 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
             continue;
         }
 
-        dap_chain_tx_vote_t *l_vote =(dap_chain_tx_vote_t *) dap_chain_datum_tx_item_get(l_tx_prev_temp, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL);
-        if(l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)){
-            dap_list_t *l_temp = NULL;
-            while (l_temp){
-                dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)l_temp->data;
-                if (dap_hash_fast_compare(&l_vote->vote_hash, &l_temp_in->header.tx_prev_hash)){
+        dap_chain_tx_vote_t *l_vote = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(l_tx_prev_temp, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL);
+        if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)) {
+            for (dap_list_t *it = l_voting->votes; it; it = it->next) {
+                dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data;
+                if (dap_hash_fast_compare(&l_vote->vote_hash, &l_temp_in->header.tx_prev_hash)) {
+                    if (l_voting->voting_params.vote_changing_allowed &&
+                            !dap_hash_fast_is_blank(a_pkey_hash) &&
+                            dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash))
+                        break;  // it's vote changing, allow it
                     l_coin_is_spent = 1;
                     break;
                 }
-                l_temp = l_temp->next;
             }
         }
 
@@ -1237,7 +1224,9 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
     return l_coin_is_spent;
 }
 
-static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx)
+static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash,
+                                                 dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx,
+                                                 dap_hash_fast_t *a_pkey_hash)
 {
 
     dap_chain_net_votings_t * l_voting = NULL;
@@ -1250,16 +1239,15 @@ static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_has
         return -1;
     }
 
-    dap_chain_net_voting_cond_outs_t *l_tx_outs = NULL;
+    dap_chain_net_voting_cond_outs_t *l_tx_out = NULL;
     pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock);
-    HASH_FIND(hh, l_voting->voting_spent_cond_outs, &a_tx_cond_hash, sizeof(dap_hash_fast_t), l_tx_outs);
+    HASH_FIND(hh, l_voting->voting_spent_cond_outs, &a_tx_cond_hash, sizeof(dap_hash_fast_t), l_tx_out);
     pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock);
 
-    if (!l_tx_outs || l_tx_outs->out_idx != a_cond_out_idx){
-        return 0;
-    }
+    if (l_tx_out && l_tx_out->out_idx == a_cond_out_idx)
+        return a_pkey_hash ? !dap_hash_fast_compare(a_pkey_hash, &l_tx_out->pkey_hash) : 1;
 
-    return 1;
+    return 0;
 }
 
 int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
@@ -1467,37 +1455,25 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
     if (l_voting->voting_params.voting_expire && dap_time_now() > l_voting->voting_params.voting_expire)
         return DAP_CHAIN_NET_VOTE_VOTING_ALREADY_EXPIRED;
 
-    dap_hash_fast_t l_pkey_hash = {0};
+    dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, a_net->pub.id);
+    if (!l_addr_from)
+        return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID;
 
+    dap_hash_fast_t l_pkey_hash = {0};
     if (l_voting->voting_params.delegate_key_required) {
         if (!a_cert)
             return DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED;
-        if (!a_cert->enc_key)
+        if (dap_cert_get_pkey_hash(a_cert, &l_pkey_hash))
             return DAP_CHAIN_NET_VOTE_VOTING_NO_KEY_FOUND_IN_CERT;
-        // Get publivc key hash
-        size_t l_pub_key_size = 0;
-        uint8_t *l_pub_key = dap_enc_key_serialize_pub_key(a_cert->enc_key, &l_pub_key_size);;
-        if (l_pub_key == NULL)
-            return DAP_CHAIN_NET_VOTE_VOTING_NO_PUBLIC_KEY_IN_CERT;
-
-        dap_hash_fast(l_pub_key, l_pub_key_size, &l_pkey_hash);
-        DAP_DELETE(l_pub_key);
         if (!dap_chain_net_srv_stake_check_pkey_hash(a_net->pub.id, &l_pkey_hash))
             return DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED;
-        for (dap_list_t *it = l_voting->votes; it; it = it->next)
-            if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &l_pkey_hash) &&
-                    !l_voting->voting_params.vote_changing_allowed)
-                return DAP_CHAIN_NET_VOTE_VOTING_DOES_NOT_ALLOW_CHANGE_YOUR_VOTE;
-    }
-
-    dap_enc_key_t *l_priv_key = NULL;
-
-    l_priv_key = dap_chain_wallet_get_key(a_wallet, 0);
-
-    const dap_chain_addr_t *l_addr_from = (const dap_chain_addr_t *) dap_chain_wallet_get_addr(a_wallet, a_net->pub.id);
+    } else
+        l_pkey_hash = l_addr_from->data.hash_fast;
 
-    if (!l_addr_from)
-        return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID;
+    for (dap_list_t *it = l_voting->votes; it; it = it->next)
+        if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &l_pkey_hash) &&
+                !l_voting->voting_params.vote_changing_allowed)
+            return DAP_CHAIN_NET_VOTE_VOTING_DOES_NOT_ALLOW_CHANGE_YOUR_VOTE;
 
     const char *l_token_ticker = l_voting->voting_params.token_ticker;
     uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer;
@@ -1519,9 +1495,8 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
     dap_list_t *it, *tmp;
     DL_FOREACH_SAFE(l_list_used_out, it, tmp) {
         dap_chain_tx_used_out_item_t *l_out = (dap_chain_tx_used_out_item_t *)it->data;
-        if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out, &l_pkey_hash) &&
-                !l_voting->voting_params.vote_changing_allowed) {
-            dap_list_delete_link(l_list_used_out, it);
+        if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out, &l_pkey_hash)) {
+            l_list_used_out = dap_list_delete_link(l_list_used_out, it);
             continue;
         }
         if (SUM_256_256(l_value_transfer_new, l_out->value, &l_value_transfer_new))
@@ -1572,7 +1547,7 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
     dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from);
     for (dap_list_t *it = l_outs; it; it = it->next) {
         dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data;
-        if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out) != 0)
+        if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out, &l_pkey_hash) != 0)
             continue;
         dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out);
         if(!l_item){
@@ -1608,18 +1583,19 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
         return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
     }
 
+    dap_enc_key_t *l_priv_key = dap_chain_wallet_get_key(a_wallet, 0);
     // add 'sign' items with wallet sign
-    if(dap_chain_datum_tx_add_sign_item(&l_tx, l_priv_key) != 1) {
+    if (dap_chain_datum_tx_add_sign_item(&l_tx, l_priv_key) != 1) {
         dap_chain_datum_tx_delete(l_tx);
+        dap_enc_key_delete(l_priv_key);
         return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX;
     }
+    dap_enc_key_delete(l_priv_key);
 
     // add 'sign' items with delegated key if needed
-    if(a_cert){
-        if(dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) {
-            dap_chain_datum_tx_delete(l_tx);
-            return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX;
-        }
+    if (a_cert && dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX;
     }
 
     size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h
index 6252b37771..8c61bc51d1 100644
--- a/modules/service/voting/include/dap_chain_net_srv_voting.h
+++ b/modules/service/voting/include/dap_chain_net_srv_voting.h
@@ -109,7 +109,6 @@ enum DAP_CHAIN_NET_VOTE_VOTING_ERROR{
     DAP_CHAIN_NET_VOTE_VOTING_THIS_VOTING_HAVE_MAX_VALUE_VOTES,
     DAP_CHAIN_NET_VOTE_VOTING_ALREADY_EXPIRED,
     DAP_CHAIN_NET_VOTE_VOTING_NO_KEY_FOUND_IN_CERT,
-    DAP_CHAIN_NET_VOTE_VOTING_NO_PUBLIC_KEY_IN_CERT,
     DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED,
     DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED,
     DAP_CHAIN_NET_VOTE_VOTING_DOES_NOT_ALLOW_CHANGE_YOUR_VOTE,
-- 
GitLab


From 4e94194671c71d524645cf9b67b87842a455705b Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Tue, 4 Mar 2025 16:10:32 +0700
Subject: [PATCH 04/53] [-] Debug code

---
 modules/consensus/esbocs/dap_chain_cs_esbocs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index f7c088e54b..dea80a38fd 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -837,7 +837,7 @@ static dap_list_t *s_get_validators_list(dap_chain_esbocs_t *a_esbocs, dap_hash_
     dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_esbocs);
     dap_list_t *l_ret = NULL;
     dap_list_t *l_validators = NULL;
-    if (l_esbocs_pvt->poa_mode) {   // UNDO it after debug
+    if (!l_esbocs_pvt->poa_mode) {
         if (a_excluded_list_size) {
             l_validators =  dap_chain_net_srv_stake_get_validators(a_esbocs->chain->net_id, false, NULL);
             uint16_t l_excluded_num = *a_excluded_list;
-- 
GitLab


From 0203d211c22944dfa41c5b217c30916bcd344a9b Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Tue, 4 Mar 2025 16:31:59 +0700
Subject: [PATCH 05/53] [*] Help clarification

---
 modules/service/voting/dap_chain_net_srv_voting.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index a447a584e3..bc69703081 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -118,7 +118,7 @@ int dap_chain_net_srv_voting_init()
     dap_chain_ledger_voting_verificator_add(s_datum_tx_voting_verification_callback, s_datum_tx_voting_verification_delete_callback);
     dap_cli_server_cmd_add("voting", s_cli_voting, "Voting commands.", ""
                             "voting create -net <net_name> -question <\"Question_string\"> -options <\"Option0\", \"Option1\" ... \"OptionN\"> [-expire <voting_expire_time_in_RCF822>]"
-                                           " [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name> -token <ticker>\n"
+                                           " [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name> [-token <ticker>]\n"
                             "voting vote -net <net_name> -hash <voting_hash> -option_idx <option_index> [-cert <delegate_cert_name>] -fee <value_datoshi> -w <fee_wallet_name>\n"
                             "voting list -net <net_name>\n"
                             "voting dump -net <net_name> -hash <voting_hash>\n");
-- 
GitLab


From ee46625e37570f59ba4c26202a78332d45be63be Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Wed, 5 Mar 2025 13:42:14 +0700
Subject: [PATCH 06/53] [*] Cond out list compound fix

---
 dap-sdk                                       |  2 +-
 .../consensus/esbocs/dap_chain_cs_esbocs.c    |  2 +-
 modules/net/dap_chain_ledger.c                |  5 ++--
 .../service/voting/dap_chain_net_srv_voting.c | 30 ++++++++++++-------
 .../voting/include/dap_chain_net_srv_voting.h |  1 +
 5 files changed, 24 insertions(+), 16 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index 3491640b76..a7b6da64ee 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 3491640b76de5715eb3936ccd377abd51d88b99e
+Subproject commit a7b6da64ee24a3aba64dcbbd5f3f356069d853ad
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index dea80a38fd..c54ba27b9f 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -837,7 +837,7 @@ static dap_list_t *s_get_validators_list(dap_chain_esbocs_t *a_esbocs, dap_hash_
     dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_esbocs);
     dap_list_t *l_ret = NULL;
     dap_list_t *l_validators = NULL;
-    if (!l_esbocs_pvt->poa_mode) {
+    if (l_esbocs_pvt->poa_mode) {
         if (a_excluded_list_size) {
             l_validators =  dap_chain_net_srv_stake_get_validators(a_esbocs->chain->net_id, false, NULL);
             uint16_t l_excluded_num = *a_excluded_list;
diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c
index deaac956e7..49b6f840a8 100644
--- a/modules/net/dap_chain_ledger.c
+++ b/modules/net/dap_chain_ledger.c
@@ -5670,11 +5670,10 @@ dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t *
         l_iter_start = l_iter_start->hh.next;
     } else
         l_iter_start = l_ledger_pvt->ledger_items;
-    for (it = l_iter_start; it; it = it->hh.next) {
+    for (it = l_iter_start; it; it = it->hh.next, ret = NULL) {
         // If a_token is setup we check if its not our token - miss it
         if (*it->cache_data.token_ticker && dap_strcmp(it->cache_data.token_ticker, a_token))
             continue;
-        ret = NULL;
         // Get 'out_cond' item from transaction
         byte_t *l_item; size_t l_size; int i, l_out_idx = 0;
         TX_ITEM_ITER_TX_TYPE(l_item, TX_ITEM_TYPE_OUT_ALL, l_size, i, it->tx) {
@@ -5699,7 +5698,7 @@ dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t *
             continue;
         }
         // Get sign item from transaction
-        dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_SIG, NULL);
+        dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_SIG, NULL);
         // Get dap_sign_t from item
         dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
         // compare public key in transaction with a_public_key
diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index bc69703081..3e057d8856 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -394,7 +394,8 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
         if (dap_strcmp(l_ticker_in, l_voting->voting_params.token_ticker))
             continue;
         if (s_datum_tx_voting_coin_check_spent(a_ledger->net, l_vote_tx_item->voting_hash,
-                                               l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx, &l_pkey_hash)) {
+                                               l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx,
+                                               l_old_vote ? &l_pkey_hash : NULL)) {
             log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx,
                                         dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash));
             return -20;
@@ -426,7 +427,8 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
             return -16;
         if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, l_pkey_sign))
             return -17;
-        if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx, &l_pkey_hash))
+        if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx,
+                                                  l_old_vote ? &l_pkey_hash : NULL))
             return -15;
         if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) {
             log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
@@ -830,10 +832,11 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
         }
 
         dap_hash_fast_t l_voting_hash = {};
-        dap_chain_hash_fast_from_str(l_hash_str, &l_voting_hash);
-
+        if (dap_chain_hash_fast_from_str(l_hash_str, &l_voting_hash)) {
+            dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID, "Hash string is not recognozed as hex of base58 hash");
+            return -DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID;
+        }
 
-        dap_chain_hash_fast_t l_pkey_hash;
         dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_name);
         dap_cert_t * l_cert = dap_cert_find_by_name(l_cert_name);
         if (l_cert_name){
@@ -1067,7 +1070,6 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
         const char *l_tw_coins, *l_tw_datoshi = dap_uint256_to_char(l_total_weight, &l_tw_coins);
         json_object_object_add(json_vote_out, "total_sum", json_object_new_string(l_tw_coins));
         json_object_object_add(json_vote_out, "total_sum_datoshi", json_object_new_string(l_tw_datoshi));
-        json_object_object_add(json_vote_out, "ticker", json_object_new_string(l_net->pub.native_ticker));
         json_object_array_add(*json_arr_reply, json_vote_out);
     } break;
     default:
@@ -1470,10 +1472,14 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
     } else
         l_pkey_hash = l_addr_from->data.hash_fast;
 
+    bool l_vote_changed = false;
     for (dap_list_t *it = l_voting->votes; it; it = it->next)
-        if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &l_pkey_hash) &&
-                !l_voting->voting_params.vote_changing_allowed)
-            return DAP_CHAIN_NET_VOTE_VOTING_DOES_NOT_ALLOW_CHANGE_YOUR_VOTE;
+        if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &l_pkey_hash)) {
+            if (!l_voting->voting_params.vote_changing_allowed)
+                return DAP_CHAIN_NET_VOTE_VOTING_DOES_NOT_ALLOW_CHANGE_YOUR_VOTE;
+            l_vote_changed = true;
+            break;
+        }
 
     const char *l_token_ticker = l_voting->voting_params.token_ticker;
     uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer;
@@ -1495,7 +1501,8 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
     dap_list_t *it, *tmp;
     DL_FOREACH_SAFE(l_list_used_out, it, tmp) {
         dap_chain_tx_used_out_item_t *l_out = (dap_chain_tx_used_out_item_t *)it->data;
-        if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out, &l_pkey_hash)) {
+        if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out,
+                                               l_vote_changed ? &l_pkey_hash : NULL)) {
             l_list_used_out = dap_list_delete_link(l_list_used_out, it);
             continue;
         }
@@ -1547,7 +1554,8 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
     dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from);
     for (dap_list_t *it = l_outs; it; it = it->next) {
         dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data;
-        if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out, &l_pkey_hash) != 0)
+        if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out,
+                                                  l_vote_changed ? &l_pkey_hash : NULL) != 0)
             continue;
         dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out);
         if(!l_item){
diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h
index 8c61bc51d1..7efdd2d656 100644
--- a/modules/service/voting/include/dap_chain_net_srv_voting.h
+++ b/modules/service/voting/include/dap_chain_net_srv_voting.h
@@ -125,6 +125,7 @@ enum DAP_CHAIN_NET_VOTE_VOTING_ERROR{
     DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING,
     DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_NOT_VALID,
     DAP_CHAIN_NET_VOTE_VOTING_HASH_NOT_FOUND,
+    DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID,
     DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_FIND_CERT,
     DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_NOT_VALID,
     DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_BAD_TYPE,
-- 
GitLab


From bdccd2ffe867f59a5d72a34c50cab225353788e5 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Wed, 5 Mar 2025 14:07:51 +0700
Subject: [PATCH 07/53] [+] Owner wallet address for delegation txs

---
 modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
index 59320cec6d..7655ee5239 100644
--- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
+++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
@@ -3523,6 +3523,9 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply)
                     json_object_object_add(l_json_obj_tx, "node_address", json_object_new_string(l_node_address_text_block));
                     json_object_object_add(l_json_obj_tx, "value_coins", json_object_new_string(l_coins));
                     json_object_object_add(l_json_obj_tx, "value_datoshi", json_object_new_string(l_balance));
+                    dap_sign_t *l_owner_sign = dap_chain_datum_tx_get_sign(l_datum_tx, 0);
+                    dap_chain_addr_t l_owner_addr; dap_chain_addr_fill_from_sign(&l_owner_addr, l_owner_sign, l_net->pub.id);
+                    json_object_object_add(l_json_obj_tx, "owner_addr", json_object_new_string(dap_chain_addr_to_str_static(&l_owner_addr)));
                     json_object_array_add(l_json_arr_tx, l_json_obj_tx);
                     DAP_DELETE(l_node_address_text_block);
                 }
-- 
GitLab


From d8a622c72189648642480fc2b64c2ccc2f9e6a18 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Wed, 5 Mar 2025 14:20:26 +0700
Subject: [PATCH 08/53] [*] Onwage definition fix for delegation txs

---
 .../service/stake/dap_chain_net_srv_stake_pos_delegate.c    | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
index 7655ee5239..6339b40935 100644
--- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
+++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
@@ -3523,7 +3523,11 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply)
                     json_object_object_add(l_json_obj_tx, "node_address", json_object_new_string(l_node_address_text_block));
                     json_object_object_add(l_json_obj_tx, "value_coins", json_object_new_string(l_coins));
                     json_object_object_add(l_json_obj_tx, "value_datoshi", json_object_new_string(l_balance));
-                    dap_sign_t *l_owner_sign = dap_chain_datum_tx_get_sign(l_datum_tx, 0);
+                    dap_hash_fast_t l_owner_hash = dap_ledger_get_first_chain_tx_hash(l_net->pub.ledger, l_datum_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE);
+                    dap_chain_datum_tx_t *l_owner_tx = dap_hash_fast_is_blank(&l_owner_hash) ? l_datum_tx
+                                                                                             : dap_ledger_tx_find_datum_by_hash(l_net->pub.ledger, &l_owner_hash, NULL, false);
+                    assert(l_owner_tx);
+                    dap_sign_t *l_owner_sign = dap_chain_datum_tx_get_sign(l_owner_tx, 0);
                     dap_chain_addr_t l_owner_addr; dap_chain_addr_fill_from_sign(&l_owner_addr, l_owner_sign, l_net->pub.id);
                     json_object_object_add(l_json_obj_tx, "owner_addr", json_object_new_string(dap_chain_addr_to_str_static(&l_owner_addr)));
                     json_object_array_add(l_json_arr_tx, l_json_obj_tx);
-- 
GitLab


From 07a967211d7cc2812597629333c114fd513ce8d5 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Wed, 5 Mar 2025 15:20:36 +0700
Subject: [PATCH 09/53] [-] Debug code

---
 modules/consensus/esbocs/dap_chain_cs_esbocs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index c54ba27b9f..dea80a38fd 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -837,7 +837,7 @@ static dap_list_t *s_get_validators_list(dap_chain_esbocs_t *a_esbocs, dap_hash_
     dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_esbocs);
     dap_list_t *l_ret = NULL;
     dap_list_t *l_validators = NULL;
-    if (l_esbocs_pvt->poa_mode) {
+    if (!l_esbocs_pvt->poa_mode) {
         if (a_excluded_list_size) {
             l_validators =  dap_chain_net_srv_stake_get_validators(a_esbocs->chain->net_id, false, NULL);
             uint16_t l_excluded_num = *a_excluded_list;
-- 
GitLab


From d9ac93979d88c7145f1dac3ce136fee67a6fb666 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Thu, 6 Mar 2025 16:06:21 +0700
Subject: [PATCH 10/53] [+] Printing unspent OUT_CONDs for wallet

---
 modules/net/dap_chain_node_cli.c     |  2 +-
 modules/net/dap_chain_node_cli_cmd.c | 53 +++++++++++++++++-----------
 2 files changed, 33 insertions(+), 22 deletions(-)

diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c
index 5faac29320..85b96544b5 100644
--- a/modules/net/dap_chain_node_cli.c
+++ b/modules/net/dap_chain_node_cli.c
@@ -159,7 +159,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
                             "wallet info {-addr <addr> | -w <wallet_name>} -net <net_name>\n"
                             "wallet activate -w <wallet_name> -password <password> [-ttl <password_ttl_in_minutes>]\n"
                             "wallet deactivate -w <wallet_name>>\n"
-                            "wallet outputs {-addr <addr> | -w <wallet_name>} -net <net_name> -token <token_tiker> [-value <uint256_value>]\n"
+                            "wallet outputs {-addr <addr> | -w <wallet_name>} -net <net_name> -token <token_tiker> [{-cond | -value <uint256_value>}]\n"
                             "wallet convert -w <wallet_name> {-password <password> | -remove_password }\n");
 
 
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index a5db76bcfe..a057b6f560 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -1799,45 +1799,56 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE;
                     return DAP_CHAIN_NODE_CLI_COM_TX_WALLET_PARAM_ERR;
             }
             json_object * json_obj_wall = json_object_new_object();
-            const char* l_value_str = NULL;
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str);
+            const char *l_cond_str, *l_value_str = NULL;
+            uint256_t l_value_datoshi = uint256_0, l_value_sum = uint256_0;
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cond", &l_cond_str);
+            if (!l_cond_str) {
+                dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str);
+                if (l_value_str) {
+                    l_value_datoshi = dap_chain_balance_scan(l_value_str);
+                    if (IS_ZERO_256(l_value_datoshi)) {
+                        dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_TX_WALLET_PARAM_ERR,
+                                                   "Can't convert -value param to 256bit integer");
+                            json_object_put(json_arr_out);
+                            return DAP_CHAIN_NODE_CLI_COM_TX_WALLET_PARAM_ERR;
+                    }
+                }
+            }
 
             dap_list_t *l_outs_list = NULL;
-            uint256_t l_value_sum = uint256_0;
-
 
-
-            if (l_value_str){
-                uint256_t l_value_datoshi = dap_chain_balance_scan(l_value_str);
+            if (l_value_str) {
                 if (dap_chain_wallet_cache_tx_find_outs_with_val(l_net, l_token_tiker, l_addr, &l_outs_list, l_value_datoshi, &l_value_sum))
                     l_outs_list = dap_ledger_get_list_tx_outs_with_val(l_net->pub.ledger, l_token_tiker, l_addr, l_value_datoshi, &l_value_sum);
+            } else if (l_cond_str) {
+                l_outs_list = dap_ledger_get_list_tx_cond_outs(l_net->pub.ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_tiker, l_addr);
             } else {
                 if (dap_chain_wallet_cache_tx_find_outs(l_net, l_token_tiker, l_addr, &l_outs_list, &l_value_sum))
                     l_outs_list = dap_ledger_get_list_tx_outs(l_net->pub.ledger, l_token_tiker, l_addr, &l_value_sum);
             }
             json_object_object_add(json_obj_wall, "wallet_addr", json_object_new_string(dap_chain_addr_to_str_static(l_addr)));
-            const char *l_out_total_value_str = dap_chain_balance_print(l_value_sum);
-            const char *l_out_total_value_coins_str = dap_chain_balance_to_coins(l_value_sum);
-            json_object_object_add(json_obj_wall, "total_value_coins", json_object_new_string(l_out_total_value_coins_str));
-            json_object_object_add(json_obj_wall, "total_value_datoshi", json_object_new_string(l_out_total_value_str));
-            DAP_DEL_Z(l_out_total_value_str);
-            DAP_DEL_Z(l_out_total_value_coins_str);
             struct json_object *l_json_outs_arr = json_object_new_array();
-            for (dap_list_t *l_temp = l_outs_list; l_temp; l_temp = l_temp->next){
+            if (!l_json_outs_arr)
+                return json_object_put(json_arr_out), DAP_CHAIN_NODE_CLI_COM_TX_WALLET_MEMORY_ERR;
+            for (dap_list_t *l_temp = l_outs_list; l_temp; l_temp = l_temp->next) {
+                json_object *json_obj_item = json_object_new_object();
+                if (!json_obj_item)
+                    return json_object_put(json_arr_out), DAP_CHAIN_NODE_CLI_COM_TX_WALLET_MEMORY_ERR;
                 dap_chain_tx_used_out_item_t *l_item = l_temp->data;
-                json_object* json_obj_item = json_object_new_object();
-                const char *l_out_value_str = dap_chain_balance_print(l_item->value);
-                const char *l_out_value_coins_str = dap_chain_balance_to_coins(l_item->value);
+                const char *l_out_value_coins_str, *l_out_value_str = dap_uint256_to_char(l_item->value, &l_out_value_coins_str);
                 json_object_object_add(json_obj_item,"item_type", json_object_new_string("unspent_out"));
                 json_object_object_add(json_obj_item,"value_coins", json_object_new_string(l_out_value_coins_str));
                 json_object_object_add(json_obj_item,"value_datosi", json_object_new_string(l_out_value_str));
-                json_object_object_add(json_obj_item,"prev_hash", json_object_new_string(dap_hash_fast_to_str_static(&l_item->tx_hash_fast)));  
-                json_object_object_add(json_obj_item,"out_prev_idx", json_object_new_int64(l_item->num_idx_out));   
+                json_object_object_add(json_obj_item,"prev_hash", json_object_new_string(dap_hash_fast_to_str_static(&l_item->tx_hash_fast)));
+                json_object_object_add(json_obj_item,"out_prev_idx", json_object_new_int64(l_item->num_idx_out));
                 json_object_array_add(l_json_outs_arr, json_obj_item);
-                DAP_DEL_Z(l_out_value_str);
-                DAP_DEL_Z(l_out_value_coins_str);
+                if (l_cond_str)
+                    SUM_256_256(l_value_sum, l_item->value, &l_value_sum);
             }
             dap_list_free_full(l_outs_list, NULL);
+            const char * l_out_total_value_coins_str, *l_out_total_value_str = dap_uint256_to_char(l_value_sum, &l_out_total_value_coins_str);
+            json_object_object_add(json_obj_wall, "total_value_coins", json_object_new_string(l_out_total_value_coins_str));
+            json_object_object_add(json_obj_wall, "total_value_datoshi", json_object_new_string(l_out_total_value_str));
             json_object_object_add(json_obj_wall, "outs", l_json_outs_arr);
             json_object_array_add(json_arr_out, json_obj_wall);
         } break;
-- 
GitLab


From 4a754aa1de646b23e0bdf3d37fec0a9b5f96d918 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Fri, 7 Mar 2025 14:13:43 +0700
Subject: [PATCH 11/53] [*] History assertion fix

---
 modules/net/dap_chain_node_cli_cmd.c    | 4 ++--
 modules/net/dap_chain_node_cli_cmd_tx.c | 8 +++-----
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index a057b6f560..4d23819b9a 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -1799,7 +1799,7 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE;
                     return DAP_CHAIN_NODE_CLI_COM_TX_WALLET_PARAM_ERR;
             }
             json_object * json_obj_wall = json_object_new_object();
-            const char *l_cond_str, *l_value_str = NULL;
+            const char *l_cond_str = NULL, *l_value_str = NULL;
             uint256_t l_value_datoshi = uint256_0, l_value_sum = uint256_0;
             dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cond", &l_cond_str);
             if (!l_cond_str) {
@@ -1836,7 +1836,7 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE;
                     return json_object_put(json_arr_out), DAP_CHAIN_NODE_CLI_COM_TX_WALLET_MEMORY_ERR;
                 dap_chain_tx_used_out_item_t *l_item = l_temp->data;
                 const char *l_out_value_coins_str, *l_out_value_str = dap_uint256_to_char(l_item->value, &l_out_value_coins_str);
-                json_object_object_add(json_obj_item,"item_type", json_object_new_string("unspent_out"));
+                json_object_object_add(json_obj_item,"item_type", json_object_new_string(l_cond_str ? "unspent_cond_out" : "unspent_out"));
                 json_object_object_add(json_obj_item,"value_coins", json_object_new_string(l_out_value_coins_str));
                 json_object_object_add(json_obj_item,"value_datosi", json_object_new_string(l_out_value_str));
                 json_object_object_add(json_obj_item,"prev_hash", json_object_new_string(dap_hash_fast_to_str_static(&l_item->tx_hash_fast)));
diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index 0748ba83ce..edf553a80b 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -429,7 +429,7 @@ json_object* dap_db_history_addr(json_object* a_json_arr_reply, dap_chain_addr_t
         int l_src_subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_UNDEFINED;
         uint8_t *l_tx_item = NULL;
         size_t l_size; int i, q = 0;
-        // Проход по входам
+        // Inputs iteration
         TX_ITEM_ITER_TX_TYPE(l_tx_item, TX_ITEM_TYPE_IN_ALL, l_size, i, l_tx) {
             dap_chain_hash_fast_t *l_tx_prev_hash = NULL;
             int l_tx_prev_out_idx;
@@ -562,7 +562,7 @@ json_object* dap_db_history_addr(json_object* a_json_arr_reply, dap_chain_addr_t
 
             if (l_src_addr && l_dst_addr &&
                     dap_chain_addr_compare(l_dst_addr, l_src_addr) &&
-                    dap_strcmp(l_noaddr_token, l_dst_token))
+                    l_noaddr_token && dap_strcmp(l_noaddr_token, l_dst_token))
                 continue;   // sent to self (coinback)
 
             if (l_dst_addr && l_net_fee_used && dap_chain_addr_compare(&l_net_fee_addr, l_dst_addr))
@@ -698,9 +698,7 @@ json_object* dap_db_history_addr(json_object* a_json_arr_reply, dap_chain_addr_t
             json_object_object_add(l_corr_object, "recv_datoshi", json_object_new_string(l_value_str));
         }
         if (l_send_to_same_cond) {
-            json_object *l_cond_recv_value_obj = json_object_object_get(l_cond_recv_object, "recv_datoshi");
-            const char *l_cond_recv_value_str = json_object_get_string(l_cond_recv_value_obj);
-            uint256_t l_cond_recv_value = dap_uint256_scan_uninteger(l_cond_recv_value_str);
+            uint256_t l_cond_recv_value = l_cond_value;
             json_object *l_cond_send_value_obj = json_object_object_get(l_cond_send_object, "send_datoshi");
             const char *l_cond_send_value_str = json_object_get_string(l_cond_send_value_obj);
             uint256_t l_cond_send_value = dap_uint256_scan_uninteger(l_cond_send_value_str);
-- 
GitLab


From c28457db3fe5e08c305820d07d0b792ea709bad1 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Fri, 7 Mar 2025 17:18:30 +0700
Subject: [PATCH 12/53] [*] Check spent recursion vs indefinite cycle

---
 modules/net/dap_chain_ledger.c                |  12 +-
 .../service/voting/dap_chain_net_srv_voting.c | 175 +++++++-----------
 2 files changed, 74 insertions(+), 113 deletions(-)

diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c
index 49b6f840a8..0d4530aca7 100644
--- a/modules/net/dap_chain_ledger.c
+++ b/modules/net/dap_chain_ledger.c
@@ -4188,13 +4188,14 @@ static int s_tx_cache_check(dap_ledger_t *a_ledger,
                 debug_if(s_debug_more, L_WARNING, "Verificator check error for voting item");
                 l_err_num = DAP_LEDGER_TX_CHECK_NO_VERIFICATOR_SET;
             }
-            // if (a_tag) 
+            // if (a_tag)
             //     a_tag->uint64 = DAP_CHAIN_TX_TAG_ACTION_VOTING;
-            if (a_action) 
+            if (a_action)
                *a_action = DAP_CHAIN_TX_TAG_ACTION_VOTING;
         } else if ( dap_chain_datum_tx_item_get(a_tx, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL) ) {
            if (s_voting_callbacks.voting_callback) {
-               if ((l_err_num = s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, a_tx_hash, false))) {
+               if (!s_check_hal(a_ledger, a_tx_hash) &&
+                       (l_err_num = s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, a_tx_hash, false))) {
                    debug_if(s_debug_more, L_WARNING, "Verificator check error %d for vote", l_err_num);
                    l_err_num = DAP_LEDGER_TX_CHECK_VERIFICATOR_CHECK_FAILURE;
                }
@@ -4202,8 +4203,6 @@ static int s_tx_cache_check(dap_ledger_t *a_ledger,
                debug_if(s_debug_more, L_WARNING, "Verificator check error for vote item");
                l_err_num = DAP_LEDGER_TX_CHECK_NO_VERIFICATOR_SET;
            }
-        //    if (a_tag) 
-        //        a_tag->uint64 = DAP_CHAIN_TX_TAG_ACTION_VOTE;
            if (a_action) 
                *a_action = DAP_CHAIN_TX_TAG_ACTION_VOTE;
         }
@@ -4614,7 +4613,8 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
         else if (l_action == DAP_CHAIN_TX_TAG_ACTION_VOTE)
             l_err_num = s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, a_tx_hash, true);
     }
-    assert(!l_err_num);
+    if (!s_check_hal(a_ledger, a_tx_hash))
+        assert(!l_err_num);
 
     // add transaction to the cache list
     dap_ledger_tx_item_t *l_tx_item = DAP_NEW_Z_SIZE(dap_ledger_tx_item_t, sizeof(dap_ledger_tx_item_t) + l_outs_count * sizeof(dap_chain_hash_fast_t));
diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index 3e057d8856..d962667961 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -398,7 +398,8 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
                                                l_old_vote ? &l_pkey_hash : NULL)) {
             log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx,
                                         dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash));
-            return -20;
+            log_it(L_ATT, "Datum hash for HAL posssible: %s", dap_hash_fast_to_str_static(a_tx_hash));
+            //return -20;
         }
         if (SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) {
             log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
@@ -426,7 +427,8 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
                 l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
             return -16;
         if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, l_pkey_sign))
-            return -17;
+            log_it(L_ATT, "Datum hash for HAL: %s", dap_hash_fast_to_str_static(a_tx_hash));
+            //return -17;
         if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx,
                                                   l_old_vote ? &l_pkey_hash : NULL))
             return -15;
@@ -1078,47 +1080,24 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
     return 0;
 }
 
-static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash,
-                                              dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash)
+static int s_tx_is_spent(dap_ledger_t *a_ledger, dap_hash_fast_t *a_tx_hash, dap_hash_fast_t *a_voting_hash,
+                         dap_hash_fast_t *a_pkey_hash, dap_chain_net_votings_t *a_voting, dap_time_t a_voting_ts)
 {
-    int l_coin_is_spent = 0;
-
-    dap_chain_net_votings_t *l_voting = NULL;
-    pthread_rwlock_wrlock(&s_votings_rwlock);
-    HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting);
-    pthread_rwlock_unlock(&s_votings_rwlock);
-    if (!l_voting) {
-        log_it(L_ERROR, "Can't find voting %s", dap_hash_fast_to_str_static(&a_voting_hash));
-        return -1;
-    }
-    const char *l_token_ticker = l_voting->voting_params.token_ticker;
-
-    dap_ledger_t *l_ledger = a_net->pub.ledger;
-    dap_chain_datum_tx_t *l_voting_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_voting_hash);
-    if (!l_voting_tx) {
-        log_it(L_ERROR, "Can't find voting tx %s", dap_hash_fast_to_str_static(&a_voting_hash));
-        return -2;
-    }
-    dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_tx_prev_hash);
+    dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_ledger, a_tx_hash);
     if (!l_tx) {
-        log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(&a_tx_prev_hash));
+        log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(a_tx_hash));
         return -3;
     }
 
-    if (l_tx->header.ts_created < l_voting_tx->header.ts_created){
+    if (l_tx->header.ts_created < a_voting_ts)
         return 0;
-    }
-
-    if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, a_tx_prev_hash, a_out_idx, a_pkey_hash) != 0){
-        return 1;
-    }
 
     dap_chain_tx_vote_t *l_vote = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL);
-    if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)) {
-        for (dap_list_t *it = l_voting->votes; it; it = it->next) {
+    if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting->voting_hash)) {
+        for (dap_list_t *it = a_voting->votes; it; it = it->next) {
             dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data;
-            if (dap_hash_fast_compare(&l_vote->vote_hash, &a_tx_prev_hash)) {
-                if (l_voting->voting_params.vote_changing_allowed &&
+            if (dap_hash_fast_compare(&l_vote->vote_hash, a_tx_hash)) {
+                if (a_voting->voting_params.vote_changing_allowed &&
                         !dap_hash_fast_is_blank(a_pkey_hash) &&
                         dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash))
                     break;  // it's vote changing, allow it
@@ -1127,103 +1106,85 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
         }
     }
 
-    dap_list_t *l_ins_list_temp = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
-    dap_list_t *l_cond_ins_list = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_COND, NULL);
-    if (!l_ins_list_temp && !l_cond_ins_list) // it's emisssion or reward TX, not marked yet
+    dap_list_t *l_ins_list = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
+    l_ins_list = dap_list_concat(l_ins_list, dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_COND, NULL));
+    if (!l_ins_list) // it's emisssion or reward TX, not marked yet
         return 0;
 
-    dap_list_t *l_ins_list = dap_list_concat(l_ins_list_temp, l_cond_ins_list);
-    dap_list_t *l_tx_list = dap_list_append(NULL, l_ins_list); // "stack" for saving txs on up level
-    dap_list_t *l_tx_temp = dap_list_last(l_tx_list);
-
-    while(l_tx_temp && !l_coin_is_spent){
-        if (l_tx_temp->data == NULL){
-            l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp);
-            l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL;
-            continue;
+    dap_hash_fast_t l_prev_hash = {};
+    for (dap_list_t *it = l_ins_list; it; it = it->next) {
+        uint32_t l_prev_idx = -1;
+        if (*(byte_t *)it->data == TX_ITEM_TYPE_IN_COND) {
+            dap_chain_tx_in_cond_t *in = it->data;
+            l_prev_hash = in->header.tx_prev_hash;
+            l_prev_idx = in->header.tx_out_prev_idx;
+        } else {
+            dap_chain_tx_in_t *in = it->data;
+            l_prev_hash = in->header.tx_prev_hash;
+            l_prev_idx = in->header.tx_out_prev_idx;
         }
-        dap_list_t *l_ins_list = (dap_list_t*)l_tx_temp->data;
-        dap_chain_tx_in_t* l_temp_in = (dap_chain_tx_in_t*)l_ins_list->data;
-        dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(l_ledger, &l_temp_in->header.tx_prev_hash);
+        dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, &l_prev_hash);
 
         const char* l_tx_token = NULL;
-        dap_chain_tx_out_t *l_prev_out_union = (dap_chain_tx_out_t*)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_temp_in->header.tx_out_prev_idx);
-        if (!l_prev_out_union){
-            l_tx_temp->data = dap_list_remove(l_tx_temp->data, l_temp_in);
-            if (l_tx_temp->data == NULL){
-                l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp);
-                l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL;
-            }
-            continue;
-        }
-
-        switch (l_prev_out_union->header.type) {
+        byte_t *l_prev_out_union = dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev, l_prev_idx);
+        switch (*l_prev_out_union) {
         case TX_ITEM_TYPE_OUT:{
-            l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_temp_in->header.tx_prev_hash);
+            dap_chain_tx_out_t *l_out = (dap_chain_tx_out_t *)l_prev_out_union;
+            l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(a_ledger, &l_prev_hash);
         }break;
         case TX_ITEM_TYPE_OUT_EXT:{
-            dap_chain_tx_out_ext_t *l_temp_out = (dap_chain_tx_out_ext_t *)l_prev_out_union;
-            l_tx_token = l_temp_out->token;
+            dap_chain_tx_out_ext_t *l_out = (dap_chain_tx_out_ext_t *)l_prev_out_union;
+            l_tx_token = l_out->token;
         }break;
         case TX_ITEM_TYPE_OUT_COND:{
-            dap_chain_tx_out_cond_t *l_temp_out = (dap_chain_tx_out_cond_t *)l_prev_out_union;
-            if (l_temp_out->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) {
-                l_tx_token = a_net->pub.native_ticker;
+            dap_chain_tx_out_cond_t *l_out = (dap_chain_tx_out_cond_t *)l_prev_out_union;
+            if (l_out->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) {
+                l_tx_token = a_ledger->net->pub.native_ticker;
                 break;
             }
-            if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, l_temp_in->header.tx_prev_hash,
-                                                      l_temp_in->header.tx_out_prev_idx, a_pkey_hash) != 0) {
-                l_coin_is_spent = 1;
-                continue;
+            if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, *a_voting_hash, l_prev_hash, l_prev_idx, a_pkey_hash) != 0) {
+                dap_list_free(l_ins_list);
+                return 1;
             }
-            l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_temp_in->header.tx_prev_hash);
+            l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(a_ledger, &l_prev_hash);
         }
         default:
             break;
         }
-
-        if (l_tx_prev_temp->header.ts_created < l_voting_tx->header.ts_created ||
-            dap_strcmp(l_tx_token, l_token_ticker)){
-            l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in);
-            if (l_tx_temp->data == NULL){
-                l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp);
-                l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL;
-            }
+        if (dap_strcmp(l_tx_token, a_voting->voting_params.token_ticker))
             continue;
-        }
+    }
 
-        dap_chain_tx_vote_t *l_vote = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(l_tx_prev_temp, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL);
-        if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)) {
-            for (dap_list_t *it = l_voting->votes; it; it = it->next) {
-                dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data;
-                if (dap_hash_fast_compare(&l_vote->vote_hash, &l_temp_in->header.tx_prev_hash)) {
-                    if (l_voting->voting_params.vote_changing_allowed &&
-                            !dap_hash_fast_is_blank(a_pkey_hash) &&
-                            dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash))
-                        break;  // it's vote changing, allow it
-                    l_coin_is_spent = 1;
-                    break;
-                }
-            }
-        }
+    return s_tx_is_spent(a_ledger, &l_prev_hash, a_voting_hash, a_pkey_hash, a_voting, a_voting_ts);
+}
+
+
+static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash,
+                                              dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash)
+{
+    int l_coin_is_spent = 0;
 
-        l_ins_list = dap_chain_datum_tx_items_get(l_tx_prev_temp, TX_ITEM_TYPE_IN, NULL);
-        l_tx_list = dap_list_append(l_tx_list, l_ins_list);
-        l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in);
-        l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL;
+    dap_chain_net_votings_t *l_voting = NULL;
+    pthread_rwlock_wrlock(&s_votings_rwlock);
+    HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting);
+    pthread_rwlock_unlock(&s_votings_rwlock);
+    if (!l_voting) {
+        log_it(L_ERROR, "Can't find voting %s", dap_hash_fast_to_str_static(&a_voting_hash));
+        return -1;
     }
 
-    if(l_tx_list){
-        l_tx_temp = l_tx_list;
-        while(l_tx_temp){
-            if (l_tx_temp->data)
-                dap_list_free((dap_list_t*)l_tx_temp->data);
-            l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp);
-            l_tx_temp = dap_list_first(l_tx_list);
-        }
+    dap_ledger_t *l_ledger = a_net->pub.ledger;
+    dap_chain_datum_tx_t *l_voting_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_voting_hash);
+    if (!l_voting_tx) {
+        log_it(L_ERROR, "Can't find voting tx %s", dap_hash_fast_to_str_static(&a_voting_hash));
+        return -2;
     }
 
-    return l_coin_is_spent;
+    if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, a_tx_prev_hash, a_out_idx, a_pkey_hash) != 0)
+        return 1;
+
+    return s_tx_is_spent(l_ledger, &a_tx_prev_hash, &a_voting_hash, a_pkey_hash, l_voting, l_voting_tx->header.ts_created);
+
 }
 
 static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash,
-- 
GitLab


From 730a53de647f429e3a4996734308297dd6337b69 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Fri, 7 Mar 2025 18:15:10 +0700
Subject: [PATCH 13/53] [*] Last bugs fixes

---
 modules/net/dap_chain_node_cli_cmd.c          | 19 +++++++++----------
 .../service/voting/dap_chain_net_srv_voting.c |  6 ++----
 2 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 4d23819b9a..fa3c41d20b 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -1799,10 +1799,10 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE;
                     return DAP_CHAIN_NODE_CLI_COM_TX_WALLET_PARAM_ERR;
             }
             json_object * json_obj_wall = json_object_new_object();
-            const char *l_cond_str = NULL, *l_value_str = NULL;
+            const char *l_value_str = NULL;
             uint256_t l_value_datoshi = uint256_0, l_value_sum = uint256_0;
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cond", &l_cond_str);
-            if (!l_cond_str) {
+            bool l_cond_outs = dap_cli_server_cmd_check_option(a_argv, l_arg_index, a_argc, "-cond") != -1;
+            if (!l_cond_outs) {
                 dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str);
                 if (l_value_str) {
                     l_value_datoshi = dap_chain_balance_scan(l_value_str);
@@ -1816,12 +1816,11 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE;
             }
 
             dap_list_t *l_outs_list = NULL;
-
-            if (l_value_str) {
-                if (dap_chain_wallet_cache_tx_find_outs_with_val(l_net, l_token_tiker, l_addr, &l_outs_list, l_value_datoshi, &l_value_sum))
-                    l_outs_list = dap_ledger_get_list_tx_outs_with_val(l_net->pub.ledger, l_token_tiker, l_addr, l_value_datoshi, &l_value_sum);
-            } else if (l_cond_str) {
+            if (l_cond_outs)
                 l_outs_list = dap_ledger_get_list_tx_cond_outs(l_net->pub.ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_tiker, l_addr);
+            else if (l_value_str) {
+                if (dap_chain_wallet_cache_tx_find_outs_with_val(l_net, l_token_tiker, l_addr, &l_outs_list, l_value_datoshi, &l_value_sum))
+                    l_outs_list = dap_ledger_get_list_tx_outs_with_val(l_net->pub.ledger, l_token_tiker, l_addr, l_value_datoshi, &l_value_sum); 
             } else {
                 if (dap_chain_wallet_cache_tx_find_outs(l_net, l_token_tiker, l_addr, &l_outs_list, &l_value_sum))
                     l_outs_list = dap_ledger_get_list_tx_outs(l_net->pub.ledger, l_token_tiker, l_addr, &l_value_sum);
@@ -1836,13 +1835,13 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE;
                     return json_object_put(json_arr_out), DAP_CHAIN_NODE_CLI_COM_TX_WALLET_MEMORY_ERR;
                 dap_chain_tx_used_out_item_t *l_item = l_temp->data;
                 const char *l_out_value_coins_str, *l_out_value_str = dap_uint256_to_char(l_item->value, &l_out_value_coins_str);
-                json_object_object_add(json_obj_item,"item_type", json_object_new_string(l_cond_str ? "unspent_cond_out" : "unspent_out"));
+                json_object_object_add(json_obj_item,"item_type", json_object_new_string(l_cond_outs ? "unspent_cond_out" : "unspent_out"));
                 json_object_object_add(json_obj_item,"value_coins", json_object_new_string(l_out_value_coins_str));
                 json_object_object_add(json_obj_item,"value_datosi", json_object_new_string(l_out_value_str));
                 json_object_object_add(json_obj_item,"prev_hash", json_object_new_string(dap_hash_fast_to_str_static(&l_item->tx_hash_fast)));
                 json_object_object_add(json_obj_item,"out_prev_idx", json_object_new_int64(l_item->num_idx_out));
                 json_object_array_add(l_json_outs_arr, json_obj_item);
-                if (l_cond_str)
+                if (l_cond_outs)
                     SUM_256_256(l_value_sum, l_item->value, &l_value_sum);
             }
             dap_list_free_full(l_outs_list, NULL);
diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index d962667961..f07f8e0f99 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -398,8 +398,7 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
                                                l_old_vote ? &l_pkey_hash : NULL)) {
             log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx,
                                         dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash));
-            log_it(L_ATT, "Datum hash for HAL posssible: %s", dap_hash_fast_to_str_static(a_tx_hash));
-            //return -20;
+            return -20;
         }
         if (SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) {
             log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash));
@@ -427,8 +426,7 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a
                 l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
             return -16;
         if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, l_pkey_sign))
-            log_it(L_ATT, "Datum hash for HAL: %s", dap_hash_fast_to_str_static(a_tx_hash));
-            //return -17;
+            return -17;
         if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx,
                                                   l_old_vote ? &l_pkey_hash : NULL))
             return -15;
-- 
GitLab


From 81136f326e01a7808a5a59ccbd9d89fbf6e0ed63 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Fri, 14 Mar 2025 12:42:39 +0700
Subject: [PATCH 14/53] [*] tx to json

---
 dap-sdk                                       |  2 +-
 modules/net/dap_chain_net_tx.c                | 30 +++++++++++++------
 .../service/voting/dap_chain_net_srv_voting.c |  4 +--
 .../voting/include/dap_chain_net_srv_voting.h |  2 +-
 4 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index d9b03ffb93..a7b6da64ee 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit d9b03ffb93d4003cb1a33c6470612a7f88ad6005
+Subproject commit a7b6da64ee24a3aba64dcbbd5f3f356069d853ad
diff --git a/modules/net/dap_chain_net_tx.c b/modules/net/dap_chain_net_tx.c
index addcb27c56..2882d01ccd 100644
--- a/modules/net/dap_chain_net_tx.c
+++ b/modules/net/dap_chain_net_tx.c
@@ -1551,9 +1551,13 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json
             json_object_object_add(json_obj_item, "sig_b64",    json_object_new_string(l_sign_b64));
         } break;
         case TX_ITEM_TYPE_TSD: {
-            json_object_object_add(json_obj_item,"type", json_object_new_string("data"));
-            json_object_object_add(json_obj_item,"type", json_object_new_uint64(((dap_chain_tx_tsd_t*)item)->header.type));
-            json_object_object_add(json_obj_item,"size", json_object_new_uint64(((dap_chain_tx_tsd_t*)item)->header.size));            
+            json_object_object_add(json_obj_item,"type", json_object_new_string("TX_ITEM_TYPE_TSD"));
+            json_object_object_add(json_obj_item,"type_tsd", json_object_new_string("data"));
+            json_object_object_add(json_obj_item,"size", json_object_new_uint64(((dap_chain_tx_tsd_t*)item)->header.size));
+            char *l_tsd_str = DAP_NEW_Z_SIZE(char, ((dap_chain_tx_tsd_t*)item)->header.size + 1);
+            memcpy(l_tsd_str, ((dap_chain_tx_tsd_t*)item)->tsd, ((dap_chain_tx_tsd_t*)item)->header.size);
+            json_object_object_add(json_obj_item, "data", json_object_new_string(l_tsd_str));
+            DAP_DEL_Z(l_tsd_str);
         } break;
         case TX_ITEM_TYPE_IN_COND:
             json_object_object_add(json_obj_item,"type", json_object_new_string("in_cond"));
@@ -1602,15 +1606,15 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json
                     const char *l_rate_str, *l_tmp_str =
                         dap_uint256_to_char( (((dap_chain_tx_out_cond_t*)item)->subtype.srv_xchange.rate), &l_rate_str );
                     sprintf(l_tmp_buff,"0x%016"DAP_UINT64_FORMAT_x"",((dap_chain_tx_out_cond_t*)item)->subtype.srv_xchange.buy_net_id.uint64);
-                    json_object_object_add(json_obj_item,"net_id", json_object_new_string(l_tmp_buff));
+                    json_object_object_add(json_obj_item,"net", json_object_new_string(l_tmp_buff));
                     json_object_object_add(json_obj_item,"token", json_object_new_string(((dap_chain_tx_out_cond_t*)item)->subtype.srv_xchange.buy_token));
                     json_object_object_add(json_obj_item,"rate", json_object_new_string(l_rate_str));
                     json_object_object_add(json_obj_item,"subtype", json_object_new_string("srv_xchange"));
                 } break;
                 case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK: {
                     dap_time_t l_ts_unlock = ((dap_chain_tx_out_cond_t*)item)->subtype.srv_stake_lock.time_unlock;
-                    dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_ts_unlock);
-                    json_object_object_add(json_obj_item,"time_unlock", json_object_new_string(l_tmp_buf));
+                    const char * l_date_str = dap_time_to_str_simplified(l_ts_unlock);
+                    json_object_object_add(json_obj_item,"time_staking", json_object_new_string(l_date_str));
                     json_object_object_add(json_obj_item,"subtype", json_object_new_string("srv_stake_lock"));
                 } break;
                 default: break;
@@ -1618,11 +1622,18 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json
         } break;
         case TX_ITEM_TYPE_OUT_EXT: {
             const char *l_coins_str, *l_value_str = dap_uint256_to_char( ((dap_chain_tx_out_ext_t*)item)->header.value, &l_coins_str );
-            json_object_object_add(json_obj_item,"type", json_object_new_string("out_ext"));
+            json_object_object_add(json_obj_item,"type", json_object_new_string("out"));
             json_object_object_add(json_obj_item,"addr", json_object_new_string(dap_chain_addr_to_str_static(&((dap_chain_tx_out_ext_t*)item)->addr)));
             json_object_object_add(json_obj_item,"token", json_object_new_string(((dap_chain_tx_out_ext_t*)item)->token));
             json_object_object_add(json_obj_item,"value", json_object_new_string(l_value_str));
             
+        } break;
+        case TX_ITEM_TYPE_IN_EMS: {
+            json_object_object_add(json_obj_item,"type", json_object_new_string("in_ems"));
+            json_object_object_add(json_obj_item,"chain_id", json_object_new_uint64(((dap_chain_tx_in_ems_t*)item)->header.token_emission_chain_id.uint64));
+            json_object_object_add(json_obj_item,"token", json_object_new_string(((dap_chain_tx_in_ems_t*)item)->header.ticker));
+            json_object_object_add(json_obj_item,"token_ems_hash", json_object_new_string( dap_hash_fast_to_str_static(&((dap_chain_tx_in_ems_t*)item)->header.token_emission_hash)));
+            
         } break;
         case TX_ITEM_TYPE_VOTING:{
             size_t l_tsd_size = 0;
@@ -1632,15 +1643,16 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json
             dap_chain_datum_tx_voting_params_t *l_voting_params = dap_chain_voting_parse_tsd(a_tx);
             json_object_object_add(json_obj_item,"type", json_object_new_string("voting"));
             json_object_object_add(json_obj_item,"voting_question", json_object_new_string(l_voting_params->voting_question));
-            json_object_object_add(json_obj_item,"answer_options", json_object_new_string(""));
+            json_object *l_json_array = json_object_new_array();
             
             dap_list_t *l_temp = l_voting_params->answers_list;
             uint8_t l_index = 0;
             while (l_temp) {
-                json_object_object_add(json_obj_item, dap_itoa(l_index), json_object_new_string((char *)l_temp->data));
+                json_object_array_add(l_json_array, json_object_new_string((char *)l_temp->data));
                 l_index++;
                 l_temp = l_temp->next;
             }
+            json_object_object_add(json_obj_item, "answer_options", l_json_array);
             if (l_voting_params->voting_expire) {
                 dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_voting_params->voting_expire);
                 json_object_object_add(json_obj_item,"Voting expire", json_object_new_string(l_tmp_buf));                
diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index c74cf6fd33..37f0ba80f4 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -532,7 +532,7 @@ static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledge
     return true;
 }
 
-static dap_list_t* s_get_options_list_from_str(const char* a_str)
+dap_list_t* dap_get_options_list_from_str(const char* a_str)
 {
     dap_list_t* l_ret = NULL;
     char * l_options_str_dup = strdup(a_str);
@@ -640,7 +640,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
             return -DAP_CHAIN_NET_VOTE_CREATE_OPTION_PARAM_MISSING;
         }
         // Parse options list
-        l_options_list = s_get_options_list_from_str(l_options_list_str);
+        l_options_list = dap_get_options_list_from_str(l_options_list_str);
         if(!l_options_list || dap_list_length(l_options_list) < 2){
             dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR, "Number of options must be 2 or greater.");
             return -DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR;
diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h
index 4bd1f71694..36c681188d 100644
--- a/modules/service/voting/include/dap_chain_net_srv_voting.h
+++ b/modules/service/voting/include/dap_chain_net_srv_voting.h
@@ -152,4 +152,4 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal
 dap_list_t *dap_chain_net_vote_list(dap_chain_net_t *a_net);
 dap_chain_net_vote_info_t *dap_chain_net_vote_extract_info(dap_chain_net_t *a_net, dap_hash_fast_t *a_vote_hash);
 void dap_chain_net_vote_info_free(dap_chain_net_vote_info_t *a_info);
-
+dap_list_t* dap_get_options_list_from_str(const char* a_str);
-- 
GitLab


From aa61ae0928ab0d8114916a9739cfaa2095d98aea Mon Sep 17 00:00:00 2001
From: "roman.padenkov" <roman.padenkov@demlabs.net>
Date: Wed, 19 Mar 2025 22:00:10 +0700
Subject: [PATCH 15/53] ...

---
 CMakeLists.txt                         | 7 +++++++
 modules/CMakeLists.txt                 | 5 +++++
 modules/net/include/dap_chain_net_tx.h | 6 +-----
 3 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index bfb08ee2e4..22001f9388 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -89,6 +89,13 @@ if (CELLFRAME_MODULES MATCHES "network")
         dap_stream dap_stream_ch dap_client dap_cli_server dap_stream_ch_chain_net dap_chain_net dap_chain_net_srv dap_chain_mempool)
 endif()
 
+# Compose
+if (CELLFRAME_MODULES MATCHES "compose")
+    message("[+] Module 'compose'")
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_compose dap_json_rpc dap_enc_server dap_notify_srv dap_http_server dap_session
+        dap_stream dap_stream_ch dap_client dap_cli_server dap_stream_ch_chain_net dap_chain_net dap_chain_net_srv dap_chain_mempool)
+endif()
+
 # Chain net services
 if (CELLFRAME_MODULES MATCHES "srv-" )
     set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_stream_ch_chain_net_srv)
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
index fef7978aab..de7713fd24 100644
--- a/modules/CMakeLists.txt
+++ b/modules/CMakeLists.txt
@@ -108,3 +108,8 @@ endif()
 if (CELLFRAME_MODULES MATCHES "srv-emit-delegate")
     add_subdirectory(service/emit-delegate)
 endif()
+
+# compose service
+if (CELLFRAME_MODULES MATCHES "compose")
+    add_subdirectory(compose)
+endif()
diff --git a/modules/net/include/dap_chain_net_tx.h b/modules/net/include/dap_chain_net_tx.h
index 0447fcb165..fe57215d18 100644
--- a/modules/net/include/dap_chain_net_tx.h
+++ b/modules/net/include/dap_chain_net_tx.h
@@ -98,10 +98,6 @@ dap_list_t * dap_chain_net_get_tx_cond_all_by_srv_uid(dap_chain_net_t * a_net, c
 dap_list_t * dap_chain_net_get_tx_cond_all_for_addr(dap_chain_net_t * a_net, dap_chain_addr_t * a_addr, dap_chain_net_srv_uid_t a_srv_uid);
 
 dap_list_t * dap_chain_net_get_tx_all_from_tx(dap_chain_net_t * a_net, dap_hash_fast_t * l_tx_hash);
-
-
-
-
 dap_chain_datum_tx_spends_items_t * dap_chain_net_get_tx_cond_all_with_spends_by_srv_uid(dap_chain_net_t * a_net, const dap_chain_net_srv_uid_t a_srv_uid,
                                                       const dap_time_t a_time_from, const dap_time_t a_time_to,
                                                      const dap_chain_net_tx_search_type_t a_search_type);
@@ -137,4 +133,4 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json
 
 #ifdef __cplusplus
 }
-#endif
\ No newline at end of file
+#endif
-- 
GitLab


From 27d4eff9b8d4d692784feaa75d683737ac132035 Mon Sep 17 00:00:00 2001
From: "roman.padenkov" <roman.padenkov@demlabs.net>
Date: Thu, 20 Mar 2025 13:10:49 +0700
Subject: [PATCH 16/53] ...

---
 dap-sdk                                       |  2 +-
 modules/compose/CMakeLists.txt                | 21 +++++++++++++++++++
 modules/compose/dap_chain_tx_compose.c        |  1 +
 .../compose/include/dap_chain_tx_compose.h    |  1 +
 4 files changed, 24 insertions(+), 1 deletion(-)
 create mode 100644 modules/compose/CMakeLists.txt
 create mode 100644 modules/compose/dap_chain_tx_compose.c
 create mode 100644 modules/compose/include/dap_chain_tx_compose.h

diff --git a/dap-sdk b/dap-sdk
index ff8478aa04..dafe5ac222 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit ff8478aa04fa94540016fee0038db4b63965d0d1
+Subproject commit dafe5ac222f390aed78fc60528d04d2905555361
diff --git a/modules/compose/CMakeLists.txt b/modules/compose/CMakeLists.txt
new file mode 100644
index 0000000000..e03c3e95bb
--- /dev/null
+++ b/modules/compose/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.10)
+project (dap_compose)
+  
+file(GLOB DAP_CHAIN_COMPOSE_SRCS  *.c)
+file(GLOB DAP_CHAIN_COMPOSE_HEADERS include/*.h)
+
+add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_COMPOSE_SRCS} ${DAP_CHAIN_COMPOSE_HEADERS})
+
+
+target_include_directories(${PROJECT_NAME} PUBLIC include/ )
+target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../dap-sdk/3rdparty/json-c)
+
+
+if (INSTALL_SDK)
+set_target_properties(${PROJECT_NAME}  PROPERTIES PUBLIC_HEADER "${DAP_CHAIN_COMPOSE_HEADERS}")
+INSTALL(TARGETS ${PROJECT_NAME} 
+        LIBRARY DESTINATION lib/modules/compose/
+        ARCHIVE DESTINATION lib/modules/compose/
+        PUBLIC_HEADER DESTINATION include/modules/compose/
+)
+endif()
diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -0,0 +1 @@
+
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -0,0 +1 @@
+
-- 
GitLab


From b6b6b884db866e26d8c2de147d4388804874ae72 Mon Sep 17 00:00:00 2001
From: "roman.padenkov" <roman.padenkov@demlabs.net>
Date: Thu, 20 Mar 2025 17:05:33 +0700
Subject: [PATCH 17/53] ...

---
 modules/compose/CMakeLists.txt                |    4 +-
 modules/compose/dap_chain_tx_compose.c        | 2350 +++++++++++++++++
 .../compose/include/dap_chain_tx_compose.h    |   96 +
 3 files changed, 2449 insertions(+), 1 deletion(-)

diff --git a/modules/compose/CMakeLists.txt b/modules/compose/CMakeLists.txt
index e03c3e95bb..2943e6fb03 100644
--- a/modules/compose/CMakeLists.txt
+++ b/modules/compose/CMakeLists.txt
@@ -6,7 +6,9 @@ file(GLOB DAP_CHAIN_COMPOSE_HEADERS include/*.h)
 
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_COMPOSE_SRCS} ${DAP_CHAIN_COMPOSE_HEADERS})
 
-
+target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_client dap_io dap_notify_srv dap_cli_server dap_chain dap_chain_wallet
+                                                dap_chain_net_srv dap_chain_net_srv_voting dap_chain_mempool dap_global_db dap_chain_net_srv_xchange dap_chain_cs_none
+                                                dap_stream_ch_chain_net dap_chain_cs_esbocs dap_json_rpc )
 target_include_directories(${PROJECT_NAME} PUBLIC include/ )
 target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../dap-sdk/3rdparty/json-c)
 
diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 8b13789179..f86c15f7c3 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -1 +1,2351 @@
+/*
+ * Authors:
+ * Roman Padenkov <roman.padenkov@demlabs.net>
+ * Olzhas Zharasbaev <oljas.jarasbaev@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://github.com/demlabsinc
+ * Copyright  (c) 2025-2026
+ * All rights reserved.
+
+ This file is part of DAP (Distributed Applications Platform) the open source project
+
+ DAP (Distributed Applications Platform) 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_common.h"
+#include "dap_chain_tx_compose.h"
+#include "dap_chain_datum_tx_voting.h"
+#include "dap_chain_net_srv_stake_lock.h"
+#include "dap_chain_net_srv_voting.h"
+
+#include <curl/curl.h>
+
+
+static const char* s_get_native_ticker(const char* name) {
+    for (int i = 0; i < NET_COUNT; i++) {
+        if (strcmp(netinfo[i].name, name) == 0) {
+            return netinfo[i].native_ticker;
+        }
+    }
+    return NULL;
+}
+
+static dap_chain_net_id_t s_get_net_id(const char* name) {
+    for (int i = 0; i < NET_COUNT; i++) {
+        if (strcmp(netinfo[i].name, name) == 0) {
+            return netinfo[i].net_id;
+        }
+    }
+    dap_chain_net_id_t empty_id = {.uint64 = 0};
+    return empty_id;
+}
+
+void bad_option(){
+    printf("Usage: %s {{-w, --wallet <path_to_wallet_file> | -z, --seed <seed_phrase> -s <sign_type>} [OPTIONS] | {-c -w <wallet_name> -d <path_to_save_wallet_file> -s <sign_type> -z <seed_phrase>} | {-a {-w <path_to_wallet_file> | -z, --seed <seed_phrase> -s <sign_type>} -i 0x<net_id>}} \n\r \
+    stake_lock hold -net <net_name> -w <wallet_name> -time_staking <YYMMDD> -token <ticker> -value <value> -fee <value> -chain_id <chain_id>  [-reinvest <percentage>] \n\r \
+    stake_lock take -net <net_name> -w <wallet_name> -tx <transaction_hash> -fee <value> -chain_id <chain_id> \
+    \t\tstake_lock command doesn't support old stake command",
+
+    dap_get_appname());
+    exit(EXIT_FAILURE);
+}
+
+
+size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userdata) {
+    size_t total_size = size * nmemb;
+    char **response = (char **)userdata;
+    *response = realloc(*response, total_size + 1);
+    if (*response == NULL) {
+        fprintf(stderr, "Memory allocation failed\n");
+        return 0;
+    }
+    memcpy(*response, ptr, total_size);
+    (*response)[total_size] = '\0';
+    return total_size;
+}
+
+json_object* request_command_to_rpc_by_curl(const char * request){
+    CURL *curl;
+    CURLcode res;
+    char *response = NULL;
+
+    curl_global_init(CURL_GLOBAL_DEFAULT);
+    curl = curl_easy_init();
+    json_object * result = NULL;
+
+    if(curl) {
+        curl_easy_setopt(curl, CURLOPT_URL, RPC_NODES_URL);
+
+        struct curl_slist *headers = NULL;
+        headers = curl_slist_append(headers, "Content-Type: application/json");
+        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+
+
+        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request);
+
+        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
+        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
+
+        res = curl_easy_perform(curl);
+
+        if(res != CURLE_OK) {
+            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
+        } else {
+            json_object *json = json_tokener_parse(response);
+            if (json == NULL) {
+                fprintf(stderr, "Failed to parse JSON response\n");
+            } else {
+                if (!json_object_object_get_ex(json, "result", &result)) {
+                    fprintf(stderr, "Result field not found in JSON response\n");
+                } else {
+                    json_object_get(result);
+                }
+                json_object_put(json);
+            }
+        }
+
+        curl_easy_cleanup(curl);
+        curl_slist_free_all(headers);
+        free(response);
+    }
+
+    curl_global_cleanup();
+    return result;
+}
+
+struct options {
+    char *cmd;
+    char *subcmd[5];
+    int count_of_subcommands;
+    int (*handler) (int argc, char **argv);
+} s_opts[] = {
+{ "tx_create", {"compose"}, 1, dap_tx_create_compose },
+{ "xchange_create", {"compose"}, 1, dap_tx_create_xchange_compose },
+{ "tx_cond_create", {"compose"}, 1, dap_tx_cond_create_compose },
+{ "stake_lock", {"hold"}, 1, dap_cli_hold_compose },
+{ "stake_lock", {"take"}, 1, dap_cli_take_compose },
+{ "voting", {"create"}, 1, dap_cli_voting_compose }
+};
+/*
+int main(int argc, char **argv)
+{
+    int l_argv_start = 1, l_argvi, l_err = -2, l_ret_cmd = -1;
+    dap_set_appname("cellframe-tool-compose");
+
+    if (argc == 1){
+        bad_option();
+    }
+
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        c_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
+    } else {
+        c_wallets_path = dap_strdup(l_wallet_path);
+    }
+
+    size_t i, l_size = sizeof(s_opts) / sizeof(struct options);
+    for (i = 0; i < l_size; ++i) {
+        l_argvi = l_argv_start;
+        if (argc >= l_argvi && !strncmp(s_opts[i].cmd, argv[l_argvi], strlen (argv[l_argvi]) + 1)) {
+            l_err = 0;
+            for (int isub = 0; isub < s_opts[i].count_of_subcommands; isub++) {
+                if ( argc - 1 < ++l_argvi || strncmp(s_opts[i].subcmd[isub], argv[l_argvi], strlen(argv[l_argvi]) + 1) ) {
+                    l_err = -1;
+                    break;
+                }
+            }
+            if ( !l_err ) {
+                l_ret_cmd = s_opts[i].handler(argc, argv);
+                break;
+            }
+        }
+    }
+    switch ( l_err ) {
+    case -2:
+        printf("Command \"%s\" not found.\n", argv[1]);
+        bad_option();
+        break;
+    case -1:
+        printf("No subcommand was found for command \"%s\".\n", argv[1]);
+        bad_option();
+        break;
+    default: break;
+    }
+    return l_err ? l_err : l_ret_cmd;
+}
+*/
+int dap_tx_create_xchange_compose(int argc, char ** argv) {
+    int arg_index = 1;
+    const char *l_net_name = NULL;
+    const char *l_token_sell = NULL;
+    const char *l_token_buy = NULL;
+    const char *l_wallet_name = NULL;
+    const char *l_value_str = NULL;
+    const char *l_rate_str = NULL;
+    const char *l_fee_str = NULL;
+
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_sell", &l_token_sell);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_buy", &l_token_buy);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-rate", &l_rate_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee_str);
+
+    if (!l_net_name) {
+        printf("xchange_create requires parameter '-net'");
+        return -1;
+    }
+
+    if (!l_token_buy) {
+        printf("xchange_create requires parameter '-token_buy'");
+        return -1;
+    }
+
+    if (!l_token_sell) {
+        printf("xchange_create requires parameter '-token_sell'");
+        return -1;
+    }
+
+    if (!l_wallet_name) {
+        printf("xchange_create requires parameter '-w'");
+        return -1;
+    }
+
+    if (!l_value_str) {
+        printf("xchange_create requires parameter '-value'");
+        return -1;
+    }
+
+    if (!l_rate_str) {
+        printf("xchange_create requires parameter '-rate'");
+        return -1;
+    }
+
+    if (!l_fee_str) {
+        printf("xchange_create requires parameter '-fee'");
+        return -1;
+    }
+
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, c_wallets_path, NULL);
+    if(!l_wallet) {
+        printf("wallet %s does not exist", l_wallet_name);
+        return -1;
+    }
+
+
+    uint256_t l_value = dap_chain_balance_scan(l_value_str);
+    uint256_t l_rate = dap_chain_balance_scan(l_rate_str);
+    uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+    if (IS_ZERO_256(l_value) || IS_ZERO_256(l_rate) || IS_ZERO_256(l_fee)) {
+        printf("Invalid parameter value, rate or fee is 0, use required format 1.0e+18 ot in datoshi");
+        return -1;
+    }
+
+    dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_net_name, l_token_buy,
+                                     l_token_sell, l_value, l_rate, l_fee, l_wallet);
+    json_object *l_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_ret);
+    printf("%s", json_object_to_json_string(l_ret));
+    json_object_put(l_ret);
+    dap_chain_datum_tx_delete(l_tx);
+    return 0;
+}
+
+
+
+int dap_tx_create_compose(int argc, char ** argv) {
+    int arg_index = 1;
+    const char *addr_base58_to = NULL;
+    const char *str_tmp = NULL;
+    const char * l_from_wallet_name = NULL;
+    const char * l_wallet_fee_name = NULL;
+    const char * l_token_ticker = NULL;
+    const char * l_net_name = NULL;
+    const char * l_chain_name = NULL;
+    const char * l_emission_chain_name = NULL;
+    const char * l_tx_num_str = NULL;
+    const char *l_emission_hash_str = NULL;
+    const char *l_cert_str = NULL;
+    dap_cert_t *l_cert = NULL;
+    dap_enc_key_t *l_priv_key = NULL;
+    dap_chain_hash_fast_t l_emission_hash = {};
+    size_t l_tx_num = 0;
+    dap_chain_wallet_t * l_wallet_fee = NULL;
+
+    const char * l_hash_out_type = NULL;
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type);
+    if(!l_hash_out_type)
+        l_hash_out_type = "hex";
+    if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) {
+        printf("Invalid parameter -H, valid values: -H <hex | base58>");
+        return -1;
+    }
+
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
+    if (!l_net_name) {
+        printf("tx_create requires parameter '-net'");
+        return -1;
+    }
+
+    uint256_t *l_value = NULL;
+    uint256_t l_value_fee = {};
+    dap_chain_addr_t **l_addr_to = NULL;
+    size_t l_addr_el_count = 0;
+    size_t l_value_el_count = 0;
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-wallet_fee", &l_wallet_fee_name);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-tx_num", &l_tx_num_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str);
+
+    if(l_tx_num_str)
+        l_tx_num = strtoul(l_tx_num_str, NULL, 10);
+
+    // Validator's fee
+    if (dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) {
+        if (!str_tmp) {
+            printf("tx_create requires parameter '-fee'");
+            return -1;
+        }
+        l_value_fee = dap_chain_balance_scan(str_tmp);
+    }
+    if (IS_ZERO_256(l_value_fee) && (str_tmp && strcmp(str_tmp, "0"))) {
+        printf("tx_create requires parameter '-fee' to be valid uint256");
+        return -2;
+    }
+
+    if (!l_from_wallet_name) {
+        printf("tx_create requires parameter '-from_wallet'");
+        return -3;
+    }
+
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
+    if (!l_token_ticker) {
+        printf("tx_create requires parameter '-token'");
+        return -4;
+    }
+
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp);
+    if (!addr_base58_to) {
+        printf("tx_create requires parameter '-to_addr'");
+        return -5;
+    }
+    if (!str_tmp) {
+        printf("tx_create requires parameter '-value' to be valid uint256 value");
+        return -6;
+    }
+    l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1;
+    l_value_el_count = dap_str_symbol_count(str_tmp, ',') + 1;
+
+    if (l_addr_el_count != l_value_el_count) {
+        printf("num of '-to_addr' and '-value' should be equal");
+        return -5;
+    }
+
+    l_value = DAP_NEW_Z_COUNT(uint256_t, l_value_el_count);
+    if (!l_value) {
+        printf("Can't allocate memory");
+        return -6;
+    }
+    char **l_value_array = dap_strsplit(str_tmp, ",", l_value_el_count);
+    if (!l_value_array) {
+        DAP_DELETE(l_value);
+        printf("Can't read '-to_addr' arg");
+        return -7;
+    }
+    for (size_t i = 0; i < l_value_el_count; ++i) {
+        l_value[i] = dap_chain_balance_scan(l_value_array[i]);
+        if(IS_ZERO_256(l_value[i])) {
+            DAP_DEL_MULTY(l_value_array, l_value);
+            printf("tx_create requires parameter '-value' to be valid uint256 value");
+            return -8;
+        }
+    }
+    DAP_DELETE(l_value_array);
+
+    l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count);
+    if (!l_addr_to) {
+        printf("Can't allocate memory");
+        DAP_DELETE(l_value);
+        return -9;
+    }
+    char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count);
+    if (!l_addr_base58_to_array) {
+        DAP_DEL_MULTY(l_addr_to, l_value);
+        printf("Can't read '-to_addr' arg");
+        return -10;
+    }
+    for (size_t i = 0; i < l_addr_el_count; ++i) {
+        l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]);
+        if(!l_addr_to[i]) {
+            for (size_t j = 0; j < i; ++j) {
+                DAP_DELETE(l_addr_to[j]);
+            }
+            DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value);
+            printf("destination address is invalid");
+            return -11;
+        }
+    }
+    DAP_DELETE(l_addr_base58_to_array);
+    
+    dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, c_wallets_path, NULL);
+    if(!l_wallet) {
+        printf("Can't open wallet %s", l_from_wallet_name);
+        return -12;
+    }
+
+
+    dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name));
+    for (size_t i = 0; i < l_addr_el_count; ++i) {
+        if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) {
+            printf("The transaction cannot be directed to the same address as the source.");
+            for (size_t j = 0; j < l_addr_el_count; ++j) {
+                    DAP_DELETE(l_addr_to[j]);
+            }
+            DAP_DEL_MULTY(l_addr_to, l_value);
+            return -13;
+        }
+    }
+
+
+
+    l_priv_key = dap_chain_wallet_get_key(l_wallet, 0);
+    dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count);
+
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
+    dap_chain_datum_tx_delete(l_tx);
+    DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from);
+    return 0;
+}
+
+bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee) {
+    char data[512];
+    snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name);
+    json_object *l_json_get_fee = request_command_to_rpc_by_curl(data);
+    if (!l_json_get_fee) {
+        return false;
+    }
+
+    json_object *l_first_result = json_object_array_get_idx(l_json_get_fee, 0);
+    if (!l_first_result || !json_object_is_type(l_first_result, json_type_object)) {
+        json_object_put(l_json_get_fee);
+        return false;
+    }
+
+    json_object *l_fees = NULL;
+    if (!json_object_object_get_ex(l_first_result, "fees", &l_fees) || 
+        !json_object_is_type(l_fees, json_type_object)) {
+        json_object_put(l_json_get_fee);
+        return false;
+    }
+
+    json_object *l_network = NULL;
+    if (!json_object_object_get_ex(l_fees, "network", &l_network) || 
+        !json_object_is_type(l_network, json_type_object)) {
+        json_object_put(l_json_get_fee);
+        return false;
+    }
+
+    json_object *l_balance = NULL;
+    if (!json_object_object_get_ex(l_network, "balance", &l_balance) || 
+        !json_object_is_type(l_balance, json_type_string)) {
+        json_object_put(l_json_get_fee);
+        return false;
+    }
+    *a_net_fee = dap_chain_balance_scan(json_object_get_string(l_balance));
+
+    json_object *l_addr = NULL;
+    if (!json_object_object_get_ex(l_network, "addr", &l_addr) || 
+        !json_object_is_type(l_addr, json_type_string)) {
+        json_object_put(l_json_get_fee);
+        return false;
+    }
+    *l_addr_fee = dap_chain_addr_from_str(json_object_get_string(l_addr));
+
+    json_object_put(l_json_get_fee);
+    return true;
+}
+
+bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count) {
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
+            dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name);
+    json_object *l_json_outs = request_command_to_rpc_by_curl(data);
+    if (!l_json_outs) {
+        return false;
+    }
+
+    if (!json_object_is_type(l_json_outs, json_type_array)) {
+        json_object_put(l_json_outs);
+        return false;
+    }
+
+    if (json_object_array_length(l_json_outs) == 0) {
+        json_object_put(l_json_outs);
+        return false;
+    }
+
+    json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0);
+    if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) {
+        json_object_put(l_json_outs);
+        return false;
+    }
+
+    json_object *l_first_item = json_object_array_get_idx(l_first_array, 0);
+    if (!l_first_item) {
+        json_object_put(l_json_outs);
+        return false;
+    }
+
+    if (!json_object_object_get_ex(l_first_item, "outs", l_outs) ||
+        !json_object_is_type(*l_outs, json_type_array)) {
+        json_object_put(l_json_outs);
+        return false;
+    }
+
+    *l_outputs_count = json_object_array_length(*l_outs);
+    json_object_get(*l_outs);
+    json_object_put(l_json_outs); // Clean up the JSON object
+    return true;
+}
+
+
+dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
+        const char* a_token_ticker,
+        uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num)
+{
+    if (!a_addr_from || !a_token_ticker || !a_value || !a_tx_num) {
+        return NULL;
+    }
+
+    if (dap_chain_addr_check_sum(a_addr_from)) {
+        return NULL;
+    }
+
+    for (size_t i = 0; i < a_tx_num; ++i) {
+        if (!a_addr_to || !a_addr_to[i]) {
+            return NULL;
+        }
+        if (dap_chain_addr_check_sum(a_addr_to[i])) {
+            return NULL;
+        }
+        if (IS_ZERO_256(a_value[i])) {
+            return NULL;
+        }
+    }
+    const char * l_native_ticker = s_get_native_ticker(l_net_name);
+    bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker);
+
+    uint256_t l_value_transfer = {}; // how many coins to transfer
+    uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {};
+    for (size_t i = 0; i < a_tx_num; ++i) {
+        SUM_256_256(l_value_total, a_value[i], &l_value_total);
+    }
+    uint256_t l_value_need = l_value_total;
+
+    dap_list_t *l_list_fee_out = NULL;
+    uint256_t l_net_fee = {};
+    dap_chain_addr_t *l_addr_fee = NULL;
+    if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee)) {
+        return NULL;
+    }
+
+    bool l_net_fee_used = !IS_ZERO_256(l_net_fee);
+    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
+    json_object *l_outs = NULL;
+    int l_outputs_count = 0;
+    if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count)) {
+        return NULL;
+    }
+
+    if (l_single_channel)
+        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+    else if (!IS_ZERO_256(l_total_fee)) {
+        l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                               l_total_fee, 
+                                                               &l_fee_transfer);
+        if (!l_list_fee_out) {
+            printf("Not enough funds to pay fee");
+            json_object_put(l_outs);
+            return NULL;
+        }
+    }
+    dap_list_t *l_list_used_out = NULL;
+    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                            l_value_need,
+                                                            &l_value_transfer);
+    json_object_put(l_outs);
+    if (!l_list_used_out) {
+        printf("Not enough funds to transfer");
+        return NULL;
+    }
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    // add 'in' items
+    {
+        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+        assert(EQUAL_256(l_value_to_items, l_value_transfer));
+        dap_list_free_full(l_list_used_out, NULL);
+        if (l_list_fee_out) {
+            uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+            assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+            dap_list_free_full(l_list_fee_out, NULL);
+        }
+
+    }
+    if (a_tx_num > 1) {
+        uint32_t l_tx_num = a_tx_num;
+        dap_chain_tx_tsd_t *l_out_count = dap_chain_datum_tx_item_tsd_create(&l_tx_num, DAP_CHAIN_DATUM_TRANSFER_TSD_TYPE_OUT_COUNT, sizeof(uint32_t));
+        dap_chain_datum_tx_add_item(&l_tx, l_out_count);
+    }
+    
+    if (l_single_channel) { // add 'out' items
+        uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
+        for (size_t i = 0; i < a_tx_num; ++i) {
+            if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) == 1) {
+                SUM_256_256(l_value_pack, a_value[i], &l_value_pack);
+            } else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
+                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // coin back
+        uint256_t l_value_back;
+        SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+        if(!IS_ZERO_256(l_value_back)) {
+            if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+    } else { // add 'out_ext' items
+        for (size_t i = 0; i < a_tx_num; ++i) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // coin back
+        uint256_t l_value_back;
+        SUBTRACT_256_256(l_value_transfer, l_value_total, &l_value_back);
+        if(!IS_ZERO_256(l_value_back)) {
+            if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // fee coin back
+        SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back);
+        if(!IS_ZERO_256(l_value_back)) {
+            if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+    }
+    DAP_DELETE(l_addr_fee);
+    return l_tx;
+}
+
+dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer)
+{
+    dap_list_t *l_list_used_out = NULL;
+    uint256_t l_value_transfer = {};
+
+    for (int i = 0; i < a_outputs_count; i++) {
+        json_object *l_output = json_object_array_get_idx(a_outputs_array, i);
+        
+        json_object *l_value_datosi_obj = NULL;
+        json_object_object_get_ex(l_output, "value_datosi", &l_value_datosi_obj);
+        if (!l_value_datosi_obj) {
+            continue;
+        }
+        const char *l_value_str = json_object_get_string(l_value_datosi_obj);
+        uint256_t l_value = dap_chain_balance_scan(l_value_str);
+
+        if (IS_ZERO_256(l_value)) {
+            continue;
+        }
+
+        json_object *l_prev_hash_obj = NULL;
+        json_object_object_get_ex(l_output, "prev_hash", &l_prev_hash_obj);
+        if (!l_prev_hash_obj) {
+            continue;
+        }
+        const char *l_prev_hash_str = json_object_get_string(l_prev_hash_obj);
+        
+        json_object *l_out_prev_idx_obj = NULL;
+        json_object_object_get_ex(l_output, "out_prev_idx", &l_out_prev_idx_obj);
+        if (!l_out_prev_idx_obj) {
+            continue;
+        }
+        int l_out_idx = json_object_get_int(l_out_prev_idx_obj);
+
+        dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t);
+        if (!l_item) {
+            continue;
+        }
+
+        dap_chain_hash_fast_from_str(l_prev_hash_str, &l_item->tx_hash_fast);
+        l_item->num_idx_out = l_out_idx;
+        l_item->value = l_value;
+
+        l_list_used_out = dap_list_append(l_list_used_out, l_item);
+        
+        SUM_256_256(l_value_transfer, l_value, &l_value_transfer);
+
+        if (compare256(l_value_transfer, a_value_need) >= 0) {
+            break;
+        }
+    }
+
+    if (compare256(l_value_transfer, a_value_need) >= 0 && l_list_used_out) {
+        if (a_value_transfer) {
+            *a_value_transfer = l_value_transfer;
+        }
+        return l_list_used_out;
+    } else {
+        dap_list_free_full(l_list_used_out, NULL);
+        return NULL;
+    }
+}
+
+uint256_t get_balance_from_json(json_object *l_json_outs, const char *a_token_sell) {
+    uint256_t l_value = {};
+    if (l_json_outs && json_object_is_type(l_json_outs, json_type_array)) {
+        for (size_t i = 0; i < json_object_array_length(l_json_outs); i++) {
+            json_object *outer_array = json_object_array_get_idx(l_json_outs, i);
+            if (json_object_is_type(outer_array, json_type_array)) {
+                for (size_t j = 0; j < json_object_array_length(outer_array); j++) {
+                    json_object *addr_obj = json_object_array_get_idx(outer_array, j);
+                    if (json_object_is_type(addr_obj, json_type_object)) {
+                        json_object *tokens = NULL;
+                        if (json_object_object_get_ex(addr_obj, "tokens", &tokens) && json_object_is_type(tokens, json_type_array)) {
+                            for (size_t k = 0; k < json_object_array_length(tokens); k++) {
+                                json_object *token_obj = json_object_array_get_idx(tokens, k);
+                                json_object *token = NULL;
+                                if (json_object_object_get_ex(token_obj, "token", &token) && json_object_is_type(token, json_type_object)) {
+                                    json_object *ticker = NULL;
+                                    if (json_object_object_get_ex(token, "ticker", &ticker) && json_object_is_type(ticker, json_type_string)) {
+                                        const char *ticker_str = json_object_get_string(ticker);
+                                        if (strcmp(ticker_str, a_token_sell) == 0) {
+                                            json_object *datoshi = NULL;
+                                            if (json_object_object_get_ex(token_obj, "datoshi", &datoshi) && json_object_is_type(datoshi, json_type_string)) {
+                                                const char *datoshi_str = json_object_get_string(datoshi);
+                                                l_value = dap_uint256_scan_uninteger(datoshi_str);
+                                                break;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return l_value;
+}
+
+bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) {
+    if (json_object_is_type(l_json_coins, json_type_array)) {
+        for (size_t i = 0; i < json_object_array_length(l_json_coins); i++) {
+            json_object *token_array = json_object_array_get_idx(l_json_coins, i);
+            if (json_object_is_type(token_array, json_type_array)) {
+                for (size_t j = 0; j < json_object_array_length(token_array); j++) {
+                    json_object *token_obj = json_object_array_get_idx(token_array, j);
+                    json_object *token_name = NULL;
+                    if (json_object_object_get_ex(token_obj, "-->Token name", &token_name) && json_object_is_type(token_name, json_type_string)) {
+                        const char *token_name_str = json_object_get_string(token_name);
+                        if (strcmp(token_name_str, a_token) == 0) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return false;
+}
+
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,
+                                     const char *a_token_sell, uint256_t a_datoshi_sell,
+                                     uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet){
+    if (!a_net_name || !a_token_buy || !a_token_sell || !a_wallet) {
+        return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMENT
+    }
+    if (IS_ZERO_256(a_rate)) {
+        return NULL; // XCHANGE_CREATE_ERROR_RATE_IS_ZERO
+    }
+    if (IS_ZERO_256(a_fee)) {
+        return NULL; // XCHANGE_CREATE_ERROR_FEE_IS_ZERO
+    }
+    if (IS_ZERO_256(a_datoshi_sell)) {
+        return NULL; // XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO
+    }
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name);
+    json_object *l_json_coins = request_command_to_rpc_by_curl(data);
+    if (!l_json_coins) {
+        return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS
+    }
+    if (!check_token_in_ledger(l_json_coins, a_token_sell) || !check_token_in_ledger(l_json_coins, a_token_buy)) {
+        json_object_put(l_json_coins);
+        return NULL; // XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER
+    }
+    json_object_put(l_json_coins);
+    dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name));
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
+            dap_chain_addr_to_str(l_wallet_addr), a_net_name);
+    DAP_DEL_Z(l_wallet_addr);
+    json_object *l_json_outs = request_command_to_rpc_by_curl(data);
+    uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell);
+
+    uint256_t l_value_sell = a_datoshi_sell;
+    if (!dap_strcmp(s_get_native_ticker(a_net_name), a_token_sell)) {
+        if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) {
+            return NULL; // XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE
+        }
+    } else { // sell non-native ticker
+        uint256_t l_fee_value = get_balance_from_json(l_json_outs, s_get_native_ticker(a_net_name));
+        if (compare256(l_fee_value, a_fee) == -1) {
+            return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET
+        }
+    }
+    if (compare256(l_value, l_value_sell) == -1) {
+        return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET
+    }
+    // Create the price
+    dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
+    if (!l_price) {
+        return NULL; // XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED
+    }
+    dap_stpcpy(l_price->token_sell, a_token_sell);
+    dap_stpcpy(l_price->token_buy, a_token_buy);
+    l_price->datoshi_sell = a_datoshi_sell;
+    l_price->rate = a_rate;
+    l_price->fee = a_fee;
+    dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name);
+    return l_tx;
+}
+
+json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_name,  dap_chain_addr_t * a_addr) { 
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
+            dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name);
+    json_object *l_json_outs = request_command_to_rpc_by_curl(data);
+    if (!l_json_outs) {
+        return NULL;
+    }
+
+    if (!json_object_is_type(l_json_outs, json_type_array)) {
+        json_object_put(l_json_outs);
+        return NULL;
+    }
+
+    if (json_object_array_length(l_json_outs) == 0) {
+        json_object_put(l_json_outs);
+        return NULL;
+    }
+
+    json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0);
+    if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) {
+        json_object_put(l_json_outs);
+        return NULL;
+    }
+
+    json_object *l_first_item = json_object_array_get_idx(l_first_array, 0);
+    if (!l_first_item) {
+        json_object_put(l_json_outs);
+        return NULL;
+    }
+
+    json_object *l_outs = NULL;
+    if (!json_object_object_get_ex(l_first_item, "outs", &l_outs) ||
+        !json_object_is_type(l_outs, json_type_array)) {
+        json_object_put(l_json_outs);
+        return NULL;
+    }
+    json_object_get(l_outs);
+    json_object_put(l_json_outs);
+    return l_outs;
+}
+
+
+static dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
+                                                                 const char *a_native_ticker, const char *a_net_name)
+{
+    if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) {
+        return NULL;
+    }
+    const char *l_native_ticker = s_get_native_ticker(a_net_name);
+    bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker);
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer; // how many coins to transfer
+    uint256_t l_value_need = a_price->datoshi_sell,
+              l_net_fee,
+              l_total_fee = a_price->fee,
+              l_fee_transfer;
+    dap_chain_addr_t * l_addr_net_fee = NULL;
+    dap_list_t *l_list_fee_out = NULL;
+
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee);
+    if (l_net_fee_used)
+        SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
+
+    dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name));
+    dap_chain_addr_t l_seller_addr = *l_wallet_addr;
+    json_object *l_outs_native = get_tx_outs_by_curl(a_native_ticker, a_net_name, l_wallet_addr);
+    if (!l_outs_native) {
+        return NULL;
+    }
+
+    json_object *l_outs = NULL;
+    if (!dap_strcmp(a_price->token_sell, a_native_ticker)) {
+        l_outs = l_outs_native;
+    } else {
+        l_outs = get_tx_outs_by_curl(a_price->token_sell, a_net_name, l_wallet_addr);
+    }
+    DAP_DELETE(l_wallet_addr);
+    int l_out_native_count = json_object_array_length(l_outs_native);
+    int l_out_count = json_object_array_length(l_outs);
+
+    if (l_single_channel)
+        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+    else if (!IS_ZERO_256(l_total_fee)) {
+        l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+                                                               l_total_fee, 
+                                                               &l_fee_transfer);
+        if (!l_list_fee_out) {
+            printf("Not enough funds to pay fee");
+            json_object_put(l_outs_native);
+            json_object_put(l_outs);
+            return NULL;
+        }
+    }
+    dap_list_t *l_list_used_out = NULL;
+    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_out_count,
+                                                            l_value_need,
+                                                            &l_value_transfer);
+    if (!l_list_used_out) {
+        printf("Not enough funds to transfer");
+        json_object_put(l_outs_native);
+        json_object_put(l_outs);
+        return NULL;
+    }
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    // add 'in' items to sell
+    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+    dap_list_free_full(l_list_used_out, NULL);
+    if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) {
+        dap_chain_datum_tx_delete(l_tx);
+        printf("Can't compose the transaction input\n");
+        return NULL;
+    }
+    if (!l_single_channel) {
+        // add 'in' items to fee
+        uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+        if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Can't compose the transaction input\n");
+            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, s_get_net_id(a_net_name), a_price->datoshi_sell,
+                                                                                                s_get_net_id(a_net_name), a_price->token_buy, a_price->rate,
+                                                                                                &l_seller_addr, NULL, 0);
+        if (!l_tx_out) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Can't compose the transaction conditional output\n");
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
+        DAP_DELETE(l_tx_out);
+        // Network fee
+        if (l_net_fee_used) {
+            if ((l_single_channel &&
+                        dap_chain_datum_tx_add_out_item(&l_tx, l_addr_net_fee, l_net_fee) != 1) ||
+                    (!l_single_channel &&
+                        dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) {
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Cant add network fee output\n");
+                return NULL;
+            }
+        }
+        DAP_DELETE(l_addr_net_fee);
+        // Validator's fee
+        if (!IS_ZERO_256(a_price->fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Cant add validator's fee output\n");
+                return NULL;
+            }
+        }
+        // coin back
+        uint256_t l_value_back = {};
+        SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back);
+        if (!IS_ZERO_256(l_value_back)) {
+            if ((l_single_channel &&
+                        dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) ||
+                    (!l_single_channel &&
+                        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);
+                printf("Cant add coin back output\n");
+                return NULL;
+            }
+        }
+        // Fee coinback
+        if (!l_single_channel) {
+            uint256_t l_fee_coinback = {};
+            SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback);
+            if (!IS_ZERO_256(l_fee_coinback)) {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    printf("Cant add fee back output\n");
+                    return NULL;
+                }
+            }
+        }
+    }
+
+    // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
+    // // add 'sign' item
+    // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
+    //     dap_chain_datum_tx_delete(l_tx);
+    //     dap_enc_key_delete(l_seller_key);
+    //     printf("Can't add sign output\n");
+    //     return NULL;
+    // }
+    // dap_enc_key_delete(l_seller_key);
+    return l_tx;
+}
+
+// tx_cond_create -net <net_name> -token <token_ticker> -w <wallet_name> -cert <pub_cert_name> -value <value_datoshi> -fee <value> -unit {B | SEC} -srv_uid <numeric_uid>
+int dap_tx_cond_create_compose(int argc, char ** argv)
+{
+    int arg_index = 1;
+    const char * l_token_ticker = NULL;
+    const char * l_wallet_str = NULL;
+    const char * l_cert_str = NULL;
+    const char * l_value_datoshi_str = NULL;
+    const char * l_value_fee_str = NULL;
+    const char * l_net_name = NULL;
+    const char * l_unit_str = NULL;
+    const char * l_srv_uid_str = NULL;
+    uint256_t l_value_datoshi = {};    
+    uint256_t l_value_fee = {};
+    const char * l_hash_out_type = NULL;
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type);
+    if(!l_hash_out_type)
+        l_hash_out_type = "hex";
+    if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) {
+        printf("Invalid parameter -H, valid values: -H <hex | base58>\n");
+        return -1;
+    }
+
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_datoshi_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_value_fee_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str);
+
+    if(!l_token_ticker) {
+        printf("tx_cond_create requires parameter '-token'\n");
+        return -2;
+    }
+    if (!l_wallet_str) {
+        printf("tx_cond_create requires parameter '-w'\n");
+        return -3;
+    }
+    if (!l_cert_str) {
+        printf("tx_cond_create requires parameter '-cert'\n");
+        return -4;
+    }
+    if(!l_value_datoshi_str) {
+        printf("tx_cond_create requires parameter '-value'\n");
+        return -5;
+    }
+    if(!l_value_fee_str){
+        printf("tx_cond_create requires parameter '-fee'\n");
+        return -6;
+    }
+    if(!l_net_name) {
+        printf("tx_cond_create requires parameter '-net'\n");
+        return -7;
+    }
+    if(!l_unit_str) {
+        printf("tx_cond_create requires parameter '-unit'\n");
+        return -8;
+    }
+
+    if(!l_srv_uid_str) {
+        printf("tx_cond_create requires parameter '-srv_uid'\n");
+        return -9;
+    }
+    dap_chain_net_srv_uid_t l_srv_uid = {};
+    l_srv_uid.uint64 = strtoll(l_srv_uid_str, NULL, 10);
+    if (!l_srv_uid.uint64) {
+        printf("Can't find service UID %s\n", l_srv_uid_str);
+        return -10;
+    }
+
+    dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)l_unit_str)};
+
+    if(l_price_unit.enm == SERV_UNIT_UNDEFINED) {
+        printf("Can't recognize unit '%s'. Unit must look like { B | SEC }\n", l_unit_str);
+        return -11;
+    }
+
+    l_value_datoshi = dap_chain_balance_scan(l_value_datoshi_str);
+    if(IS_ZERO_256(l_value_datoshi)) {
+        printf("Can't recognize value '%s' as a number\n", l_value_datoshi_str);
+        return -12;
+    }
+
+    l_value_fee = dap_chain_balance_scan(l_value_fee_str);
+    if(IS_ZERO_256(l_value_fee)) {
+        printf("Can't recognize value '%s' as a number\n", l_value_fee_str);
+        return -13;
+    }
+
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path, NULL);
+    if(!l_wallet) {
+        printf("Can't open wallet '%s'\n", l_wallet_str);
+        return -15;
+    }
+
+    dap_cert_t *l_cert_cond = dap_cert_find_by_name(l_cert_str);
+    if(!l_cert_cond) {
+        dap_chain_wallet_close(l_wallet);
+        printf("Can't find cert '%s'\n", l_cert_str);
+        return -16;
+    }
+
+    dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
+    dap_pkey_t *l_key_cond = dap_pkey_from_enc_key(l_cert_cond->enc_key);
+    if (!l_key_cond) {
+        dap_chain_wallet_close(l_wallet);
+        dap_enc_key_delete(l_key_from);
+        printf("Cert '%s' doesn't contain a valid public key\n", l_cert_str);
+        return -17;
+    }
+
+    uint256_t l_value_per_unit_max = {};
+    dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker,
+                                                        l_value_datoshi, l_value_per_unit_max, l_price_unit,
+                                                        l_srv_uid, l_value_fee, NULL, 0, l_hash_out_type);
+    
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
+    dap_chain_datum_tx_delete(l_tx);
+    dap_chain_wallet_close(l_wallet);
+    dap_enc_key_delete(l_key_from);
+    DAP_DELETE(l_key_cond);
+    return 0;
+}
+
+
+dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name,
+        dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
+        const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+        uint256_t a_value, uint256_t a_value_per_unit_max,
+        dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
+        uint256_t a_value_fee, const void *a_cond,
+        size_t a_cond_size, const char *a_hash_out_type)
+{
+    // check valid param
+    if (!a_net_name || !a_key_from || !a_key_cond ||
+            !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value))
+        return NULL;
+
+    if (dap_strcmp(s_get_native_ticker(a_net_name), a_token_ticker)) {
+        printf("Pay for service should be only in native token ticker\n");
+        return NULL;
+    }
+
+    uint256_t l_net_fee = {};
+    dap_chain_addr_t* l_addr_fee = NULL;
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee);
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer = {}; // how many coins to transfer
+    uint256_t l_value_need = {};
+    SUM_256_256(a_value, a_value_fee, &l_value_need);
+    if (l_net_fee_used) {
+        SUM_256_256(l_value_need, l_net_fee, &l_value_need);
+    }
+    // where to take coins for service
+    dap_chain_addr_t l_addr_from;
+    dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, s_get_net_id(a_net_name));
+    // list of transaction with 'out' items
+    json_object *l_outs = NULL;
+    int l_outputs_count = 0;
+    if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count)) {
+        return NULL;
+    }
+    dap_list_t *l_list_used_out = NULL;
+    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                            l_value_need,
+                                                            &l_value_transfer);
+    json_object_put(l_outs);
+
+
+    // dap_list_t *l_list_used_out = NULL;
+    // if (dap_chain_wallet_cache_tx_find_outs_with_val(l_ledger->net, a_token_ticker, &l_addr_from, &l_list_used_out, l_value_need, &l_value_transfer) == -101)
+    //     l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_token_ticker,
+    //                                         &l_addr_from, l_value_need, &l_value_transfer);
+    if(!l_list_used_out) {
+        printf("Nothing to transfer (not enough funds)\n");
+        return NULL;
+    }
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    // add 'in' items
+    {
+        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+        assert(EQUAL_256(l_value_to_items, l_value_transfer));
+        dap_list_free_full(l_list_used_out, NULL);
+    }
+    // add 'out_cond' and 'out' items
+    {
+        uint256_t l_value_pack = {}; // how much coin add to 'out' items
+        if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond,
+                a_cond_size) == 1) {
+            SUM_256_256(l_value_pack, a_value, &l_value_pack);
+        } else {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Cant add conditional output\n");
+            return NULL;
+        }
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
+                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // coin back
+        uint256_t l_value_back = {};
+        SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+        if (!IS_ZERO_256(l_value_back)) {
+            if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Cant add coin back output\n");
+                return NULL;
+            }
+        }
+    }
+
+    // // add 'sign' items
+    // if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) {
+    //     dap_chain_datum_tx_delete(l_tx);
+    //     printf("Can't add sign output\n");
+    //     return NULL;
+    // }
+    // size_t l_tx_size = dap_chain_datum_tx_get_size( l_tx );
+    // dap_chain_datum_t *l_datum = dap_chain_datum_create( DAP_CHAIN_DATUM_TX, l_tx, l_tx_size );
+    // dap_chain_datum_tx_delete(l_tx);
+    // dap_chain_t *l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX);
+    // char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, a_hash_out_type);
+    // DAP_DELETE(l_datum);
+
+    return l_tx;
+}
+
+// stake_lock hold -net <net_name> -w <wallet_name> -time_staking <YYMMDD> -token <ticker> -value <value> -fee <value>[-chain <chain_name>] [-reinvest <percentage>]
+int  dap_cli_hold_compose(int a_argc, char **a_argv)
+{
+    int arg_index = 1;
+    const char *l_net_name = NULL, *l_ticker_str = NULL, *l_coins_str = NULL,
+            *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL,
+            *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL;
+
+    const char *l_wallets_path								=	c_wallets_path;
+    char 	l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
+    dap_time_t              			l_time_staking		=	0;
+    uint256_t						    l_reinvest_percent	=	{};
+    uint256_t							l_value_delegated	=	{};
+    uint256_t                           l_value_fee     	=	{};
+    uint256_t 							l_value;
+    dap_enc_key_t						*l_key_from;
+    dap_chain_wallet_t					*l_wallet;
+    dap_chain_addr_t					*l_addr_holder;
+
+
+    const char *l_hash_out_type = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
+    if(!l_hash_out_type)
+        l_hash_out_type = "hex";
+    if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type, "base58")) {
+        printf("Error: Invalid hash type argument\n");
+        return -1;
+    }
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_name) || NULL == l_net_name) {
+        printf("Error: Missing or invalid network argument\n");
+        return -2;
+    }
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_ticker_str) || NULL == l_ticker_str || dap_strlen(l_ticker_str) > 8) {
+        printf("Error: Missing or invalid token argument\n");
+        return -3;
+    }
+
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name);
+    json_object *l_json_coins = request_command_to_rpc_by_curl(data);
+    if (!l_json_coins) {
+        return -4;
+    }
+    if (!check_token_in_ledger(l_json_coins, l_ticker_str)) {
+        printf("Error: Invalid token '%s'\n", l_ticker_str);
+        return -4;
+    }
+
+    if ((!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-coins", &l_coins_str) || NULL == l_coins_str) &&
+            (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-value", &l_coins_str) || NULL == l_coins_str)) {
+        printf("Error: Missing coins or value argument\n");
+        return -5;
+    }
+
+    if (IS_ZERO_256((l_value = dap_chain_balance_scan(l_coins_str)))) {
+        printf("Error: Invalid coins format\n");
+        return -6;
+    }
+
+    dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str);
+
+    if (!check_token_in_ledger(l_json_coins, l_delegated_ticker_str)) {
+        printf("Error: No delegated token found\n");
+        return -7;
+    }
+    json_object_put(l_json_coins);
+
+    uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001");  // TODO 16126
+    // uint256_t l_emission_rate = dap_ledger_token_get_emission_rate(l_ledger, l_delegated_ticker_str);
+    // if (IS_ZERO_256(l_emission_rate)) {
+    //     printf("Error: Invalid token emission rate\n");
+    //     return -8;
+    // }
+
+    if (MULT_256_COIN(l_value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) {
+        printf("Error: Invalid coins format\n");
+        return -9;
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_str);
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str);
+    if (!l_chain_id_str) {
+        printf("Error: Missing or invalid chain_id argument\n");
+        return -10;
+    }
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) {
+        printf("Error: Missing wallet argument\n");
+        return -11;
+    }
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) {
+        printf("Error: Missing fee argument\n");
+        return -12;
+    }
+
+    if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) {
+        printf("Error: Invalid fee format\n");
+        return -13;
+    }
+
+    // Read time staking
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-time_staking", &l_time_staking_str) || !l_time_staking_str) {
+        printf("Error: Missing time staking argument\n");
+        return -14;
+    }
+
+    if (dap_strlen(l_time_staking_str) != 6) {
+        printf("Error: Invalid time staking format\n");
+        return -15;
+    }
+
+    char l_time_staking_month_str[3] = {l_time_staking_str[2], l_time_staking_str[3], 0};
+    int l_time_staking_month = atoi(l_time_staking_month_str);
+    if (l_time_staking_month < 1 || l_time_staking_month > 12) {
+        printf("Error: Invalid time staking month\n");
+        return -16;
+    }
+
+    char l_time_staking_day_str[3] = {l_time_staking_str[4], l_time_staking_str[5], 0};
+    int l_time_staking_day = atoi(l_time_staking_day_str);
+    if (l_time_staking_day < 1 || l_time_staking_day > 31) {
+        printf("Error: Invalid time staking day\n");
+        return -17;
+    }
+
+    l_time_staking = dap_time_from_str_simplified(l_time_staking_str);
+    if (0 == l_time_staking) {
+        printf("Error: Invalid time staking\n");
+        return -18;
+    }
+    dap_time_t l_time_now = dap_time_now();
+    if (l_time_staking < l_time_now) {
+        printf("Error: Time staking is in the past\n");
+        return -19;
+    }
+    l_time_staking -= l_time_now;
+
+    if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-reinvest", &l_reinvest_percent_str) && NULL != l_reinvest_percent_str) {
+        l_reinvest_percent = dap_chain_coins_to_balance(l_reinvest_percent_str);
+        if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1) {
+            printf("Error: Invalid reinvest percentage\n");
+            return -20;
+        }
+        if (IS_ZERO_256(l_reinvest_percent)) {
+            int l_reinvest_percent_int = atoi(l_reinvest_percent_str);
+            if (l_reinvest_percent_int < 0 || l_reinvest_percent_int > 100) {
+                printf("Error: Invalid reinvest percentage\n");
+                return -21;
+            }
+            l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int);
+            MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent);
+        }
+    }
+
+    if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallets_path, NULL))) {
+        printf("Error: Unable to open wallet '%s'\n", l_wallet_str);
+        return -22;
+    }
+
+
+    if (NULL == (l_addr_holder = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)))) {
+        dap_chain_wallet_close(l_wallet);
+        printf("Error: Unable to get wallet address for '%s'\n", l_wallet_str);
+        return -24;
+    }
+
+    snprintf(data, sizeof(data), 
+        "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
+        dap_chain_addr_to_str(l_addr_holder), l_net_name);
+    DAP_DEL_Z(l_addr_holder);
+
+    json_object *l_json_outs = request_command_to_rpc_by_curl(data);
+    uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str);
+    json_object_put(l_json_outs);
+    if (compare256(l_value_balance, l_value) == -1) {
+        dap_chain_wallet_close(l_wallet);
+        printf("Error: Insufficient funds in wallet\n");
+        return -23;
+    }
+
+    l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
+
+    // Make transfer transaction
+    dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_net_name, l_key_from,
+                                                           l_ticker_str, l_value, l_value_fee,
+                                                           l_time_staking, l_reinvest_percent,
+                                                           l_delegated_ticker_str, l_value_delegated, l_chain_id_str);
+
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
+    dap_chain_datum_tx_delete(l_tx);
+
+    dap_chain_wallet_close(l_wallet);
+    dap_enc_key_delete(l_key_from);
+    
+    return 0;
+}
+
+
+dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
+                                                    const char *a_main_ticker,
+                                                    uint256_t a_value, uint256_t a_value_fee,
+                                                    dap_time_t a_time_staking, uint256_t a_reinvest_percent,
+                                                    const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * l_chain_id_str)
+{
+    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
+    // check valid param
+    if (!a_net_name || !a_key_from ||
+        !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value))
+        return NULL;
+
+    const char *l_native_ticker = s_get_native_ticker(a_net_name);
+    bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker);
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer = {}; // how many coins to transfer
+    uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
+    dap_chain_addr_t * l_addr_fee = NULL;
+    dap_chain_addr_t l_addr = {};
+
+    dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name));
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee);
+    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
+
+    json_object *l_outs_native = get_tx_outs_by_curl(l_native_ticker, a_net_name, &l_addr);
+    if (!l_outs_native) {
+        return NULL;
+    }
+
+    json_object *l_outs_main = NULL;
+    if (!dap_strcmp(a_main_ticker, l_native_ticker)) {
+        l_outs_main = l_outs_native;
+    } else {
+        l_outs_main = get_tx_outs_by_curl(a_main_ticker, a_net_name, &l_addr);
+    }
+    int l_out_native_count = json_object_array_length(l_outs_native);
+    int l_out_main_count = json_object_array_length(l_outs_main);
+
+    dap_list_t *l_list_fee_out = NULL;
+    if (l_main_native)
+        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+    else if (!IS_ZERO_256(l_total_fee)) {
+        l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+                                                               l_total_fee, 
+                                                               &l_fee_transfer);
+        if (!l_list_fee_out) {
+            printf("Not enough funds to pay fee");
+            json_object_put(l_outs_native);
+            json_object_put(l_outs_main);
+            return NULL;
+        }
+    }
+    // list of transaction with 'out' items
+    dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_main, l_out_main_count,
+                                                            l_value_need,
+                                                            &l_value_transfer);
+    if (!l_list_used_out) {
+        printf("Not enough funds to transfer");
+        json_object_put(l_outs_native);
+        json_object_put(l_outs_main);
+        return NULL;
+    }
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
+    // add 'in' items
+    {
+        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+        assert(EQUAL_256(l_value_to_items, l_value_transfer));
+        dap_list_free_full(l_list_used_out, NULL);
+        if (l_list_fee_out) {
+            uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+            assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+            dap_list_free_full(l_list_fee_out, NULL);
+        }
+    }
+
+    // add 'in_ems' item
+    {
+        dap_chain_id_t l_chain_id = { };
+        dap_chain_id_parse(l_chain_id_str, &l_chain_id);
+        dap_hash_fast_t l_blank_hash = {};
+        dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(l_chain_id, &l_blank_hash, a_delegated_ticker_str);
+        dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems);
+    }
+
+    // add 'out_cond' and 'out_ext' items
+    {
+        uint256_t l_value_pack = {}, l_native_pack = {}; // how much coin add to 'out_ext' items
+        dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock(
+                                                        l_uid, a_value, a_time_staking, a_reinvest_percent);
+        if (l_tx_out_cond) {
+            SUM_256_256(l_value_pack, a_value, &l_value_pack);
+            dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond);
+            DAP_DEL_Z(l_tx_out_cond);
+        } else {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Error: Cant add conditional output\n");
+            return NULL;
+        }
+
+        uint256_t l_value_back = {};
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Error: Cant add network fee output\n");
+                return NULL;
+            }
+            if (l_main_native)
+                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            else
+                SUM_256_256(l_native_pack, l_net_fee, &l_native_pack);
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Error: Cant add validator's fee output\n");
+                return NULL;
+            }
+            if (l_main_native)
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            else
+                SUM_256_256(l_native_pack, a_value_fee, &l_native_pack);
+        }
+        // coin back
+        SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+        if (!IS_ZERO_256(l_value_back)) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Error: Cant add coin back output for main ticker\n");
+                return NULL;
+            }
+        }
+        // fee coin back
+        if (!IS_ZERO_256(l_fee_transfer)) {
+            SUBTRACT_256_256(l_fee_transfer, l_native_pack, &l_value_back);
+            if (!IS_ZERO_256(l_value_back)) {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    printf("Error: Cant add coin back output for native ticker\n");
+                    return NULL;
+                }
+            }
+        }
+    }
+
+    // add delegated token emission 'out_ext'
+    if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_delegated_value, a_delegated_ticker_str) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        printf("Error: Cant add delegated token emission output\n");
+        return NULL;
+    }
+
+    return l_tx;
+    // // add 'sign' item
+    // if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) {
+    //     dap_chain_datum_tx_delete(l_tx);
+    //     printf("Error: Can't add sign output\n");
+    //     return NULL;
+    // }
+
+    // size_t l_tx_size = dap_chain_datum_tx_get_size( l_tx );
+    // dap_chain_datum_t *l_datum = dap_chain_datum_create( DAP_CHAIN_DATUM_TX, l_tx, l_tx_size );
+
+    // return l_datum;
+}
+
+
+int dap_cli_take_compose(int a_argc, char **a_argv)
+{
+    int arg_index = 1;
+    const char *l_net_str, *l_ticker_str, *l_wallet_str, *l_tx_str, *l_tx_burning_str, *l_chain_id_str, *l_value_fee_str;
+    l_net_str = l_ticker_str = l_wallet_str = l_tx_str = l_tx_burning_str = l_chain_id_str = l_value_fee_str = NULL;
+    char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
+    int									l_prev_cond_idx		=	0;
+    uint256_t							l_value_delegated	= 	{};
+    uint256_t                           l_value_fee     	=	{};
+    dap_chain_wallet_t					*l_wallet;
+    dap_hash_fast_t						l_tx_hash;
+    dap_chain_tx_out_cond_t				*l_cond_tx = NULL;
+    dap_enc_key_t						*l_owner_key;
+
+
+    const char *l_hash_out_type = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
+    if (!l_hash_out_type)
+        l_hash_out_type = "hex";
+    if (dap_strcmp(l_hash_out_type, "hex") && dap_strcmp(l_hash_out_type, "base58")) {
+        printf("Error: Invalid hash type argument\n");
+        return -1;
+    }
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str) || NULL == l_net_str) {
+        printf("Error: Missing or invalid network argument\n");
+        return -2;
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str);
+    if (!l_chain_id_str) {
+        printf("Error: Missing or invalid chain_id argument\n");
+        return -10;
+    }
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_str) || NULL == l_tx_str) {
+        printf("Error: Missing or invalid transaction argument\n");
+        return -5;
+    }
+
+    if (dap_chain_hash_fast_from_str(l_tx_str, &l_tx_hash)) {
+        printf("Error: Invalid transaction hash\n");
+        return -6;
+    }
+
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+            l_tx_str, l_net_str);
+    
+    json_object *response = request_command_to_rpc_by_curl(data);
+    if (!response) {
+        printf("Error: Failed to get response from remote node\n");
+        return -15;
+    }
+    
+    json_object *items = NULL;
+    json_object *items_array = json_object_array_get_idx(response, 0);
+    if (items_array) {
+        items = json_object_object_get(items_array, "ITEMS");
+    }
+    if (!items) {
+        printf("Error: No items found in response\n");
+        return -16;
+    }
+    int items_count = json_object_array_length(items);
+    for (int i = 0; i < items_count; i++) {
+        json_object *item = json_object_array_get_idx(items, i);
+        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+        if (dap_strcmp(item_type, "OUT COND") == 0) {
+            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+            if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK")) {
+                l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+                l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+                l_cond_tx->header.value =  dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+                l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK;
+                l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+                l_cond_tx->subtype.srv_stake_lock.time_unlock =  dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "time_unlock")));
+                break;
+            }
+        }
+    }
+    if (!l_cond_tx) {
+        printf("Error: No transaction output condition found\n");
+        return -7;
+    }
+
+
+    json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
+    const char *spent_outs_value = json_object_get_string(spent_outs);
+    if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
+        printf("Error: Transaction output item already used\n");
+        return -9;
+    }
+
+    json_object *response_header_array = json_object_array_get_idx(response, 0);
+    if (!response_header_array) {
+        printf("Error: Failed to get items array from response\n");
+        return -10;
+    }
+
+    json_object *token_ticker_obj = json_object_object_get(response_header_array, "token ticker");
+    if (!token_ticker_obj) {
+        printf("Error: Token ticker not found in response\n");
+        return -11;
+    }
+    l_ticker_str = json_object_get_string(token_ticker_obj);
+
+
+
+    dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str);
+
+    uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001");
+
+    if (IS_ZERO_256(l_emission_rate) ||
+        MULT_256_COIN(l_cond_tx->header.value, l_emission_rate, &l_value_delegated) ||
+        IS_ZERO_256(l_value_delegated)) {
+        printf("Error: Invalid coins format\n");
+        return -12;
+    }
+
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) {
+        printf("Error: Missing or invalid wallet argument\n");
+        return -13;
+    }
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) {
+        printf("Error: Missing or invalid fee argument\n");
+        return -14;
+    }
+
+    if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) {
+        printf("Error: Invalid fee format\n");
+        return -15;
+    }
+
+    if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path, NULL))) {
+        printf("Error: Unable to open wallet\n");
+        return -16;
+    }
+
+    if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) {
+        dap_chain_wallet_close(l_wallet);
+        printf("Error: Owner key not found\n");
+        return -17;
+    }
+
+    if (l_cond_tx->subtype.srv_stake_lock.time_unlock > dap_time_now()) {
+        dap_chain_wallet_close(l_wallet);
+        dap_enc_key_delete(l_owner_key);
+        printf("Error: Not enough time has passed for unlocking\n");
+        return -19;
+    }
+    dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_net_str, l_owner_key, &l_tx_hash, l_prev_cond_idx,
+                                          l_ticker_str, l_cond_tx->header.value, l_value_fee,
+                                          l_delegated_ticker_str, l_value_delegated);
+
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
+
+
+    dap_chain_datum_tx_delete(l_tx);
+    dap_enc_key_delete(l_owner_key);
+
+    return 0;
+}
+
+
+dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
+                                               dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
+                                               const char *a_main_ticker, uint256_t a_value,
+                                               uint256_t a_value_fee,
+                                               const char *a_delegated_ticker_str, uint256_t a_delegated_value)
+{
+    // check valid param
+    if (!a_net_name | !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) {
+        printf("Error: Invalid parameters\n");
+        return NULL;
+    }
+
+    const char *l_native_ticker = s_get_native_ticker(a_net_name);
+    bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker);
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer = {}; // how many coins to transfer
+    uint256_t l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
+    dap_chain_addr_t* l_addr_fee = NULL;
+    dap_chain_addr_t l_addr = {};
+
+    dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name));
+    dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL;
+
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee);
+
+    json_object *l_outs_native = get_tx_outs_by_curl(l_native_ticker, a_net_name, &l_addr);
+    if (!l_outs_native) {
+        return NULL;
+    }
+
+    json_object *l_outs_delegated = get_tx_outs_by_curl(a_delegated_ticker_str, a_net_name, &l_addr);
+    int l_out_native_count = json_object_array_length(l_outs_native);
+    int l_out_delegated_count = json_object_array_length(l_outs_delegated);
+
+    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
+    if (!IS_ZERO_256(l_total_fee)) {
+        if (!l_main_native) {
+            l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+                                                                l_total_fee, 
+                                                                &l_fee_transfer);
+            if (!l_list_fee_out) {
+                printf("Not enough funds to pay fee");
+                json_object_put(l_outs_native);
+                json_object_put(l_outs_delegated);
+                return NULL;
+            }
+        } else if (compare256(a_value, l_total_fee) == -1) {
+            printf("Error: Total fee more than stake\n");
+            return NULL;
+        }
+    }
+    if (!IS_ZERO_256(a_delegated_value)) {
+        l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count,
+                                                               a_delegated_value, 
+                                                               &l_value_transfer);
+        if (!l_list_used_out) {
+            printf("Not enough funds to pay fee");
+            json_object_put(l_outs_native);
+            json_object_put(l_outs_delegated);
+            return NULL;
+        }
+    }
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
+    // add 'in_cond' & 'in' items
+    {
+        dap_chain_datum_tx_add_in_cond_item(&l_tx, a_stake_tx_hash, a_prev_cond_idx, 0);
+        if (l_list_used_out) {
+            uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+            assert(EQUAL_256(l_value_to_items, l_value_transfer));
+            dap_list_free_full(l_list_used_out, NULL);
+        }
+        if (l_list_fee_out) {
+            uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+            assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+            dap_list_free_full(l_list_fee_out, NULL);
+        }
+    }
+
+    // add 'out_ext' items
+    uint256_t l_value_back;
+    {
+        uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
+        // Network fee
+        if(l_net_fee_used){
+            if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker)){
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Error: Can't add network fee output\n");
+                return NULL;
+            }
+            SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+            {
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            }
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Error: Can't add validator's fee output\n");
+                return NULL;
+            }
+        }
+        // coin back
+        //SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back);
+        if(l_main_native){
+            if (SUBTRACT_256_256(a_value, l_value_pack, &l_value_back)) {
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Error: Can't subtract value pack from value\n");
+                return NULL;
+            }
+            if(!IS_ZERO_256(l_value_back)) {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker)!=1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    printf("Error: Can't add coin back output for main ticker\n");
+                    return NULL;
+                }
+            }
+        } else {
+            SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back);
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_value, a_main_ticker)!=1) {
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Error: Can't add coin back output for main ticker\n");
+                return NULL;
+            }
+            else
+            {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker)!=1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    printf("Error: Can't add coin back output for native ticker\n");
+                    return NULL;
+                }
+            }
+        }
+    }
+
+    // add burning 'out_ext'
+    if (!IS_ZERO_256(a_delegated_value)) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &c_dap_chain_addr_blank,
+                                               a_delegated_value, a_delegated_ticker_str) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Error: Can't add burning output for delegated value\n");
+            return NULL;
+        }
+        // delegated token coin back
+        SUBTRACT_256_256(l_value_transfer, a_delegated_value, &l_value_back);
+        if (!IS_ZERO_256(l_value_back)) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_delegated_ticker_str) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                printf("Error: Can't add coin back output for delegated ticker\n");
+                return NULL;
+            }
+        }
+    }
+
+    return l_tx;
+}
+uint256_t s_get_key_delegating_min_value(const char *a_net_str){
+    uint256_t l_key_delegating_min_value = uint256_0;
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", 
+            a_net_str);
+    
+    json_object *response = request_command_to_rpc_by_curl(data);
+    if (!response) {
+        printf("Error: Failed to get response from remote node\n");
+        return l_key_delegating_min_value;
+    }
+
+    json_object *response_array = json_object_array_get_idx(response, 0);
+    if (!response_array) {
+        printf("Error: Invalid response format\n");
+        return l_key_delegating_min_value;
+    }
+
+    json_object *summary_obj = json_object_array_get_idx(response_array, json_object_array_length(response_array) - 1);
+    if (!summary_obj) {
+        printf("Error: Summary object not found in response\n");
+        return l_key_delegating_min_value;
+    }
+
+    json_object *key_delegating_min_value_obj = json_object_object_get(summary_obj, "key_delegating_min_value");
+    if (!key_delegating_min_value_obj) {
+        printf("Error: key_delegating_min_value not found in summary\n");
+        return l_key_delegating_min_value;
+    }
+
+    const char *key_delegating_min_value_str = json_object_get_string(key_delegating_min_value_obj);
+    if (!key_delegating_min_value_str) {
+        printf("Error: Invalid key_delegating_min_value format\n");
+        return l_key_delegating_min_value;
+    }
+
+    l_key_delegating_min_value = dap_chain_balance_scan(key_delegating_min_value_str);
+    if (IS_ZERO_256(l_key_delegating_min_value)) {
+        printf("Error: Unrecognized number in key_delegating_min_value\n");
+        return l_key_delegating_min_value;
+    }
+
+    return l_key_delegating_min_value;
+}
+
+
+int dap_cli_voting_compose(int a_argc, char **a_argv)
+{
+    int arg_index = 1;
+    const char* l_question_str = NULL;
+    const char* l_options_list_str = NULL;
+    const char* l_voting_expire_str = NULL;
+    const char* l_max_votes_count_str = NULL;
+    const char* l_fee_str = NULL;
+    const char* l_wallet_str = NULL;
+    const char* l_net_str = NULL;
+    
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
+    // Select chain network
+    if(!l_net_str) {
+        printf("Voting requires parameter '-net' to be valid.\n");
+        return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING;
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str);
+    if (!l_question_str){
+        printf("Voting requires a question parameter to be valid.\n");
+        return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_PARAM_MISSING;
+    }
+
+    if (strlen(l_question_str) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
+        printf("The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH);
+        return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_CONTAIN_MAX_CHARACTERS;
+    }
+
+    dap_list_t *l_options_list = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-options", &l_options_list_str);
+    if (!l_options_list_str){
+        printf("Voting requires a question parameter to be valid.\n");
+        return -DAP_CHAIN_NET_VOTE_CREATE_OPTION_PARAM_MISSING;
+    }
+    // Parse options list
+    l_options_list = dap_get_options_list_from_str(l_options_list_str);
+    if(!l_options_list || dap_list_length(l_options_list) < 2){
+        printf("Number of options must be 2 or greater.\n");
+        return -DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR;
+    }
+
+    if(dap_list_length(l_options_list)>DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){
+        printf("The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT);            
+        return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS;
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str);
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str);
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str);
+    if (!l_fee_str){
+        printf("Voting requires parameter -fee to be valid.\n");
+        return -DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID;
+    }
+    uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str);
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str);
+    if (!l_wallet_str){
+        printf("Voting requires parameter -w to be valid.\n");
+        return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID;
+    }
+
+    dap_time_t l_time_expire = 0;
+    if (l_voting_expire_str)
+        l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str);
+    if (l_voting_expire_str && !l_time_expire){
+        printf("Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"\n");
+        return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT;
+    }
+    uint64_t l_max_count = 0;
+    if (l_max_votes_count_str)
+        l_max_count = strtoul(l_max_votes_count_str, NULL, 10);
+
+    bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false;
+    bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false;
+    dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, c_wallets_path,NULL);
+    if (!l_wallet_fee) {
+        printf("Wallet %s does not exist\n", l_wallet_str);
+        return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
+    }
+
+    dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net_str);
+    dap_list_free(l_options_list);
+    dap_chain_wallet_close(l_wallet_fee);
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
+    return 0;
+}
+
+
+dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
+                              uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
+                              bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
+                              const char *a_net_str) {
+
+    if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
+        return NULL;
+    }
+
+    // Parse options list
+
+    if(dap_list_length(a_options) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){
+        return NULL;
+    }
+
+    if (IS_ZERO_256(a_fee)) {
+        return NULL;
+    }
+
+    dap_chain_addr_t *l_addr_from =  dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str));
+
+    if(!l_addr_from) {
+        return NULL;
+    }
+
+    const char *l_native_ticker = s_get_native_ticker(a_net_str);
+    uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer;
+    dap_chain_addr_t *l_addr_fee = NULL;
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee);
+    SUM_256_256(l_net_fee, a_fee, &l_total_fee);
+
+    json_object *l_outs = NULL;
+    int l_outputs_count = 0;
+    if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count)) {
+        return NULL;
+    }
+
+    dap_list_t *l_list_used_out = NULL;
+    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                            l_total_fee,
+                                                            &l_value_transfer);
+
+    json_object_put(l_outs);
+    if (!l_list_used_out) {
+        printf("Not enough funds to transfer");
+        return NULL;
+    }
+
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
+    // Add Voting item
+    dap_chain_tx_voting_t* l_voting_item = dap_chain_datum_tx_item_voting_create();
+
+    dap_chain_datum_tx_add_item(&l_tx, l_voting_item);
+    DAP_DELETE(l_voting_item);
+
+    // Add question to tsd data
+    dap_chain_tx_tsd_t* l_question_tsd = dap_chain_datum_voting_question_tsd_create(a_question, strlen(a_question));
+    dap_chain_datum_tx_add_item(&l_tx, l_question_tsd);
+
+    // Add options to tsd
+    dap_list_t *l_temp = a_options;
+    while(l_temp){
+        if(strlen((char*)l_temp->data) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH){
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        dap_chain_tx_tsd_t* l_option = dap_chain_datum_voting_answer_tsd_create((char*)l_temp->data, strlen((char*)l_temp->data));
+        if(!l_option){
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_option);
+        DAP_DEL_Z(l_option);
+
+        l_temp = l_temp->next;
+    }
+
+    // add voting expire time if needed
+    if(a_expire_vote != 0){
+        dap_time_t l_expired_vote = a_expire_vote;
+        if (l_expired_vote < dap_time_now()){
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+
+        dap_chain_tx_tsd_t* l_expired_item = dap_chain_datum_voting_expire_tsd_create(l_expired_vote);
+        if(!l_expired_item){
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_expired_item);
+        DAP_DEL_Z(l_expired_item);
+    }
+
+    // Add vote max count if needed
+    if (a_max_vote != 0) {
+        dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote);
+        if(!l_max_votes_item){
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_max_votes_item);
+        DAP_DEL_Z(l_max_votes_item);
+    }
+
+    if (a_delegated_key_required) {
+        dap_chain_tx_tsd_t* l_delegated_key_req_item = dap_chain_datum_voting_delegated_key_required_tsd_create(true);
+        if(!l_delegated_key_req_item){
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_delegated_key_req_item);
+        DAP_DEL_Z(l_delegated_key_req_item);
+    }
+
+    if(a_vote_changing_allowed){
+        dap_chain_tx_tsd_t* l_vote_changing_item = dap_chain_datum_voting_vote_changing_allowed_tsd_create(true);
+        if(!l_vote_changing_item){
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item);
+        DAP_DEL_Z(l_vote_changing_item);
+    }
+
+    // add 'in' items
+    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+    assert(EQUAL_256(l_value_to_items, l_value_transfer));
+    dap_list_free_full(l_list_used_out, NULL);
+    uint256_t l_value_pack = {};
+    // Network fee
+    if (l_net_fee_used) {
+        if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
+            SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+        else {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+    }
+    // Validator's fee
+    if (!IS_ZERO_256(a_fee)) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1)
+            SUM_256_256(l_value_pack, a_fee, &l_value_pack);
+        else {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+    }
+    // coin back
+    uint256_t l_value_back;
+    SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+    if(!IS_ZERO_256(l_value_back)) {
+        if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+    }
+
+
+    return l_tx;
+}
 
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 8b13789179..41c05c0e90 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -1 +1,97 @@
+/*
+ * Authors:
+ * Roman Padenkov <roman.padenkov@demlabs.net>
+ * Olzhas Zharasbaev <oljas.jarasbaev@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://github.com/demlabsinc
+ * Copyright  (c) 2025-2026
+ * All rights reserved.
 
+ This file is part of DAP (Distributed Applications Platform) the open source project
+
+ DAP (Distributed Applications Platform) is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DAP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #pragma once
+ #include "dap_chain_common.h"
+ #include "dap_list.h"
+ #include "dap_math_ops.h"
+ #include "dap_chain_datum_tx.h"
+ #include "dap_chain_wallet.h"
+ #include "dap_chain_net_srv_xchange.h"
+
+ #include <json-c/json.h>
+
+
+
+
+ // #define RPC_NODES_URL "http://rpc.cellframe.net"
+#define RPC_NODES_URL "45.76.140.191:8081"
+
+#define NET_COUNT 6
+
+const char *c_wallets_path = NULL;
+
+typedef struct {
+    char name[20];
+    char native_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+    dap_chain_net_id_t net_id;
+} NetInfo;
+
+static NetInfo netinfo[NET_COUNT] = {
+    {"riemann",  "tKEL",  {.uint64 = 0x000000000000dddd}},
+    {"raiden",   "tCELL", {.uint64 = 0x000000000000bbbb}},
+    {"KelVPN",   "KEL",   {.uint64 = 0x1807202300000000}},
+    {"Backbone", "CELL",  {.uint64 = 0x0404202200000000}},
+    {"mileena",  "tMIL",  {.uint64 = 0x000000000000cccc}},
+    {"subzero",  "tCELL", {.uint64 = 0x000000000000acca}}
+};
+
+int dap_tx_create_compose(int argc, char ** argv);
+int dap_tx_create_xchange_compose(int argc, char ** argv);
+int dap_tx_cond_create_compose(int argc, char ** argv);
+int dap_cli_hold_compose(int a_argc, char **a_argv);
+int dap_cli_take_compose(int a_argc, char **a_argv);
+int dap_cli_voting_compose(int a_argc, char **a_argv);
+dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer);
+dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
+                                                        const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num);
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,const char *a_token_sell, 
+                                                        uint256_t a_datoshi_sell, uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet);
+static dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
+                                                                const char *a_native_ticker, const char *a_net_name);
+dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name,
+        dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
+        const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+        uint256_t a_value, uint256_t a_value_per_unit_max,
+        dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
+        uint256_t a_value_fee, const void *a_cond,
+        size_t a_cond_size, const char *a_hash_out_type);
+bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee);
+bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count);
+dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
+                                                    const char *a_main_ticker,
+                                                    uint256_t a_value, uint256_t a_value_fee,
+                                                    dap_time_t a_time_staking, uint256_t a_reinvest_percent,
+                                                    const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * l_chain_id_str);
+bool check_token_in_ledger(json_object *l_json_coins, const char *a_token);
+dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
+                                               dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
+                                               const char *a_main_ticker, uint256_t a_value,
+                                               uint256_t a_value_fee,
+                                               const char *a_delegated_ticker_str, uint256_t a_delegated_value);
+dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
+                              uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
+                              bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
+                              const char *a_net_str);
-- 
GitLab


From 1112c71b19b871ab35311dcc8f8b7a1450727a56 Mon Sep 17 00:00:00 2001
From: Konstantin <konstatin.kuharenko@demlabs.net>
Date: Mon, 24 Mar 2025 12:37:06 +0700
Subject: [PATCH 18/53] [*] link compose

---
 CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 22001f9388..a7908ac9a0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@ endif()
 if(NOT DEFINED CELLFRAME_MODULES)
     include (dap-sdk/cmake/OS_Detection.cmake)
 
-    set(CELLFRAME_MODULES "core chains mining network cs-dag-poa cs-esbocs cs-none srv-stake srv-voting srv-bridge srv-xchange srv-emit-delegate")
+    set(CELLFRAME_MODULES "core chains mining network cs-dag-poa cs-esbocs cs-none srv-stake srv-voting srv-bridge srv-xchange srv-emit-delegate compose")
 
     if(LINUX OR DARWIN)
         set(CELLFRAME_MODULES "${CELLFRAME_MODULES} srv-vpn")
-- 
GitLab


From 63817e695b823d2ee8364bf7cc5e2ce1f5f47049 Mon Sep 17 00:00:00 2001
From: Konstantin <konstatin.kuharenko@demlabs.net>
Date: Mon, 24 Mar 2025 14:52:52 +0700
Subject: [PATCH 19/53] [*] fix build wallet

---
 modules/net/srv/CMakeLists.txt                              | 2 +-
 modules/net/srv/{ => include}/dap_chain_net_srv_countries.h | 0
 modules/net/srv/{ => include}/dap_chain_net_srv_geoip.h     | 0
 3 files changed, 1 insertion(+), 1 deletion(-)
 rename modules/net/srv/{ => include}/dap_chain_net_srv_countries.h (100%)
 rename modules/net/srv/{ => include}/dap_chain_net_srv_geoip.h (100%)

diff --git a/modules/net/srv/CMakeLists.txt b/modules/net/srv/CMakeLists.txt
index d48b0f9a3b..818863316a 100644
--- a/modules/net/srv/CMakeLists.txt
+++ b/modules/net/srv/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
 project (dap_chain_net_srv)
 
 file(GLOB DAP_CHAIN_NET_SRV_SRCS *.c)
-file(GLOB DAP_CHAIN_NET_SRV_HEADERS *.h)
+file(GLOB DAP_CHAIN_NET_SRV_HEADERS include/*.h)
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_SRCS} ${DAP_CHAIN_NET_SRV_HEADERS})
 
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/libmaxminddb ${CMAKE_CURRENT_BINARY_DIR}/../../../3rdparty/libmaxminddb)
diff --git a/modules/net/srv/dap_chain_net_srv_countries.h b/modules/net/srv/include/dap_chain_net_srv_countries.h
similarity index 100%
rename from modules/net/srv/dap_chain_net_srv_countries.h
rename to modules/net/srv/include/dap_chain_net_srv_countries.h
diff --git a/modules/net/srv/dap_chain_net_srv_geoip.h b/modules/net/srv/include/dap_chain_net_srv_geoip.h
similarity index 100%
rename from modules/net/srv/dap_chain_net_srv_geoip.h
rename to modules/net/srv/include/dap_chain_net_srv_geoip.h
-- 
GitLab


From 9cc1644961e32d1728282cd5414ce6a38ba2d226 Mon Sep 17 00:00:00 2001
From: Konstantin <konstatin.kuharenko@demlabs.net>
Date: Mon, 24 Mar 2025 15:31:16 +0700
Subject: [PATCH 20/53] [*] more fix

---
 modules/chain/include/dap_chain_policy.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/chain/include/dap_chain_policy.h b/modules/chain/include/dap_chain_policy.h
index 883e8469c5..5ef6f54dd2 100644
--- a/modules/chain/include/dap_chain_policy.h
+++ b/modules/chain/include/dap_chain_policy.h
@@ -104,6 +104,6 @@ DAP_STATIC_INLINE const char *dap_chain_policy_to_str(dap_chain_policy_t *a_poli
  */
 DAP_STATIC_INLINE bool dap_chain_policy_num_is_valid(uint64_t a_num)
 {
-    uint32_t l_num = dap_maxval(l_num);
+    uint32_t l_num = UINT32_MAX;
     return (a_num && a_num <= l_num);
 }
\ No newline at end of file
-- 
GitLab


From 5ab4733ae3c1d6fe040295961dee3953686546e3 Mon Sep 17 00:00:00 2001
From: Konstantin <konstatin.kuharenko@demlabs.net>
Date: Mon, 24 Mar 2025 17:39:26 +0700
Subject: [PATCH 21/53] [8] new fix

---
 modules/net/srv/include/dap_chain_net_srv.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/net/srv/include/dap_chain_net_srv.h b/modules/net/srv/include/dap_chain_net_srv.h
index c8b252b9af..cc697439b7 100755
--- a/modules/net/srv/include/dap_chain_net_srv.h
+++ b/modules/net/srv/include/dap_chain_net_srv.h
@@ -50,7 +50,7 @@ typedef struct {
 
 typedef struct dap_chain_net_srv_abstract
 {
-    uint8_t class; //Class of service (once or permanent)
+    uint8_t c; //Class of service (once or permanent)
     dap_chain_net_srv_uid_t type_id; //Type of service
     union {
         struct {
-- 
GitLab


From 78bed9171fb2ecaf6d20c8bfef5c237534469cfa Mon Sep 17 00:00:00 2001
From: Konstantin <konstatin.kuharenko@demlabs.net>
Date: Tue, 25 Mar 2025 13:25:11 +0700
Subject: [PATCH 22/53] [*] add extern C

---
 modules/compose/include/dap_chain_tx_compose.h           | 8 ++++++++
 .../service/voting/include/dap_chain_net_srv_voting.h    | 9 +++++++++
 2 files changed, 17 insertions(+)

diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 41c05c0e90..2e626778d0 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -58,6 +58,10 @@ static NetInfo netinfo[NET_COUNT] = {
     {"subzero",  "tCELL", {.uint64 = 0x000000000000acca}}
 };
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 int dap_tx_create_compose(int argc, char ** argv);
 int dap_tx_create_xchange_compose(int argc, char ** argv);
 int dap_tx_cond_create_compose(int argc, char ** argv);
@@ -95,3 +99,7 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
                               const char *a_net_str);
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h
index 70509562bd..7ec943e6c4 100644
--- a/modules/service/voting/include/dap_chain_net_srv_voting.h
+++ b/modules/service/voting/include/dap_chain_net_srv_voting.h
@@ -146,11 +146,20 @@ enum DAP_CHAIN_NET_VOTE_DUMP_ERROR{
     DAP_CHAIN_NET_VOTE_DUMP_MEMORY_ERR
 
 };
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wallet_t *a_wallet, dap_hash_fast_t a_hash,
                               uint64_t a_option_idx, dap_chain_net_t *a_net, const char *a_hash_out_type,
                               char **a_hash_tx_out);
 
 dap_list_t *dap_chain_net_vote_list(dap_chain_net_t *a_net);
+dap_list_t* dap_get_options_list_from_str(const char* a_str);
 dap_chain_net_vote_info_t *dap_chain_net_vote_extract_info(dap_chain_net_t *a_net, dap_hash_fast_t *a_vote_hash);
 void dap_chain_net_vote_info_free(dap_chain_net_vote_info_t *a_info);
 
+#if defined(__cplusplus)
+}
+#endif
+
-- 
GitLab


From 06dd70822ac46fb839c103b19406464e47160918 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Wed, 26 Mar 2025 13:06:07 +0700
Subject: [PATCH 23/53] [*] port all in sdk

---
 modules/compose/CMakeLists.txt                |    2 +-
 modules/compose/dap_chain_tx_compose.c        | 2089 +++++++++++++++--
 .../compose/include/dap_chain_tx_compose.h    |   33 +-
 .../service/voting/dap_chain_net_srv_voting.c |    5 -
 .../voting/include/dap_chain_net_srv_voting.h |    1 -
 5 files changed, 1877 insertions(+), 253 deletions(-)

diff --git a/modules/compose/CMakeLists.txt b/modules/compose/CMakeLists.txt
index 456054471c..82f0ea9189 100644
--- a/modules/compose/CMakeLists.txt
+++ b/modules/compose/CMakeLists.txt
@@ -6,7 +6,7 @@ file(GLOB DAP_CHAIN_COMPOSE_HEADERS include/*.h)
 
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_COMPOSE_SRCS} ${DAP_CHAIN_COMPOSE_HEADERS})
 
-target_link_libraries(${PROJECT_NAME} dap_cli_server dap_chain_net dap_chain_net_srv dap_enc_server dap_json_rpc dap_chain_net_srv_xchange dap_chain_net_srv_voting)
+target_link_libraries(${PROJECT_NAME} dap_cli_server dap_chain_net dap_chain_net_srv dap_enc_server dap_json_rpc dap_chain_net_srv_xchange dap_chain_net_srv_voting dap_app_cli dap_cli_server)
 target_include_directories(${PROJECT_NAME} PUBLIC include/ )
 target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../dap-sdk/3rdparty/json-c)
 
diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 3b035cf1ad..ce082f0782 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -29,9 +29,20 @@
 #include "dap_chain_datum_tx_voting.h"
 #include "dap_chain_net_srv_stake_lock.h"
 #include "dap_chain_net_srv_voting.h"
+#include "dap_chain_net_tx.h"
+#include "dap_net.h"
+#include "dap_app_cli.h"
+#include "dap_json_rpc.h"
+#include "dap_app_cli_net.h"
+#include "dap_cli_server.h"
 
-#include <curl/curl.h>
+#include <netdb.h>
+#include <json-c/json.h>
 
+static json_object* s_request_command_to_rpc(const char *request);
+
+
+const char *arg_wallets_path = NULL;
 
 static const char* s_get_native_ticker(const char* name) {
     for (int i = 0; i < NET_COUNT; i++) {
@@ -52,6 +63,251 @@ static dap_chain_net_id_t s_get_net_id(const char* name) {
     return empty_id;
 }
 
+
+int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add) {
+    json_object *items_array;
+    if (!json_object_object_get_ex(json_tx, "items", &items_array)) {
+        fprintf(stderr, "Failed to get 'items' array\n");
+        return 1;
+    }
+    json_object_array_add(items_array, json_add);
+    return 0;
+}
+
+
+static json_object* s_request_command_to_rpc(const char *request) {
+    struct addrinfo hints, *res = NULL, *p = NULL;
+    int sockfd = -1;
+    struct sockaddr_storage l_saddr = { };
+    char l_ip[INET6_ADDRSTRLEN] = { '\0' }; 
+    uint16_t l_port = 0;
+    char path[256] = "/";
+    json_object *response_json = NULL;
+    dap_json_rpc_response_t* response = NULL;
+
+    if (strchr(RPC_NODES_URL, ':') != NULL && strchr(RPC_NODES_URL, '/') == NULL) {
+        if (dap_net_parse_config_address(RPC_NODES_URL, l_ip, &l_port, &l_saddr, NULL) < 0) {
+            printf("Incorrect address \"%s\" format\n", RPC_NODES_URL);
+            return NULL;
+        }
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_family = AF_INET;
+        hints.ai_socktype = SOCK_STREAM;
+
+        char port_str[6];
+        snprintf(port_str, sizeof(port_str), "%u", l_port);
+
+        if (getaddrinfo(l_ip, port_str, &hints, &res) != 0) {
+            fprintf(stderr, "Failed to resolve IP address\n");
+            return NULL;
+        }
+    } else {
+        const char *host_start = strstr(RPC_NODES_URL, "://");
+        if (!host_start) {
+            fprintf(stderr, "Invalid URL format\n");
+            return NULL;
+        }
+        host_start += 3;  // Move past "://"
+
+        char host[256] = {0};
+        const char *path_start = strchr(host_start, '/');
+        size_t host_len = path_start ? (size_t)(path_start - host_start) : strlen(host_start);
+        if (host_len >= sizeof(host)) host_len = sizeof(host) - 1;
+        strncpy(host, host_start, host_len);
+        host[host_len] = '\0';  // Ensure null termination
+
+        printf("Extracted host: %s\n", host);  // Debugging output
+
+        struct addrinfo hints = {0}, *res = NULL;
+        hints.ai_family = AF_INET;
+        hints.ai_socktype = SOCK_STREAM;
+
+        if (getaddrinfo(host, "80", &hints, &res) != 0) {
+            fprintf(stderr, "Failed to resolve hostname: %s\n", host);
+            return NULL;
+        }
+    }
+
+    for (p = res; p != NULL; p = p->ai_next) {
+        sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+        if (sockfd == -1) continue;
+
+        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == 0) {
+            break;
+        }
+        
+        close(sockfd);
+        sockfd = -1;
+    }
+
+    freeaddrinfo(res);
+
+    if (sockfd == -1) {
+        fprintf(stderr, "Failed to connect to host\n");
+        return NULL;
+    }
+
+    char http_request[1024];
+    snprintf(http_request, sizeof(http_request),
+             "POST %s HTTP/1.1\r\n"
+             "Host: %s\r\n"
+             "Content-Type: application/json\r\n"
+             "Content-Length: %zu\r\n"
+             "Connection: close\r\n\r\n"
+             "%s",
+             path, l_ip, strlen(request), request);
+
+    if (send(sockfd, http_request, strlen(http_request), 0) < 0) {
+        fprintf(stderr, "Failed to send request\n");
+        close(sockfd);
+        return NULL;
+    }
+
+    dap_app_cli_cmd_state_t cmd = {
+        .cmd_res = DAP_NEW_Z_SIZE(char, MAX_RESPONSE_SIZE),
+        .cmd_res_cur = 0,
+        .hdr_len = 0  // Ensure this is initialized
+    };
+
+    if (!cmd.cmd_res) {
+        fprintf(stderr, "Memory allocation failed\n");
+        close(sockfd);
+        return NULL;
+    }
+
+    int l_status = 1;
+    while (l_status > 0) {
+        l_status = dap_app_cli_http_read(sockfd, &cmd, l_status);
+    }
+    
+    close(sockfd);
+
+    response = dap_json_rpc_response_from_string(cmd.cmd_res + cmd.hdr_len);
+    DAP_DELETE(cmd.cmd_res);
+
+    if (!response) {
+        return NULL;
+    }
+
+    response_json = response->result_json_object;
+    json_object_get(response_json);  // Prevent early free
+
+    json_object *errors_array;
+    if (json_object_is_type(response_json, json_type_array) && json_object_array_length(response_json) > 0) {
+        json_object *first_element = json_object_array_get_idx(response_json, 0);
+        if (json_object_object_get_ex(first_element, "errors", &errors_array)) {
+            int errors_len = json_object_array_length(errors_array);
+            for (int j = 0; j < errors_len; j++) {
+                json_object *error_obj = json_object_array_get_idx(errors_array, j);
+                json_object *error_code, *error_message;
+                if (json_object_object_get_ex(error_obj, "code", &error_code) &&
+                    json_object_object_get_ex(error_obj, "message", &error_message)) {
+                    printf("Error %d: %s\n", json_object_get_int(error_code), json_object_get_string(error_message));
+                }
+            }
+            json_object_put(response_json);  // Free memory
+            response_json = NULL;
+        }
+    }
+
+    dap_json_rpc_response_free(response);
+    return response_json;
+}
+
+
+bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee) {
+    char data[512];
+    snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name);
+    json_object *l_json_get_fee = s_request_command_to_rpc(data);
+    if (!l_json_get_fee) {
+        return false;
+    }
+
+    json_object *l_first_result = json_object_array_get_idx(l_json_get_fee, 0);
+    if (!l_first_result || !json_object_is_type(l_first_result, json_type_object)) {
+        json_object_put(l_json_get_fee);
+        return false;
+    }
+
+    json_object *l_fees = NULL;
+    if (!json_object_object_get_ex(l_first_result, "fees", &l_fees) || 
+        !json_object_is_type(l_fees, json_type_object)) {
+        json_object_put(l_json_get_fee);
+        return false;
+    }
+
+    json_object *l_network = NULL;
+    if (!json_object_object_get_ex(l_fees, "network", &l_network) || 
+        !json_object_is_type(l_network, json_type_object)) {
+        json_object_put(l_json_get_fee);
+        return false;
+    }
+
+    json_object *l_balance = NULL;
+    if (!json_object_object_get_ex(l_network, "balance", &l_balance) || 
+        !json_object_is_type(l_balance, json_type_string)) {
+        json_object_put(l_json_get_fee);
+        return false;
+    }
+    *a_net_fee = dap_chain_balance_scan(json_object_get_string(l_balance));
+
+    json_object *l_addr = NULL;
+    if (!json_object_object_get_ex(l_network, "addr", &l_addr) || 
+        !json_object_is_type(l_addr, json_type_string)) {
+        json_object_put(l_json_get_fee);
+        return false;
+    }
+    *l_addr_fee = dap_chain_addr_from_str(json_object_get_string(l_addr));
+
+    json_object_put(l_json_get_fee);
+    return true;
+}
+
+bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count) {
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
+            dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name);
+    json_object *l_json_outs = s_request_command_to_rpc(data);
+    if (!l_json_outs) {
+        return false;
+    }
+
+    if (!json_object_is_type(l_json_outs, json_type_array)) {
+        json_object_put(l_json_outs);
+        return false;
+    }
+
+    if (json_object_array_length(l_json_outs) == 0) {
+        json_object_put(l_json_outs);
+        return false;
+    }
+
+    json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0);
+    if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) {
+        json_object_put(l_json_outs);
+        return false;
+    }
+
+    json_object *l_first_item = json_object_array_get_idx(l_first_array, 0);
+    if (!l_first_item) {
+        json_object_put(l_json_outs);
+        return false;
+    }
+
+    if (!json_object_object_get_ex(l_first_item, "outs", l_outs) ||
+        !json_object_is_type(*l_outs, json_type_array)) {
+        json_object_put(l_json_outs);
+        return false;
+    }
+
+    *l_outputs_count = json_object_array_length(*l_outs);
+    json_object_get(*l_outs);
+    json_object_put(l_json_outs); // Clean up the JSON object
+    return true;
+}
+
+
 int dap_tx_create_xchange_compose(int argc, char ** argv) {
     int arg_index = 1;
     const char *l_net_name = NULL;
@@ -62,6 +318,21 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) {
     const char *l_rate_str = NULL;
     const char *l_fee_str = NULL;
 
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        arg_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
+    } else {
+        arg_wallets_path = dap_strdup(l_wallet_path);
+    }
+
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_sell", &l_token_sell);
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_buy", &l_token_buy);
@@ -105,7 +376,7 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) {
         return -1;
     }
 
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, c_wallets_path, NULL);
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, arg_wallets_path, NULL);
     if(!l_wallet) {
         printf("wallet %s does not exist", l_wallet_name);
         return -1;
@@ -141,15 +412,6 @@ int dap_tx_create_compose(int argc, char ** argv) {
     const char * l_token_ticker = NULL;
     const char * l_net_name = NULL;
     const char * l_chain_name = NULL;
-    const char * l_emission_chain_name = NULL;
-    const char * l_tx_num_str = NULL;
-    const char *l_emission_hash_str = NULL;
-    const char *l_cert_str = NULL;
-    dap_cert_t *l_cert = NULL;
-    dap_enc_key_t *l_priv_key = NULL;
-    dap_chain_hash_fast_t l_emission_hash = {};
-    size_t l_tx_num = 0;
-    dap_chain_wallet_t * l_wallet_fee = NULL;
 
     const char * l_hash_out_type = NULL;
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type);
@@ -160,6 +422,21 @@ int dap_tx_create_compose(int argc, char ** argv) {
         return -1;
     }
 
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        arg_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
+    } else {
+        arg_wallets_path = dap_strdup(l_wallet_path);
+    }
+
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
     if (!l_net_name) {
         printf("tx_create requires parameter '-net'");
@@ -174,11 +451,6 @@ int dap_tx_create_compose(int argc, char ** argv) {
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name);
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-wallet_fee", &l_wallet_fee_name);
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-tx_num", &l_tx_num_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str);
-
-    if(l_tx_num_str)
-        l_tx_num = strtoul(l_tx_num_str, NULL, 10);
 
     // Validator's fee
     if (dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) {
@@ -206,18 +478,19 @@ int dap_tx_create_compose(int argc, char ** argv) {
 
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to);
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp);
-    if (!addr_base58_to) {
-        printf("tx_create requires parameter '-to_addr'");
-        return -5;
-    }
+
     if (!str_tmp) {
         printf("tx_create requires parameter '-value' to be valid uint256 value");
         return -6;
     }
-    l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1;
     l_value_el_count = dap_str_symbol_count(str_tmp, ',') + 1;
 
-    if (l_addr_el_count != l_value_el_count) {
+    if (addr_base58_to)
+        l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1;
+    else 
+        l_addr_el_count = l_value_el_count;
+
+    if (addr_base58_to && l_addr_el_count != l_value_el_count) {
         printf("num of '-to_addr' and '-value' should be equal");
         return -5;
     }
@@ -243,32 +516,34 @@ int dap_tx_create_compose(int argc, char ** argv) {
     }
     DAP_DELETE(l_value_array);
 
-    l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count);
-    if (!l_addr_to) {
-        printf("Can't allocate memory");
-        DAP_DELETE(l_value);
-        return -9;
-    }
-    char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count);
-    if (!l_addr_base58_to_array) {
-        DAP_DEL_MULTY(l_addr_to, l_value);
-        printf("Can't read '-to_addr' arg");
-        return -10;
-    }
-    for (size_t i = 0; i < l_addr_el_count; ++i) {
-        l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]);
-        if(!l_addr_to[i]) {
-            for (size_t j = 0; j < i; ++j) {
-                DAP_DELETE(l_addr_to[j]);
+    if (addr_base58_to) {
+        l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count);
+        if (!l_addr_to) {
+            printf("Can't allocate memory");
+            DAP_DELETE(l_value);
+            return -9;
+        }
+        char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count);
+        if (!l_addr_base58_to_array) {
+            DAP_DEL_MULTY(l_addr_to, l_value);
+            printf("Can't read '-to_addr' arg");
+            return -10;
+        }
+        for (size_t i = 0; i < l_addr_el_count; ++i) {
+            l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]);
+            if(!l_addr_to[i]) {
+                for (size_t j = 0; j < i; ++j) {
+                    DAP_DELETE(l_addr_to[j]);
+                }
+                DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value);
+                printf("destination address is invalid");
+                return -11;
             }
-            DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value);
-            printf("destination address is invalid");
-            return -11;
         }
+        DAP_DELETE(l_addr_base58_to_array);
     }
-    DAP_DELETE(l_addr_base58_to_array);
     
-    dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, c_wallets_path, NULL);
+    dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, arg_wallets_path, NULL);
     if(!l_wallet) {
         printf("Can't open wallet %s", l_from_wallet_name);
         return -12;
@@ -276,7 +551,7 @@ int dap_tx_create_compose(int argc, char ** argv) {
 
 
     dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name));
-    for (size_t i = 0; i < l_addr_el_count; ++i) {
+    for (size_t i = 0; l_addr_to && i < l_addr_el_count; ++i) {
         if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) {
             printf("The transaction cannot be directed to the same address as the source.");
             for (size_t j = 0; j < l_addr_el_count; ++j) {
@@ -288,8 +563,6 @@ int dap_tx_create_compose(int argc, char ** argv) {
     }
 
 
-
-    l_priv_key = dap_chain_wallet_get_key(l_wallet, 0);
     dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count);
 
     json_object * l_json_obj_ret = json_object_new_object();
@@ -301,124 +574,67 @@ int dap_tx_create_compose(int argc, char ** argv) {
     return 0;
 }
 
-bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee) {
-    char data[512];
-    snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name);
-    json_object *l_json_get_fee = request_command_to_rpc_by_curl(data);
-    if (!l_json_get_fee) {
-        return false;
-    }
-
-    json_object *l_first_result = json_object_array_get_idx(l_json_get_fee, 0);
-    if (!l_first_result || !json_object_is_type(l_first_result, json_type_object)) {
-        json_object_put(l_json_get_fee);
-        return false;
-    }
-
-    json_object *l_fees = NULL;
-    if (!json_object_object_get_ex(l_first_result, "fees", &l_fees) || 
-        !json_object_is_type(l_fees, json_type_object)) {
-        json_object_put(l_json_get_fee);
-        return false;
-    }
+int dap_chain_datum_tx_add_out_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value) {
+    if (IS_ZERO_256(a_value))
+        return -1;
+    
+    dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t);
+    if (!l_item)
+        return -1;
+    
+    l_item->header.type = TX_ITEM_TYPE_OUT;
+    l_item->header.value = a_value;
+    
+    int res = dap_chain_datum_tx_add_item(a_tx, l_item);
+    DAP_DELETE(l_item);
+    
+    return res;
+}
 
-    json_object *l_network = NULL;
-    if (!json_object_object_get_ex(l_fees, "network", &l_network) || 
-        !json_object_is_type(l_network, json_type_object)) {
-        json_object_put(l_json_get_fee);
-        return false;
-    }
 
-    json_object *l_balance = NULL;
-    if (!json_object_object_get_ex(l_network, "balance", &l_balance) || 
-        !json_object_is_type(l_balance, json_type_string)) {
-        json_object_put(l_json_get_fee);
-        return false;
-    }
-    *a_net_fee = dap_chain_balance_scan(json_object_get_string(l_balance));
+int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value, const char *a_token)
+{
+    if (!a_token || IS_ZERO_256(a_value))
+        return -1;
 
-    json_object *l_addr = NULL;
-    if (!json_object_object_get_ex(l_network, "addr", &l_addr) || 
-        !json_object_is_type(l_addr, json_type_string)) {
-        json_object_put(l_json_get_fee);
-        return false;
-    }
-    *l_addr_fee = dap_chain_addr_from_str(json_object_get_string(l_addr));
+    dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t);
+    if (!l_item)
+        return -2;
+    l_item->header.type = TX_ITEM_TYPE_OUT_EXT;
+    l_item->header.value = a_value;
+    dap_strncpy((char*)l_item->token, a_token, sizeof(l_item->token) - 1);
 
-    json_object_put(l_json_get_fee);
-    return true;
+    int result = dap_chain_datum_tx_add_item(a_tx, l_item);
+    DAP_DELETE(l_item);
+    return result;
 }
 
-bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count) {
-    char data[512];
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
-            dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name);
-    json_object *l_json_outs = request_command_to_rpc_by_curl(data);
-    if (!l_json_outs) {
-        return false;
+
+dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
+        const char* a_token_ticker,
+        uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num)
+{
+    if (!a_addr_from || !a_token_ticker || !a_value) {
+        return NULL;
     }
 
-    if (!json_object_is_type(l_json_outs, json_type_array)) {
-        json_object_put(l_json_outs);
-        return false;
+    if (dap_chain_addr_check_sum(a_addr_from)) {
+        return NULL;
     }
 
-    if (json_object_array_length(l_json_outs) == 0) {
-        json_object_put(l_json_outs);
-        return false;
+    for (size_t i = 0; i < a_tx_num; ++i) {
+        // if (!a_addr_to || !a_addr_to[i]) {
+        //     return NULL;
+        // }
+        if (a_addr_to && dap_chain_addr_check_sum(a_addr_to[i])) {
+            return NULL;
+        }
+        if (IS_ZERO_256(a_value[i])) {
+            return NULL;
+        }
     }
-
-    json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0);
-    if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) {
-        json_object_put(l_json_outs);
-        return false;
-    }
-
-    json_object *l_first_item = json_object_array_get_idx(l_first_array, 0);
-    if (!l_first_item) {
-        json_object_put(l_json_outs);
-        return false;
-    }
-
-    if (!json_object_object_get_ex(l_first_item, "outs", l_outs) ||
-        !json_object_is_type(*l_outs, json_type_array)) {
-        json_object_put(l_json_outs);
-        return false;
-    }
-
-    *l_outputs_count = json_object_array_length(*l_outs);
-    json_object_get(*l_outs);
-    json_object_put(l_json_outs); // Clean up the JSON object
-    return true;
-}
-
-
-dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
-        const char* a_token_ticker,
-        uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num)
-{
-    if (!a_addr_from || !a_token_ticker || !a_value || !a_tx_num) {
-        return NULL;
-    }
-
-    if (dap_chain_addr_check_sum(a_addr_from)) {
-        return NULL;
-    }
-
-    for (size_t i = 0; i < a_tx_num; ++i) {
-        if (!a_addr_to || !a_addr_to[i]) {
-            return NULL;
-        }
-        if (dap_chain_addr_check_sum(a_addr_to[i])) {
-            return NULL;
-        }
-        if (IS_ZERO_256(a_value[i])) {
-            return NULL;
-        }
-    }
-    const char * l_native_ticker = s_get_native_ticker(l_net_name);
-    bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker);
+    const char * l_native_ticker = s_get_native_ticker(l_net_name);
+    bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker);
 
     uint256_t l_value_transfer = {}; // how many coins to transfer
     uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {};
@@ -486,12 +702,18 @@ dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name,
     if (l_single_channel) { // add 'out' items
         uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
         for (size_t i = 0; i < a_tx_num; ++i) {
-            if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) == 1) {
-                SUM_256_256(l_value_pack, a_value[i], &l_value_pack);
+            if (a_addr_to) {
+                if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    return NULL;
+                }
             } else {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
+                if (dap_chain_datum_tx_add_out_without_addr(&l_tx, a_value[i]) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    return NULL;
+                }
             }
+                SUM_256_256(l_value_pack, a_value[i], &l_value_pack);
         }
         // Network fee
         if (l_net_fee_used) {
@@ -522,9 +744,16 @@ dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name,
         }
     } else { // add 'out_ext' items
         for (size_t i = 0; i < a_tx_num; ++i) {
-            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
+            if (a_addr_to) {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    return NULL;
+                }
+            } else {
+                if (dap_chain_datum_tx_add_out_ext_item_without_addr(&l_tx, a_value[i], a_token_ticker) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    return NULL;
+                }
             }
         }
         // coin back
@@ -703,7 +932,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name);
-    json_object *l_json_coins = request_command_to_rpc_by_curl(data);
+    json_object *l_json_coins = s_request_command_to_rpc(data);
     if (!l_json_coins) {
         return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS
     }
@@ -717,7 +946,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net
             "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
             dap_chain_addr_to_str(l_wallet_addr), a_net_name);
     DAP_DEL_Z(l_wallet_addr);
-    json_object *l_json_outs = request_command_to_rpc_by_curl(data);
+    json_object *l_json_outs = s_request_command_to_rpc(data);
     uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell);
 
     uint256_t l_value_sell = a_datoshi_sell;
@@ -753,7 +982,7 @@ json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_n
     snprintf(data, sizeof(data), 
             "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
             dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name);
-    json_object *l_json_outs = request_command_to_rpc_by_curl(data);
+    json_object *l_json_outs = s_request_command_to_rpc(data);
     if (!l_json_outs) {
         return NULL;
     }
@@ -792,7 +1021,7 @@ json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_n
 }
 
 
-static dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
+dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
                                                                  const char *a_native_ticker, const char *a_net_name)
 {
     if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) {
@@ -934,16 +1163,6 @@ static dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net
             }
         }
     }
-
-    // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
-    // // add 'sign' item
-    // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
-    //     dap_chain_datum_tx_delete(l_tx);
-    //     dap_enc_key_delete(l_seller_key);
-    //     printf("Can't add sign output\n");
-    //     return NULL;
-    // }
-    // dap_enc_key_delete(l_seller_key);
     return l_tx;
 }
 
@@ -961,13 +1180,20 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
     const char * l_srv_uid_str = NULL;
     uint256_t l_value_datoshi = {};    
     uint256_t l_value_fee = {};
-    const char * l_hash_out_type = NULL;
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type);
-    if(!l_hash_out_type)
-        l_hash_out_type = "hex";
-    if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) {
-        printf("Invalid parameter -H, valid values: -H <hex | base58>\n");
-        return -1;
+
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        arg_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
+    } else {
+        arg_wallets_path = dap_strdup(l_wallet_path);
     }
 
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
@@ -1038,7 +1264,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
         return -13;
     }
 
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path, NULL);
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL);
     if(!l_wallet) {
         printf("Can't open wallet '%s'\n", l_wallet_str);
         return -15;
@@ -1063,7 +1289,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
     uint256_t l_value_per_unit_max = {};
     dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker,
                                                         l_value_datoshi, l_value_per_unit_max, l_price_unit,
-                                                        l_srv_uid, l_value_fee, NULL, 0, l_hash_out_type);
+                                                        l_srv_uid, l_value_fee, NULL, 0);
     
     json_object * l_json_obj_ret = json_object_new_object();
     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
@@ -1083,7 +1309,7 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net
         uint256_t a_value, uint256_t a_value_per_unit_max,
         dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
         uint256_t a_value_fee, const void *a_cond,
-        size_t a_cond_size, const char *a_hash_out_type)
+        size_t a_cond_size)
 {
     // check valid param
     if (!a_net_name || !a_key_from || !a_key_cond ||
@@ -1114,17 +1340,10 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net
     if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count)) {
         return NULL;
     }
-    dap_list_t *l_list_used_out = NULL;
-    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+    dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
                                                             l_value_need,
                                                             &l_value_transfer);
     json_object_put(l_outs);
-
-
-    // dap_list_t *l_list_used_out = NULL;
-    // if (dap_chain_wallet_cache_tx_find_outs_with_val(l_ledger->net, a_token_ticker, &l_addr_from, &l_list_used_out, l_value_need, &l_value_transfer) == -101)
-    //     l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_token_ticker,
-    //                                         &l_addr_from, l_value_need, &l_value_transfer);
     if(!l_list_used_out) {
         printf("Nothing to transfer (not enough funds)\n");
         return NULL;
@@ -1179,19 +1398,6 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net
         }
     }
 
-    // // add 'sign' items
-    // if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) {
-    //     dap_chain_datum_tx_delete(l_tx);
-    //     printf("Can't add sign output\n");
-    //     return NULL;
-    // }
-    // size_t l_tx_size = dap_chain_datum_tx_get_size( l_tx );
-    // dap_chain_datum_t *l_datum = dap_chain_datum_create( DAP_CHAIN_DATUM_TX, l_tx, l_tx_size );
-    // dap_chain_datum_tx_delete(l_tx);
-    // dap_chain_t *l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX);
-    // char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, a_hash_out_type);
-    // DAP_DELETE(l_datum);
-
     return l_tx;
 }
 
@@ -1203,7 +1409,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
             *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL,
             *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL;
 
-    const char *l_wallets_path								=	c_wallets_path;
+    const char *l_wallets_path								=	arg_wallets_path;
     char 	l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
     dap_time_t              			l_time_staking		=	0;
     uint256_t						    l_reinvest_percent	=	{};
@@ -1214,6 +1420,21 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
     dap_chain_wallet_t					*l_wallet;
     dap_chain_addr_t					*l_addr_holder;
 
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        arg_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
+    } else {
+        arg_wallets_path = dap_strdup(l_wallet_path);
+    }
+
 
     const char *l_hash_out_type = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
@@ -1237,7 +1458,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name);
-    json_object *l_json_coins = request_command_to_rpc_by_curl(data);
+    json_object *l_json_coins = s_request_command_to_rpc(data);
     if (!l_json_coins) {
         return -4;
     }
@@ -1371,7 +1592,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
         dap_chain_addr_to_str(l_addr_holder), l_net_name);
     DAP_DEL_Z(l_addr_holder);
 
-    json_object *l_json_outs = request_command_to_rpc_by_curl(data);
+    json_object *l_json_outs = s_request_command_to_rpc(data);
     uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str);
     json_object_put(l_json_outs);
     if (compare256(l_value_balance, l_value) == -1) {
@@ -1558,17 +1779,6 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_nam
     }
 
     return l_tx;
-    // // add 'sign' item
-    // if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) {
-    //     dap_chain_datum_tx_delete(l_tx);
-    //     printf("Error: Can't add sign output\n");
-    //     return NULL;
-    // }
-
-    // size_t l_tx_size = dap_chain_datum_tx_get_size( l_tx );
-    // dap_chain_datum_t *l_datum = dap_chain_datum_create( DAP_CHAIN_DATUM_TX, l_tx, l_tx_size );
-
-    // return l_datum;
 }
 
 
@@ -1587,6 +1797,21 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
     dap_enc_key_t						*l_owner_key;
 
 
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        arg_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
+    } else {
+        arg_wallets_path = dap_strdup(l_wallet_path);
+    }
+
     const char *l_hash_out_type = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
     if (!l_hash_out_type)
@@ -1622,7 +1847,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
             l_tx_str, l_net_str);
     
-    json_object *response = request_command_to_rpc_by_curl(data);
+    json_object *response = s_request_command_to_rpc(data);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return -15;
@@ -1709,7 +1934,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
         return -15;
     }
 
-    if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path, NULL))) {
+    if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL))) {
         printf("Error: Unable to open wallet\n");
         return -16;
     }
@@ -1742,7 +1967,6 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
     return 0;
 }
 
-
 dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
                                                dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
                                                const char *a_main_ticker, uint256_t a_value,
@@ -1903,6 +2127,7 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_na
 
     return l_tx;
 }
+
 uint256_t s_get_key_delegating_min_value(const char *a_net_str){
     uint256_t l_key_delegating_min_value = uint256_0;
     char data[512];
@@ -1910,7 +2135,7 @@ uint256_t s_get_key_delegating_min_value(const char *a_net_str){
             "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", 
             a_net_str);
     
-    json_object *response = request_command_to_rpc_by_curl(data);
+    json_object *response = s_request_command_to_rpc(data);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return l_key_delegating_min_value;
@@ -1960,6 +2185,22 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
     const char* l_fee_str = NULL;
     const char* l_wallet_str = NULL;
     const char* l_net_str = NULL;
+    const char* l_token_str = NULL;
+
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        arg_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
+    } else {
+        arg_wallets_path = dap_strdup(l_wallet_path);
+    }
     
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
     // Select chain network
@@ -2025,13 +2266,34 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
 
     bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false;
     bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false;
-    dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, c_wallets_path,NULL);
+    dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL);
     if (!l_wallet_fee) {
         printf("Wallet %s does not exist\n", l_wallet_str);
         return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
     }
 
-    dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net_str);
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str);
+    if (!l_token_str) {
+        printf("Command required -token argument");
+        return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
+    }
+        
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str);
+    json_object *l_json_coins = s_request_command_to_rpc(data);
+    if (!l_json_coins) {
+        printf("Error: Can't get ledger coins list\n");
+        return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
+    }
+    if (!check_token_in_ledger(l_json_coins, l_token_str)) {
+        json_object_put(l_json_coins);
+        printf("Token %s does not exist\n", l_token_str);
+        return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN;
+    }
+    json_object_put(l_json_coins);
+
+    dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net_str, l_token_str);
     dap_list_free(l_options_list);
     dap_chain_wallet_close(l_wallet_fee);
     json_object * l_json_obj_ret = json_object_new_object();
@@ -2045,7 +2307,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
 dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
-                              const char *a_net_str) {
+                              const char *a_net_str, const char *a_token_ticker) {
 
     if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
         return NULL;
@@ -2169,6 +2431,15 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question,
         dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item);
         DAP_DEL_Z(l_vote_changing_item);
     }
+    if (a_token_ticker) {
+        dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker);
+        if (!l_voting_token_item) {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item);
+        DAP_DEL_Z(l_voting_token_item);
+    }
 
     // add 'in' items
     uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
@@ -2207,3 +2478,1367 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question,
     return l_tx;
 }
 
+/**
+int dap_cli_vote_compose(int a_argc, char **a_argv){
+    const char* l_cert_name = NULL;
+    const char* l_fee_str = NULL;
+    const char* l_wallet_str = NULL;
+    const char* l_hash_str = NULL;
+    const char* l_option_idx_str = NULL;
+    const char* l_net_str = NULL;
+    int arg_index = 1;
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
+    if(!l_net_str) {
+        printf("command requires parameter '-net'\n");
+        return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING;
+    } 
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hash", &l_hash_str);
+    if(!l_hash_str){
+        printf("Command 'vote' require the parameter -hash\n");
+        return -DAP_CHAIN_NET_VOTE_VOTING_HASH_NOT_FOUND;
+    }
+
+    dap_hash_fast_t l_voting_hash = {};
+    if (dap_chain_hash_fast_from_str(l_hash_str, &l_voting_hash)) {
+        printf("Hash string is not recognozed as hex of base58 hash\n");
+        return -DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID;
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_name);
+    dap_cert_t * l_cert = dap_cert_find_by_name(l_cert_name);
+    if (l_cert_name){
+        if (l_cert == NULL) {
+            printf("Can't find \"%s\" certificate\n", l_cert_name);
+            return -DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_FIND_CERT;
+        }
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str);
+    if (!l_fee_str){
+        printf("Command 'vote' requires paramete -fee to be valid.\n");
+        return -DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_NOT_VALID;
+    }
+    uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str);
+    if (IS_ZERO_256(l_value_fee)) {
+        printf("command requires parameter '-fee' to be valid uint256\n");            
+        return -DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_BAD_TYPE;
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str);
+    if (!l_wallet_str){
+        printf("Command 'vote' requires parameter -w to be valid.\n");
+        return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_PARAM_NOT_VALID;
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-option_idx", &l_option_idx_str);
+    if (!l_option_idx_str){
+        printf("Command 'vote' requires parameter -option_idx to be valid.\n");
+        return -DAP_CHAIN_NET_VOTE_VOTING_OPTION_IDX_PARAM_NOT_VALID;
+    }
+
+    const char *arg_wallets_path = dap_chain_wallet_get_path(g_config);
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path,NULL);
+    if (!l_wallet) {
+        printf("Wallet %s does not exist\n", l_wallet_str);
+        return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST;
+    }
+
+    uint64_t l_option_idx_count = strtoul(l_option_idx_str, NULL, 10);
+
+    char *l_hash_tx;
+
+    int res = dap_chain_net_vote_voting_compose(l_cert, l_value_fee, l_wallet, l_voting_hash, l_option_idx_count,
+                                        l_net_str, &l_hash_tx);
+    dap_chain_wallet_close(l_wallet);
+
+    return res;
+}
+
+
+int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wallet_t *a_wallet, dap_hash_fast_t a_hash,
+                              uint64_t a_option_idx, const char *a_net_str, const char *a_hash_out_type,
+                              char **a_hash_tx_out) {
+    const char * l_hash_str = dap_chain_hash_fast_to_str_static(&a_hash);
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"voting\",\"params\": [\"voting;dump;-hash;%s\"],\"id\": \"2\"}", l_hash_str);
+    json_object *l_json_voting = s_request_command_to_rpc(data);
+    if (!l_json_voting) {
+        printf("Error: Can't get voting info\n");
+        return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
+    }
+
+    
+    json_object *l_voting_info = json_object_array_get_idx(l_json_voting, 0);
+    if (!l_voting_info) {
+        printf("Error: Can't get voting info from JSON\n");
+        return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
+    }
+
+    const char *l_voting_tx = json_object_get_string(json_object_object_get(l_voting_info, "voting_tx"));
+    const char *l_expiration_str = json_object_get_string(json_object_object_get(l_voting_info, "expiration"));
+    const char *l_status = json_object_get_string(json_object_object_get(l_voting_info, "status"));
+    int l_votes_max = json_object_get_int(json_object_object_get(l_voting_info, "votes_max"));
+    int l_votes_available = json_object_get_int(json_object_object_get(l_voting_info, "votes_available"));
+    bool l_vote_changed = json_object_get_boolean(json_object_object_get(l_voting_info, "can_change_status"));
+    bool l_delegated_key_required = json_object_get_boolean(json_object_object_get(l_voting_info, "delegated_key_required"));
+
+    json_object *l_results = json_object_object_get(l_voting_info, "results");
+    if (!l_results) {
+        printf("Error: Can't get results from JSON\n");
+        return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
+    }
+
+    int l_results_count = json_object_array_length(l_results);
+
+
+    if (l_votes_max && l_votes_max <= l_results_count)
+        return DAP_CHAIN_NET_VOTE_VOTING_THIS_VOTING_HAVE_MAX_VALUE_VOTES;
+
+    if (l_expiration_str) {
+        struct tm tm;
+        strptime(l_expiration_str, "%a, %d %b %Y %H:%M:%S %z", &tm);
+        time_t l_expiration_time = mktime(&tm);
+        if (l_expiration_time && dap_time_now() > l_expiration_time)
+            return DAP_CHAIN_NET_VOTE_VOTING_ALREADY_EXPIRED;
+    }
+
+    dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str));
+    if (!l_addr_from)
+        return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID;
+
+    dap_hash_fast_t l_pkey_hash = {0};
+    if (l_delegated_key_required) {
+        if (!a_cert)
+            return DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED;
+        if (dap_cert_get_pkey_hash(a_cert, &l_pkey_hash))
+            return DAP_CHAIN_NET_VOTE_VOTING_NO_KEY_FOUND_IN_CERT;
+        char data[512];
+        snprintf(data, sizeof(data), 
+                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str);
+        json_object *l_json_coins = s_request_command_to_rpc(data);
+        if (!l_json_coins) {
+            printf("Error: Failed to retrieve coins from ledger\n");
+            return -4;
+        }
+        const char * l_hash_fast_str[DAP_HASH_FAST_STR_SIZE] = {};
+        dap_chain_hash_fast_from_str(l_hash_fast_str, &l_pkey_hash);
+        if (!l_hash_fast_str) {
+            printf("Error: Can't covert l_pkey_hash to str");
+            return -5;
+        }
+        int items_count = json_object_array_length(l_json_coins);
+        bool found = false;
+        for (int i = 0; i < items_count; i++) {
+            json_object *item = json_object_array_get_idx(l_json_coins, i);
+            const char *pkey_hash_str = json_object_get_string(json_object_object_get(item, "pkey_hash"));
+            if (l_hash_fast_str && !dap_strcmp(l_hash_fast_str, pkey_hash_str)) {
+                const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash"));
+                if (dap_chain_hash_fast_from_str(tx_hash_str, &l_pkey_hash)) {
+                    printf("Invalid transaction hash format\n");
+                    return DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED;
+                }
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            printf("Specified certificate/pkey hash is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n");
+            return -9;
+        }
+
+
+    } else
+        l_pkey_hash = l_addr_from->data.hash_fast;
+
+
+    const char *l_token_ticker = json_object_get_string(json_object_object_get(l_voting_info, "token"));
+    uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer;
+    dap_chain_addr_t* l_addr_fee = NULL;
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee);
+    if (l_net_fee_used)
+        SUM_256_256(l_net_fee, a_fee, &l_total_fee);
+
+    bool l_native_tx = !dap_strcmp(l_token_ticker, s_get_native_ticker(a_net_str));
+
+    json_object *l_outs = NULL;
+    int l_outputs_count = 0;
+    if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_token_ticker, a_net_str, &l_outs, &l_outputs_count)) {
+        return -11;
+    }
+
+    dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                            l_total_fee,
+                                                            &l_value_transfer);
+    json_object_put(l_outs);
+    if (!l_list_used_out) {
+        printf("Not enough funds to transfer");
+        return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER;
+    }
+
+    // check outputs UTXOs
+    uint256_t l_value_transfer_new = {};
+    dap_list_t *it, *tmp;
+    DL_FOREACH_SAFE(l_list_used_out, it, tmp) {
+        dap_chain_tx_used_out_item_t *l_out = (dap_chain_tx_used_out_item_t *)it->data;
+        if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out,
+                                               l_vote_changed ? &l_pkey_hash : NULL)) {
+            l_list_used_out = dap_list_delete_link(l_list_used_out, it);
+            continue;
+        }
+        if (SUM_256_256(l_value_transfer_new, l_out->value, &l_value_transfer_new))
+            return DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW;
+    }
+
+    if (IS_ZERO_256(l_value_transfer_new) || (l_native_tx && compare256(l_value_transfer_new, l_total_fee) <= 0))
+        return DAP_CHAIN_NET_VOTE_VOTING_UNSPENT_UTX0_FOR_PARTICIPATION_THIS_VOTING;
+
+    l_value_transfer = l_value_transfer_new;
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
+    uint256_t l_value_back = l_value_transfer, l_fee_back = {};
+    if (!l_native_tx) {
+        dap_list_t *l_list_fee_outs = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_net->pub.native_ticker, l_addr_from, l_total_fee, &l_fee_transfer);
+        if (!l_list_fee_outs) {
+            dap_chain_datum_tx_delete(l_tx);
+            return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER;
+        }
+        uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_outs);
+        assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+        dap_list_free_full(l_list_fee_outs, NULL);
+        SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_back);
+    } else
+        SUBTRACT_256_256(l_value_transfer, l_total_fee, &l_value_back);
+
+    // add 'in' items
+    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+    assert(EQUAL_256(l_value_to_items, l_value_transfer));
+    dap_list_free_full(l_list_used_out, NULL);
+
+    // Add vote item
+    if (a_option_idx > dap_list_length(l_voting->voting_params.option_offsets_list)){
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_INVALID_OPTION_INDEX;
+    }
+    dap_chain_tx_vote_t* l_vote_item = dap_chain_datum_tx_item_vote_create(&a_hash, &a_option_idx);
+    if(!l_vote_item){
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_VOTE_ITEM;
+    }
+    dap_chain_datum_tx_add_item(&l_tx, l_vote_item);
+    DAP_DEL_Z(l_vote_item);
+
+    // add out conds items
+    dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from);
+    for (dap_list_t *it = l_outs; it; it = it->next) {
+        dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data;
+        if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out,
+                                                  l_vote_changed ? &l_pkey_hash : NULL) != 0)
+            continue;
+        dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out);
+        if(!l_item){
+            dap_chain_datum_tx_delete(l_tx);
+
+            dap_list_free_full(l_outs, NULL);
+            return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_TSD_TX_COND_ITEM;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_item);
+        DAP_DEL_Z(l_item);
+    }
+    dap_list_free_full(l_outs, NULL);
+
+    // Network fee
+    if (l_net_fee_used && dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, a_net->pub.native_ticker) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT;
+    }
+
+    // Validator's fee
+    if (!IS_ZERO_256(a_fee) && dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT;
+    }
+
+    // coin back
+    if (!IS_ZERO_256(l_value_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_token_ticker) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
+    }
+    if (!IS_ZERO_256(l_fee_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_fee_back, a_net->pub.native_ticker) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
+    }
+
+    dap_enc_key_t *l_priv_key = dap_chain_wallet_get_key(a_wallet, 0);
+    // add 'sign' items with wallet sign
+    if (dap_chain_datum_tx_add_sign_item(&l_tx, l_priv_key) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        dap_enc_key_delete(l_priv_key);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX;
+    }
+    dap_enc_key_delete(l_priv_key);
+
+    // add 'sign' items with delegated key if needed
+    if (a_cert && dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX;
+    }
+
+    size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
+    dap_hash_fast_t l_tx_hash;
+    dap_hash_fast(l_tx, l_tx_size, &l_tx_hash);
+    dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, l_tx_size);
+    DAP_DELETE(l_tx);
+    dap_chain_t* l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX);
+
+    char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, a_hash_out_type);
+    DAP_DELETE(l_datum);
+    if (l_ret) {
+        *a_hash_tx_out = l_ret;
+        return DAP_CHAIN_NET_VOTE_VOTING_OK;
+    } else {
+        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_POOL_IN_MEMPOOL;
+    }
+}
+
+*/
+
+
+/**
+static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
+{
+    const char *l_net_str = NULL,
+               *l_wallet_str = NULL,
+               *l_cert_str = NULL,
+               *l_fee_str = NULL,
+               *l_tx_hash_str = NULL,
+               *l_poa_cert_str = NULL,
+               *l_signing_pkey_hash_str = NULL,
+               *l_signing_pkey_type_str = NULL;
+    int l_arg_index = 1;
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
+    if (!l_net_str) {
+        printf("Command 'invalidate' requires parameter -net\n");
+        return -1;
+    }
+
+    uint256_t l_fee = {};
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
+    if (!l_wallet_str) {
+        dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-poa_cert", &l_poa_cert_str);
+        if (!l_poa_cert_str) {
+            printf("Command 'invalidate' requires parameter -w or -poa_cert\n");
+            return -1;
+        }
+    } else {
+        dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
+        if (!l_fee_str) {
+            printf("Command 'delegate' requires parameter -fee\n");
+            return -1;
+        }
+        l_fee = dap_chain_balance_scan(l_fee_str);
+        if (IS_ZERO_256(l_fee)) {
+            printf("Unrecognized number in '-fee' param\n");
+            return -1;
+        }
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tx", &l_tx_hash_str);
+    if (!l_tx_hash_str) {
+        dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str);
+        if (!l_cert_str) {
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-signing_pkey_hash", &l_signing_pkey_hash_str);
+            if (!l_signing_pkey_hash_str) {
+                printf("Command 'invalidate' requires parameter -tx or -cert or -signing_pkey_hash\n");
+                return -1;
+            }
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-signing_pkey_type", &l_signing_pkey_type_str);
+            if (!l_signing_pkey_type_str) {
+                printf("Command 'invalidate' requires parameter -signing_pkey_type\n");
+                return -1;
+            }
+            if (dap_sign_type_from_str(l_signing_pkey_type_str).type == SIG_TYPE_NULL) {
+                printf("Invalid signing_pkey_type %s\n", l_signing_pkey_type_str);
+                return -3;
+            }
+        }
+    }
+
+    dap_hash_fast_t l_tx_hash = {};
+    if (l_tx_hash_str) {
+        dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash);
+    } else {
+        dap_chain_addr_t l_signing_addr;
+        if (l_cert_str) {
+            dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str);
+            if (!l_cert) {
+                printf("Specified certificate not found\n");
+                return -4;
+            }
+            if (!l_cert->enc_key->priv_key_data || l_cert->enc_key->priv_key_data_size == 0) {
+                printf("It is not possible to invalidate a stake using a public key.\n");
+                return -5;
+            }
+            if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, s_get_net_id(l_net_str))) {
+                printf("Specified certificate is wrong\n");
+                return -6;
+            }
+        } else {
+            dap_hash_fast_t l_pkey_hash = {};
+            if (dap_chain_hash_fast_from_str(l_signing_pkey_hash_str, &l_pkey_hash)) {
+                printf("Invalid pkey hash format\n");
+                return -7;
+            }
+            dap_chain_addr_fill(&l_signing_addr, dap_sign_type_from_str(l_signing_pkey_type_str), &l_pkey_hash, s_get_net_id(l_net_str));
+        }
+
+        
+        char data[512];
+        snprintf(data, sizeof(data), 
+                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", l_net_str);
+        json_object *l_json_coins = s_request_command_to_rpc(data);
+        if (!l_json_coins) {
+            printf("Error: Failed to retrieve coins from ledger\n");
+            return -4;
+        }
+        
+        int items_count = json_object_array_length(l_json_coins);
+        bool found = false;
+        for (int i = 0; i < items_count; i++) {
+            json_object *item = json_object_array_get_idx(l_json_coins, i);
+            const char *pkey_hash_str = json_object_get_string(json_object_object_get(item, "pkey_hash"));
+            if (l_signing_pkey_hash_str && !dap_strcmp(l_signing_pkey_hash_str, pkey_hash_str)) {
+                const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash"));
+                if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) {
+                    printf("Invalid transaction hash format\n");
+                    return -8;
+                }
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            printf("Specified certificate/pkey hash is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n");
+            return -9;
+        }
+    }
+
+    const char *l_tx_hash_str_tmp = l_tx_hash_str ? l_tx_hash_str : dap_hash_fast_to_str_static(&l_tx_hash);
+
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str);
+    json_object *l_json_response = s_request_command_to_rpc(data);
+    if (!l_json_response) {
+        printf("Error: Failed to retrieve transaction info from ledger\n");
+        return -4;
+    }
+
+    json_object *l_json_items = json_object_object_get(l_json_response, "ITEMS");
+    bool has_delegate_out = false;
+    if (l_json_items) {
+        int items_count = json_object_array_length(l_json_items);
+        for (int i = 0; i < items_count; i++) {
+            json_object *item = json_object_array_get_idx(l_json_items, i);
+            const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+            if (item_type && strcmp(item_type, "OUT COND") == 0) {
+                const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+                if (subtype && strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE") == 0) {
+                    has_delegate_out = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (!has_delegate_out) {
+        printf("Transaction %s does not have a delegate out\n", l_tx_hash_str_tmp);
+        return -11;
+    }
+
+    json_object *l_json_spents = json_object_object_get(l_json_response, "Spent OUTs");
+    if (l_json_spents) {
+        int spents_count = json_object_array_length(l_json_spents);
+        for (int i = 0; i < spents_count; i++) {
+            json_object *spent_item = json_object_array_get_idx(l_json_spents, i);
+            const char *spent_by_tx = json_object_get_string(json_object_object_get(spent_item, "is spent by tx"));
+            if (spent_by_tx) {
+                if (dap_chain_hash_fast_from_str(spent_by_tx, &l_tx_hash)) {
+                    printf("Invalid transaction hash format in response\n");
+                    return -8;
+                }
+                l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash);
+                snprintf(data, sizeof(data), 
+                        "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str);
+                json_object *l_json_prev_tx = s_request_command_to_rpc(data);
+                if (!l_json_prev_tx) {
+                    printf("Previous transaction %s is not found\n", l_tx_hash_str_tmp);
+                    return -12;
+                }
+                break; 
+            }
+        }
+    }
+
+    if (l_tx_hash_str) {
+        char data[512];
+        snprintf(data, sizeof(data), 
+                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", l_net_str);
+        json_object *l_json_coins = s_request_command_to_rpc(data);
+        if (!l_json_coins) {
+            printf("Error: Failed to retrieve coins from ledger\n");
+            return -4;
+        }
+
+        bool tx_exists = false;
+        int tx_count = json_object_array_length(l_json_coins);
+        for (int i = 0; i < tx_count; i++) {
+            json_object *tx_item = json_object_array_get_idx(l_json_items, i);
+            const char *tx_hash = json_object_get_string(json_object_object_get(tx_item, "tx_hash"));
+            if (tx_hash && strcmp(tx_hash, l_tx_hash_str_tmp) == 0) {
+                printf("Error: Transaction %s already exists in the ledger\n", l_tx_hash_str_tmp);
+                return -13;
+            }
+        }
+    }
+    dap_chain_datum_tx_t *l_tx = NULL;
+    if (l_wallet_str) {
+        const char* l_sign_str = "";
+        dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config),NULL);
+        if (!l_wallet) {
+            printf("Specified wallet not found\n");
+            return -14;
+        } else {
+            l_sign_str = dap_chain_wallet_check_sign(l_wallet);
+        }
+        dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
+        l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key);
+        dap_chain_wallet_close(l_wallet);
+        dap_enc_key_delete(l_enc_key);
+    } else {
+        dap_cert_t *l_poa_cert = dap_cert_find_by_name(l_poa_cert_str);
+        if (!l_poa_cert) {
+            printf("Specified certificate not found\n");
+            return -4;
+        }
+        if (!s_srv_stake_is_poa_cert(l_net, l_poa_cert->enc_key)) {
+            printf("Specified certificate is not PoA root one\n");
+            return -16;
+        }
+        dap_chain_datum_decree_t *l_decree = s_stake_decree_invalidate(l_net, &l_tx_hash, l_poa_cert);
+        char *l_decree_hash_str = NULL;
+        if (l_decree && (l_decree_hash_str = s_stake_decree_put(l_decree, l_net))) {
+            json_object* l_json_object_invalidate = json_object_new_object();
+            json_object_object_add(l_json_object_invalidate, "status", json_object_new_string("success"));
+            json_object_object_add(l_json_object_invalidate, "decree", json_object_new_string(l_decree_hash_str));
+            json_object_object_add(l_json_object_invalidate, "message", json_object_new_string("Specified delegated key invalidated. Try to execute this command with -w to return m-tokens to owner"));
+            json_object_array_add(*a_json_arr_reply, l_json_object_invalidate);
+            DAP_DELETE(l_decree);
+            DAP_DELETE(l_decree_hash_str);
+        } else {
+            char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
+            dap_chain_hash_fast_to_str(&l_tx, l_tx_hash_str, sizeof(l_tx_hash_str));
+            printf("Can't invalidate transaction %s, examine log files for details\n", l_tx_hash_str);
+            DAP_DEL_Z(l_decree);
+            return -15;
+        }
+    }
+    return 0;
+}
+
+dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key)
+{
+
+
+    dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
+    if (!l_cond_tx) {
+        printf("Requested conditional transaction not found\n");
+        return NULL;
+    }
+    int l_prev_cond_idx = 0;
+    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx,
+                                                  DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_prev_cond_idx);
+    if (!l_tx_out_cond) {
+        printf("Requested conditional transaction requires conditional output\n");
+        return NULL;
+    }
+    dap_hash_fast_t l_spender_hash = { };
+    if (dap_ledger_tx_hash_is_used_out_item(l_ledger, a_tx_hash, l_prev_cond_idx, &l_spender_hash)) {
+        char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
+        dap_chain_hash_fast_to_str(&l_spender_hash, l_hash_str, sizeof(l_hash_str));
+        printf("Requested conditional transaction is already used out by %s\n", l_hash_str);
+        return NULL;
+    }
+    dap_chain_tx_in_cond_t *l_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(l_cond_tx, NULL, NULL, TX_ITEM_TYPE_IN_COND, NULL);
+    if (l_in_cond) {
+        l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, &l_in_cond->header.tx_prev_hash);
+        if (!l_cond_tx) {
+            printf("Requested conditional transaction is unchained\n");
+            return NULL;
+        }
+    }
+    // Get sign item
+    dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(l_cond_tx, NULL, NULL,
+            TX_ITEM_TYPE_SIG, NULL);
+    // Get sign from sign item
+    // TODO Can't get sign from sign item required new command for remote node
+    dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
+    dap_chain_addr_t l_owner_addr;
+    dap_chain_addr_fill_from_sign(&l_owner_addr, l_sign, s_get_net_id(a_net_str));
+    dap_chain_addr_t l_wallet_addr;
+    dap_chain_addr_fill_from_key(&l_wallet_addr, a_key, s_get_net_id(a_net_str));
+    if (!dap_chain_addr_compare(&l_owner_addr, &l_wallet_addr)) {
+        printf("Trying to invalidate delegating tx with not a owner wallet\n");
+        return NULL;
+    }
+    const char *l_native_ticker = s_get_native_ticker(a_net_str);
+    const char *l_delegated_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, a_tx_hash);
+    uint256_t l_fee_transfer = {}; // how many coins to transfer
+    // list of transaction with 'out' items to sell
+    uint256_t l_net_fee, l_fee_total = a_fee;
+    dap_chain_addr_t l_net_fee_addr;
+    bool l_net_fee_used = dap_chain_net_tx_get_fee(a_net->pub.id, &l_net_fee, &l_net_fee_addr);
+    if (l_net_fee_used)
+        SUM_256_256(l_fee_total, l_net_fee, &l_fee_total);
+    dap_list_t *l_list_fee_out = NULL; 
+    if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101)
+        l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker,
+                                                                            &l_owner_addr, l_fee_total, &l_fee_transfer);
+    if (!l_list_fee_out) {
+        printf("Nothing to pay for fee (not enough funds)\n");
+        return NULL;
+    }
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
+    // add 'in' item to buy from conditional transaction
+    dap_chain_datum_tx_add_in_cond_item(&l_tx, a_tx_hash, l_prev_cond_idx, 0);
+
+    // add 'in' items to pay fee
+    uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+    dap_list_free_full(l_list_fee_out, NULL);
+    if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
+        printf("Can't compose the transaction input\n");
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+
+    // add 'out_ext' item
+    if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_tx_out_cond->header.value, l_delegated_ticker) == -1) {
+        dap_chain_datum_tx_delete(l_tx);
+        printf("Cant add returning coins output\n");
+        return NULL;
+    }
+    // add fee items
+    if (l_net_fee_used) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+    }
+    if (!IS_ZERO_256(a_fee)) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+    }
+    // fee coin back
+    uint256_t l_fee_back = {};
+    SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back);
+    if(!IS_ZERO_256(l_fee_back)) {
+        if(dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+    }
+    // add 'sign' items
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        printf("Can't add sign output\n");
+        return NULL;
+    }
+    return l_tx;
+}
+*/
+
+// dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){
+//     dap_chain_net_srv_order_t* l_order = NULL;
+//     json_object *orders_array = json_object_array_get_idx(response, 0);
+//     size_t orders_count = json_object_array_length(orders_array);
+//     for (size_t i = 0; i < orders_count; i++) {
+//         json_object *order_obj = json_object_array_get_idx(orders_array, i);
+//         const char *order_hash_str = json_object_get_string(json_object_object_get(order_obj, "order"));
+
+//         if (strcmp(order_hash_str, l_order_hash_str) == 0) {
+//             l_order = DAP_NEW_Z_SIZE(dap_chain_net_srv_order_t, sizeof(dap_chain_net_srv_order_t));
+//             l_order->version = json_object_get_int(json_object_object_get(order_obj, "version"));
+//             l_order->direction = dap_chain_net_srv_order_direction_from_str(json_object_get_string(json_object_object_get(order_obj, "direction")));
+//             l_order->ts_created = dap_time_from_str(json_object_get_string(json_object_object_get(order_obj, "created")));
+//             l_order->srv_uid.uint64 = dap_chain_net_srv_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "srv_uid"))).uint64;
+//             l_order->price = dap_uint256_scan_uninteger(json_object_get_string(json_object_object_get(order_obj, "price datoshi")));
+//             strncpy(l_order->price_ticker, json_object_get_string(json_object_object_get(order_obj, "price token")), DAP_CHAIN_TICKER_SIZE_MAX);
+//             l_order->units = json_object_get_int(json_object_object_get(order_obj, "units"));
+//             l_order->price_unit = dap_chain_net_srv_price_unit_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "price unit")));
+//             dap_chain_node_addr_from_str(&l_order->node_addr, json_object_get_string(json_object_object_get(order_obj, "node_addr")));
+//             dap_chain_hash_fast_from_str(&l_order->tx_cond_hash, json_object_get_string(json_object_object_get(order_obj, "tx_cond_hash")));
+//             l_order->ext_size = json_object_get_int(json_object_object_get(order_obj, "ext_size"));
+//             if (l_order->ext_size > 0) {
+//                 const char *tax_str = json_object_get_string(json_object_object_get(order_obj, "tax"));
+//                 const char *value_max_str = json_object_get_string(json_object_object_get(order_obj, "maximum_value"));
+//                 *a_tax = dap_uint256_scan_decimal(tax_str);
+//                 *a_value_max = dap_uint256_scan_decimal(value_max_str);
+//             }
+
+//             json_object *conditional_tx_params = json_object_object_get(order_obj, "conditional_tx_params");
+//             if (conditional_tx_params) {
+//                 const char *sovereign_tax_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_tax"));
+//                 const char *sovereign_addr_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_addr"));
+//                 *a_sovereign_tax = dap_uint256_scan_decimal(sovereign_tax_str);
+//                 a_sovereign_addr = dap_chain_addr_from_str(sovereign_addr_str);
+//             }
+//             break;
+//         }
+//     }
+//     return l_order;
+// }
+
+// dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax){
+//     char data[512];
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", 
+//             l_net_str);
+//     json_object *response = s_request_command_to_rpc(data);
+//     if (!response) {
+//         printf("Error: Failed to get response from remote node\n");
+//         return NULL;
+//     }
+
+//     dap_chain_net_srv_order_t *l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response);
+//     json_object_put(response);
+
+//     if (!l_order) {
+//         snprintf(data, sizeof(data), 
+//                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", 
+//                 l_net_str);
+//         response = s_request_command_to_rpc(data);
+//         if (!response) {
+//             printf("Error: Failed to get response from remote node\n");
+//             return NULL;
+//         }
+//         l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response);
+//         json_object_put(response);
+//     }
+//     return l_order;
+// }
+
+
+
+
+// static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
+// {
+//     int l_arg_index = 0;
+//     const char *l_net_str = NULL,
+//                *l_wallet_str = NULL,
+//                *l_cert_str = NULL,
+//                *l_pkey_str = NULL,
+//                *l_pkey_full_str = NULL,
+//                *l_sign_type_str = NULL,
+//                *l_value_str = NULL,
+//                *l_fee_str = NULL,
+//                *l_node_addr_str = NULL,
+//                *l_order_hash_str = NULL;
+    
+//     dap_pkey_t *l_pkey = NULL;
+//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-net", &l_net_str);
+//     if (!l_net_str) {
+//         printf("Command 'delegate' requires parameter -net\n");
+//         return -1;
+//     }
+
+//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-w", &l_wallet_str);
+//     if (!l_wallet_str) {
+//         printf("Command 'delegate' requires parameter -w\n");
+//         return -1;
+//     }
+//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL);
+//     if (!l_wallet) {
+//         printf("Specified wallet not found\n");
+//         return -2;
+//     }
+//     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
+//     dap_chain_wallet_close(l_wallet);
+//     dap_chain_addr_t l_signing_addr, l_sovereign_addr = {};
+//     uint256_t l_sovereign_tax = uint256_0;
+//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-cert", &l_cert_str);
+//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str);
+//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-sign_type", &l_sign_type_str);
+//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-order", &l_order_hash_str);
+//     if (!l_cert_str && !l_order_hash_str && !l_pkey_full_str) {
+//         printf("Command 'delegate' requires parameter -cert and/or -order and/or -pkey\n");
+//         dap_enc_key_delete(l_enc_key);
+//         return -1;
+//     }
+//     if (l_pkey_full_str) {
+//         printf("Command 'delegate' requires only one, -pkey or -pkey_full\n");
+//         dap_enc_key_delete(l_enc_key);
+//         return -1;
+//     }
+//     if (( l_pkey_full_str) && !l_sign_type_str) {
+//         printf("Command 'delegate' requires parameter -sign_type for pkey\n");
+//         dap_enc_key_delete(l_enc_key);
+//         return -1;
+//     }
+//     uint256_t l_value = uint256_0;
+//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-value", &l_value_str);
+//     if (!l_value_str) {
+//         if (!l_order_hash_str) {
+//             printf("Command 'delegate' requires parameter -value\n");
+//             dap_enc_key_delete(l_enc_key);
+//             return -1;
+//         }
+//     } else {
+//         l_value = dap_chain_balance_scan(l_value_str);
+//         if (IS_ZERO_256(l_value)) {
+//             printf("Unrecognized number in '-value' param\n");
+//             dap_enc_key_delete(l_enc_key);
+//             return -1;
+//         }
+//     }
+//     dap_chain_datum_tx_t *l_prev_tx = NULL;
+//     if (l_cert_str) {
+//         dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str);
+//         if (!l_signing_cert) {
+//             printf("Specified certificate not found\n");
+//             dap_enc_key_delete(l_enc_key);
+//             return -3;
+//         }
+//         if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(l_net_str))) {
+//             printf("Specified certificate is wrong\n");
+//             dap_enc_key_delete(l_enc_key);
+//             return -4;
+//         }
+//         l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key);
+//         dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
+//     } 
+//     else if (l_pkey_full_str) {
+//         dap_sign_type_t l_type = dap_sign_type_from_str(l_sign_type_str);
+//         if (l_type.type == SIG_TYPE_NULL) {
+//             printf("Wrong sign type\n");
+//             dap_enc_key_delete(l_enc_key);
+//             return -5;
+//         }
+//         l_pkey = dap_pkey_get_from_str(l_pkey_full_str);
+//         if (!l_pkey) {
+//             printf("Invalid pkey string format, can't get pkey_full\n");
+//             dap_enc_key_delete(l_enc_key);
+//             return -6;
+//         }
+//         if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) {
+//             printf("pkey and sign types is different\n");
+//             dap_enc_key_delete(l_enc_key);
+//             return -6;
+//         }
+//         dap_chain_hash_fast_t l_hash_public_key = {0};
+//         if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) {
+//             printf("Invalid pkey hash format\n");
+//             dap_enc_key_delete(l_enc_key);
+//             return -6;
+//         }
+//         dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(l_net_str));
+//         dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
+//     }
+
+//     dap_chain_node_addr_t l_node_addr = g_node_addr;
+//     if (l_node_addr_str) {
+//         if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) {
+//             printf("Unrecognized node addr %s\n", l_node_addr_str);
+//             dap_enc_key_delete(l_enc_key);
+//             return -7;
+//         }
+//     }
+//     if (l_order_hash_str) {
+
+//         uint256_t l_tax;
+//         uint256_t l_value_max;
+//         int l_prev_tx_count = 0;
+//         dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax);
+
+//         if (l_order->direction == SERV_DIR_BUY) { // Staker order
+//             if (!l_cert_str) {
+//                 printf("Command 'delegate' requires parameter -cert with this order type\n");
+//                 dap_enc_key_delete(l_enc_key);
+//                 return -1;
+//             }
+//             if (l_order->ext_size != 0) {
+//                 printf("Specified order has invalid size\n");
+//                 dap_enc_key_delete(l_enc_key);
+//                 DAP_DELETE(l_order);
+//                 return -9;
+//             }
+
+//             dap_chain_tx_out_cond_t *l_cond_tx = NULL;
+//             char data[512];
+//             snprintf(data, sizeof(data), 
+//                     "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+//                     l_order->tx_cond_hash, l_net_str);
+            
+//             json_object *response = s_request_command_to_rpc(data);
+//             if (!response) {
+//                 printf("Error: Failed to get response from remote node\n");
+//                 return -15;
+//             }
+            
+//             json_object *items = json_object_object_get(response, "ITEMS");
+//             if (!items) {
+//                 printf("Error: No items found in response\n");
+//                 return -16;
+//             }
+//             int items_count = json_object_array_length(items);
+//             for (int i = 0; i < items_count; i++) {
+//                 json_object *item = json_object_array_get_idx(items, i);
+//                 const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+//                 if (dap_strcmp(item_type, "OUT COND") == 0) {
+//                     const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+//                     if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE")) {
+//                         l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+//                         l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+//                         l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+//                         l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE;
+//                         l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+//                         l_cond_tx->header.ts_expires = dap_time_from_str(json_object_get_string(json_object_object_get(item, "ts_expires")));
+//                         l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr")));
+//                         if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) {
+//                             printf("Error: Failed to parse signer node address\n");
+//                             return -17;
+//                         }
+//                         l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
+//                         l_prev_tx_count++;
+//                         break;
+//                     }
+//                 } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) {
+//                     l_prev_tx_count++;
+//                 }
+//             }
+//             if (!l_cond_tx) {
+//                 printf("Error: No transaction output condition found\n");
+//                 return -7;
+//             }
+
+//             json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
+//             const char *spent_outs_value = json_object_get_string(spent_outs);
+//             if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
+//                 printf("Error: Transaction output item already used\n");
+//                 return -9;
+//             }
+
+
+
+//             // l_prev_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash);
+//             // if (!l_prev_tx) {
+//             //     printf("The order's conditional transaction not found in ledger\n");
+//             //     dap_enc_key_delete(l_enc_key);
+//             //     DAP_DELETE(l_order);
+//             //     return -10;
+//             // }
+//             // int l_out_num = 0;
+//             // dap_chain_tx_out_cond_t *l_cond_tx = dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
+//             // if (!l_cond) {
+//             //     printf("The order's conditional transaction has invalid type\n");
+//             //     dap_enc_key_delete(l_enc_key);
+//             //     DAP_DELETE(l_order);
+//             //     return -11;
+//             // }
+//             // if (dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_order->tx_cond_hash, l_out_num, NULL)) {
+//             //     printf("The order's conditional transaction is already spent\n");
+//             //     dap_enc_key_delete(l_enc_key);
+//             //     DAP_DELETE(l_order);
+//             //     return -12;
+//             // }
+
+//             char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+//             dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(l_net_str));
+//             const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker"));
+//             if (!l_token_ticker) {
+//                 printf("Error: Token ticker not found in response\n");
+//                 return -18;
+//             }
+//             json_object_put(response);
+//             if (dap_strcmp(l_token_ticker, l_delegated_ticker)) {
+//                 printf("Requested conditional transaction have another ticker (not %s)\n", l_delegated_ticker);
+//                 return -13;
+//             }
+//             if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) {
+//                 printf("The order's conditional transaction has invalid format\n");
+//                 dap_enc_key_delete(l_enc_key);
+//                 DAP_DELETE(l_order);
+//                 return -14;
+//             }
+//             if (compare256(l_cond_tx->header.value, l_order->price)) {
+//                 printf("The order's conditional transaction has different value\n");
+//                 dap_enc_key_delete(l_enc_key);
+//                 DAP_DELETE(l_order);
+//                 return -15;
+//             }
+//             if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) ||
+//                     l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) {
+//                 printf("The order's conditional transaction gas not blank address or key\n");
+//                 dap_enc_key_delete(l_enc_key);
+//                 DAP_DELETE(l_order);
+//                 return -16;
+//             }
+//             l_value = l_order->price;
+//             // dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR);
+//             // l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE);
+//             // l_sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t);
+//             // MULT_256_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
+//         }
+//         /** TODO add new command to get l_pkey from order
+//          * else {
+//             if (!l_value_str) {
+//                 printf("Command 'delegate' requires parameter -value with this order type\n");
+//                 dap_enc_key_delete(l_enc_key);
+//                 return -1;
+//             }
+//             const char *l_sovereign_addr_str = NULL;
+//             dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str);
+//             if (l_sovereign_addr_str) {
+//                 dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str);
+//                 if (!l_spec_addr) {
+//                     printf("Specified address is ivalid\n");
+//                     return -17;
+//                 }
+//                 l_sovereign_addr = *l_spec_addr;
+//                 DAP_DELETE(l_spec_addr);
+//             } else
+//                 dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, s_get_net_id(l_net_str));
+
+//             if (l_order_hash_str && compare256(l_value, l_order->price) == -1) {
+//                 const char *l_coin_min_str, *l_value_min_str =
+//                     dap_uint256_to_char(l_order->price, &l_coin_min_str);
+//                 printf("Number in '-value' param %s is lower than order minimum allowed value %s(%s)\n",
+//                                                   l_value_str, l_coin_min_str, l_value_min_str);
+//                 dap_enc_key_delete(l_enc_key);
+//                 return -18;
+//             }
+//             if (l_order_hash_str && compare256(l_value, l_value_max) == 1) {
+//                 const char *l_coin_max_str, *l_value_max_str =
+//                     dap_uint256_to_char(l_value_max, &l_coin_max_str);
+//                 printf("Number in '-value' param %s is higher than order minimum allowed value %s(%s)\n",
+//                                                   l_value_str, l_coin_max_str, l_value_max_str);
+//                 dap_enc_key_delete(l_enc_key);
+//                 return -19;
+//             }
+//             dap_sign_t *l_sign = (dap_sign_t *)(l_order->ext_n_sign + l_order->ext_size);
+//             if (l_sign->header.type.type == SIG_TYPE_NULL) {
+//                 printf("Specified order is unsigned\n");
+//                 dap_enc_key_delete(l_enc_key);
+//                 DAP_DELETE(l_order);
+//                 return -20;
+//             }
+//             dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_net->pub.id);
+//             l_pkey = dap_pkey_get_from_sign(l_sign);
+//             char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX];
+//             dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_net->pub.native_ticker);
+//             if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) {
+//                 printf("Specified order is invalid\n");
+//                 dap_enc_key_delete(l_enc_key);
+//                 DAP_DELETE(l_order);
+//                 return -21;
+//             }
+//             l_node_addr = l_order->node_addr;
+//         }
+//         DAP_DELETE(l_order);
+//         if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 ||
+//                 compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) {
+//             printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n");
+//             dap_enc_key_delete(l_enc_key);
+//             return -22;
+//         }
+//         DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
+//     }
+//     */
+//     if (!l_pkey) {
+//         printf("pkey not defined\n");
+//         dap_enc_key_delete(l_enc_key);
+//         return -6;
+//     }
+
+//     int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr);
+//     if (l_check_result) {
+//         printf("Key and node verification error\n");
+//         dap_enc_key_delete(l_enc_key);
+//         return l_check_result;
+//     }
+ 
+
+//     uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str);
+//     if (compare256(l_value, l_allowed_min) == -1) {
+//         const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str);
+//         printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n",
+//                                           l_value_str, l_coin_min_str, l_value_min_str);
+//         dap_enc_key_delete(l_enc_key);
+//         return -23;
+//     }
+//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-fee", &l_fee_str);
+//     if (!l_fee_str) {
+//         printf("Command 'delegate' requires parameter -fee\n");
+//         dap_enc_key_delete(l_enc_key);
+//         return -1;
+//     }
+//     uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+//     if (IS_ZERO_256(l_fee)) {
+//         printf("Unrecognized number in '-fee' param\n");
+//         dap_enc_key_delete(l_enc_key);
+//         return -1;
+//     }
+
+//     // Create conditional transaction
+//     dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr,
+//                                                    l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_prev_tx_count, l_pkey);
+//     dap_enc_key_delete(l_enc_key);
+//     DAP_DELETE(l_pkey);
+
+//     DAP_DELETE(l_tx);
+
+//     return 0;
+
+// }
+
+// // Freeze staker's funds when delegating a key
+// dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc_key_t *a_key,
+//                                                uint256_t a_value, uint256_t a_fee,
+//                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
+//                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
+//                                                dap_chain_datum_tx_t *a_prev_tx, int l_prev_tx_count, dap_pkey_t *a_pkey)
+// {
+//     dap_return_val_if_pass (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr, NULL);
+
+//     const char *l_native_ticker = s_get_native_ticker(a_net_str);
+//     char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+//     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker);
+//     uint256_t l_value_transfer = {}, l_fee_transfer = {}; // how many coins to transfer
+//     // list of transaction with 'out' items to sell
+//     dap_chain_addr_t l_owner_addr;
+//     dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str));
+//     uint256_t l_net_fee, l_fee_total = a_fee;
+//     dap_chain_addr_t l_net_fee_addr;
+//     bool l_net_fee_used = get_remote_net_fee(a_net_str, l_native_ticker, &l_net_fee, &l_net_fee_addr);
+//     if (l_net_fee_used)
+//         SUM_256_256(l_fee_total, l_net_fee, &l_fee_total);
+
+//     dap_list_t *l_list_fee_out = NULL;
+//     if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101)
+//         l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker,
+//                                                                       &l_owner_addr, l_fee_total, &l_fee_transfer);
+//     if (!l_list_fee_out) {
+//         log_it(L_WARNING, "Nothing to pay for fee (not enough funds)");
+//         return NULL;
+//     }
+
+//     // create empty transaction
+//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
+//     if (!a_prev_tx) {
+//         dap_list_t *l_list_used_out = NULL  ;
+//         if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_delegated_ticker, &l_owner_addr, &l_list_used_out, a_value, &l_value_transfer) == -101)
+//             l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_delegated_ticker,
+//                                                                            &l_owner_addr, a_value, &l_value_transfer);
+//         if (!l_list_used_out) {
+//             log_it(L_WARNING, "Nothing to pay for delegate (not enough funds)");
+//             goto tx_fail;
+//         }
+//         // add 'in' items to pay for delegate
+//         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+//         dap_list_free_full(l_list_used_out, NULL);
+//         if (!EQUAL_256(l_value_to_items, l_value_transfer)) {
+//             log_it(L_ERROR, "Can't compose the transaction input");
+//             goto tx_fail;
+//         }
+//     } else {
+//         dap_hash_fast_t l_prev_tx_hash;
+//         dap_hash_fast(a_prev_tx, dap_chain_datum_tx_get_size(a_prev_tx), &l_prev_tx_hash);
+//         int l_out_num = 0;
+//         dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
+//         // add 'in' item to buy from conditional transaction
+//         if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_prev_tx_count, -1)) {
+//             log_it(L_ERROR, "Can't compose the transaction conditional input");
+//             goto tx_fail;
+//         }
+//     }
+//     // add 'in' items to pay fee
+//     uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+//     dap_list_free_full(l_list_fee_out, NULL);
+//     if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
+//         log_it(L_ERROR, "Can't compose the fee transaction input");
+//         goto tx_fail;
+//     }
+
+//     // add 'out_cond' & 'out_ext' items
+//     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID };
+//     dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_value, a_signing_addr, a_node_addr,
+//                                                                                           a_sovereign_addr, a_sovereign_tax, a_pkey);
+
+//     if (!l_tx_out) {
+//         log_it(L_ERROR, "Can't compose the transaction conditional output");
+//         goto tx_fail;
+//     }
+//     dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
+//     DAP_DELETE(l_tx_out);
+//     if (!a_prev_tx) {
+//         // coin back
+//         uint256_t l_value_back = {};
+//         SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back);
+//         if (!IS_ZERO_256(l_value_back)) {
+//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) {
+//                 log_it(L_ERROR, "Cant add coin back output");
+//                 goto tx_fail;
+//             }
+//         }
+//     }
+
+//     // add fee items
+//     if (l_net_fee_used) {
+//         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
+//             log_it(L_ERROR, "Cant add net fee output");
+//             goto tx_fail;
+//         }
+//     }
+//     if (!IS_ZERO_256(a_fee)) {
+//         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
+//             log_it(L_ERROR, "Cant add validator fee output");
+//             goto tx_fail;
+//         }
+//     }
+//     uint256_t l_fee_back = {};
+//     // fee coin back
+//     SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back);
+//     if (!IS_ZERO_256(l_fee_back)) {
+//         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) {
+//             log_it(L_ERROR, "Cant add fee back output");
+//             goto tx_fail;
+//         }
+//     }
+
+//     // add 'sign' item
+//     if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) {
+//         log_it(L_ERROR, "Can't add sign output");
+//         goto tx_fail;
+//     }
+
+//     return l_tx;
+
+// tx_fail:
+//     dap_chain_datum_tx_delete(l_tx);
+//     return NULL;
+// }
+
+
+// srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value>
+// int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) {
+//     int arg_index = 1;
+//     const char * l_net_name = NULL;
+//     const char * l_wallet_name = NULL;  
+//     const char * l_order_hash = NULL;
+//     const char * l_value = NULL;
+//     const char * l_fee = NULL;
+
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
+//     if (!l_net_name) {
+//         printf("tx_create requires parameter '-net'");
+//         return -1;
+//     }
+
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name);
+//     if (!l_wallet_name) {
+//         printf("Error: Command 'purchase' requires parameter -w\n");
+//         return -1;
+//     }
+//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, arg_wallets_path, NULL);
+//     if (!l_wallet) {
+//         printf("Error: Specified wallet not found\n");
+//         return -2;
+//     }
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-order", &l_order_hash);
+//     if (!l_order_hash) {
+//         printf("Error: Command 'purchase' requires parameter -order\n");
+//         return -3;
+//     }
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value);
+//     if (!l_value) {
+//         printf("Error: Command 'purchase' requires parameter -value\n");
+//         return -4;
+//     }
+//     uint256_t l_datoshi_buy = dap_chain_balance_scan(l_value);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee);
+//     if (!l_fee) {
+//         printf("Error: Command 'purchase' requires parameter -fee\n");
+//         return -5;
+//     }
+//     uint256_t l_datoshi_fee = dap_chain_balance_scan(l_fee);
+//     dap_hash_fast_t l_tx_hash = {};
+//     dap_chain_hash_fast_from_str(l_order_hash, &l_tx_hash);
+//     char *l_str_ret_hash = NULL;
+//     int l_ret_code = dap_chain_net_srv_xchange_purchase_compose(l_net_name, &l_tx_hash, l_datoshi_buy, l_datoshi_fee,
+//                                                         l_wallet, &l_str_ret_hash);
+//     switch (l_ret_code) {
+//         case XCHANGE_PURCHASE_ERROR_OK: {
+//             printf("Exchange transaction has done\n");
+//             printf("hash: %s\n", l_str_ret_hash);
+//             DAP_DELETE(l_str_ret_hash);
+//             return 0;
+//         }
+//         case XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND: {
+//             printf("Error: Specified order not found\n");
+//             return -6;
+//         }
+//         case XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE: {
+//             printf("Error: Can't create price from order\n");
+//             return -7;
+//         }
+//         case XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX: {
+//             printf("Error: Exchange transaction error\n");
+//             return -8;
+//         }
+//         default: {
+//             printf("Error: An error occurred with an unknown code: %d.\n", l_ret_code);
+//             return -9;
+//         }
+//     }
+//     return 0;
+// }
+
+
+// dap_chain_net_srv_xchange_purchase_error_t dap_chain_net_srv_xchange_purchase_compose(const char *a_net_name, dap_hash_fast_t *a_order_hash, uint256_t a_value,
+//                                        uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out){
+//     if (!a_net_name || !a_order_hash || !a_wallet || !a_hash_out) {
+//         return XCHANGE_PURCHASE_ERROR_INVALID_ARGUMENT;
+//     }
+//     dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(a_net->pub.ledger, a_order_hash);
+//     if (l_cond_tx) {
+//         dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(a_net, l_cond_tx, a_order_hash, &a_fee, false);
+//         if(!l_price){
+//             return XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE;
+//         }
+//         // Create conditional transaction
+//         char *l_ret = NULL;
+//         dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_exchange(l_price, a_wallet, a_value, a_fee);
+//         if (l_tx ) {
+//             l_ret = s_xchange_tx_put(l_tx, a_net);
+//         }
+//         DAP_DELETE(l_price);
+//         if (l_tx && l_ret){
+//             *a_hash_out = l_ret;
+//             return XCHANGE_PURCHASE_ERROR_OK;
+//         } else
+//             return XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX;
+//     } else {
+//         return XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND;
+//     }
+// }
+
+
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 5ff863f5da..12867d60e9 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -38,11 +38,9 @@
 
  // #define RPC_NODES_URL "http://rpc.cellframe.net"
 #define RPC_NODES_URL "45.76.140.191:8081"
-
+#define MAX_RESPONSE_SIZE 4096
 #define NET_COUNT 6
 
-const char *c_wallets_path = NULL;
-
 typedef struct {
     char name[20];
     char native_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
@@ -69,37 +67,34 @@ int dap_cli_hold_compose(int a_argc, char **a_argv);
 int dap_cli_take_compose(int a_argc, char **a_argv);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
 
+int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
 
 dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer);
 dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
                                                         const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num);
 dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,const char *a_token_sell, 
                                                         uint256_t a_datoshi_sell, uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet);
-static dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
+dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
                                                                 const char *a_native_ticker, const char *a_net_name);
 dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name,
-                                                        dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-                                                        uint256_t a_value, uint256_t a_value_per_unit_max,
-                                                        dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
-                                                        uint256_t a_value_fee, const void *a_cond,
-                                                        size_t a_cond_size, const char *a_hash_out_type);
+        dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
+        const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+        uint256_t a_value, uint256_t a_value_per_unit_max,
+        dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
+        uint256_t a_value_fee, const void *a_cond,
+        size_t a_cond_size);
 bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee);
 bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count);
-dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
-                                                    const char *a_main_ticker,
-                                                    uint256_t a_value, uint256_t a_value_fee,
-                                                    dap_time_t a_time_staking, uint256_t a_reinvest_percent,
+dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, const char *a_main_ticker,
+                                                    uint256_t a_value, uint256_t a_value_fee, dap_time_t a_time_staking, uint256_t a_reinvest_percent,
                                                     const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * l_chain_id_str);
 bool check_token_in_ledger(json_object *l_json_coins, const char *a_token);
-dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
-                                               dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
-                                               const char *a_main_ticker, uint256_t a_value,
-                                               uint256_t a_value_fee,
-                                               const char *a_delegated_ticker_str, uint256_t a_delegated_value);
+dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
+                                               const char *a_main_ticker, uint256_t a_value, uint256_t a_value_fee, const char *a_delegated_ticker_str, uint256_t a_delegated_value);
 dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
-                              const char *a_net_str);
+                              const char *a_net_str, const char *a_token_ticker);
 
 #ifdef __cplusplus
 }
diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index 9081fe4bf1..60f5e6f244 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -51,7 +51,6 @@ typedef struct dap_chain_net_voting_params_offsets{
     bool delegate_key_required;
     bool vote_changing_allowed;
     char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
-    char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
 } dap_chain_net_voting_params_offsets_t;
 
 typedef struct dap_chain_net_vote_option {
@@ -574,7 +573,6 @@ static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledge
             return false;
         }
 
-        dap_chain_net_votings_t *l_voting = NULL;
         dap_chain_net_votings_t *l_voting = NULL;
         pthread_rwlock_wrlock(&s_votings_rwlock);
         HASH_FIND(hh, s_votings, &l_vote_tx_item->voting_hash, sizeof(dap_hash_fast_t), l_voting);
@@ -1223,9 +1221,6 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f
 
 }
 
-static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash,
-                                                 dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx,
-                                                 dap_hash_fast_t *a_pkey_hash)
 static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash,
                                                  dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx,
                                                  dap_hash_fast_t *a_pkey_hash)
diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h
index 2f944a4324..9299ac5022 100644
--- a/modules/service/voting/include/dap_chain_net_srv_voting.h
+++ b/modules/service/voting/include/dap_chain_net_srv_voting.h
@@ -95,7 +95,6 @@ enum DAP_CHAIN_NET_VOTE_CREATE_ERROR {
     DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST,
     DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT,
     DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN,
-    DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_TOKEN,    DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN,
     DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_TOKEN,
     DAP_CHAIN_NET_VOTE_CREATE_UNKNOWN_ERR,
     DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS
-- 
GitLab


From 4842fe8707f23ccd2138f9592ff28015a9148945 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Thu, 27 Mar 2025 12:39:39 +0700
Subject: [PATCH 24/53] [*] fix http

---
 modules/compose/dap_chain_tx_compose.c        | 319 +++++++++++-------
 .../compose/include/dap_chain_tx_compose.h    |  20 +-
 2 files changed, 210 insertions(+), 129 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index ce082f0782..a992519a56 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -39,7 +39,7 @@
 #include <netdb.h>
 #include <json-c/json.h>
 
-static json_object* s_request_command_to_rpc(const char *request);
+static json_object* s_request_command_to_rpc(const char *a_request, const char * a_net_name);
 
 
 const char *arg_wallets_path = NULL;
@@ -63,6 +63,24 @@ static dap_chain_net_id_t s_get_net_id(const char* name) {
     return empty_id;
 }
 
+static const char* s_get_net_url(const char* name) {
+    for (int i = 0; i < NET_COUNT; i++) {
+        if (strcmp(netinfo[i].name, name) == 0) {
+            return netinfo[i].url;
+        }
+    }
+    return NULL;
+}
+
+static uint16_t s_get_net_port(const char* name) {
+    for (int i = 0; i < NET_COUNT; i++) {
+        if (strcmp(netinfo[i].name, name) == 0) {
+            return netinfo[i].port;
+        }
+    }
+    return 0;
+}
+
 
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add) {
     json_object *items_array;
@@ -74,127 +92,193 @@ int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add) {
     return 0;
 }
 
+struct cmd_request {
+#ifdef DAP_OS_WINDOWS
+    CONDITION_VARIABLE wait_cond;
+    CRITICAL_SECTION wait_crit_sec;
+#else
+    pthread_cond_t wait_cond;
+    pthread_mutex_t wait_mutex;
+#endif
+    char* response;
+    size_t response_size;
+    int error_code;
+};
+
+static struct cmd_request* s_cmd_request_init()
+{
+    struct cmd_request *l_cmd_request = DAP_NEW_Z(struct cmd_request);
+    if (!l_cmd_request)
+        return NULL;
+#ifdef DAP_OS_WINDOWS
+    InitializeCriticalSection(&l_cmd_request->wait_crit_sec);
+    InitializeConditionVariable(&l_cmd_request->wait_cond);
+#else
+    pthread_mutex_init(&l_cmd_request->wait_mutex, NULL);
+#ifdef DAP_OS_DARWIN
+    pthread_cond_init(&l_cmd_request->wait_cond, NULL);
+#else
+    pthread_condattr_t attr;
+    pthread_condattr_init(&attr);
+    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+    pthread_cond_init(&l_cmd_request->wait_cond, &attr);    
+#endif
+#endif
+    return l_cmd_request;
+}
 
-static json_object* s_request_command_to_rpc(const char *request) {
-    struct addrinfo hints, *res = NULL, *p = NULL;
-    int sockfd = -1;
-    struct sockaddr_storage l_saddr = { };
-    char l_ip[INET6_ADDRSTRLEN] = { '\0' }; 
-    uint16_t l_port = 0;
-    char path[256] = "/";
-    json_object *response_json = NULL;
-    dap_json_rpc_response_t* response = NULL;
-
-    if (strchr(RPC_NODES_URL, ':') != NULL && strchr(RPC_NODES_URL, '/') == NULL) {
-        if (dap_net_parse_config_address(RPC_NODES_URL, l_ip, &l_port, &l_saddr, NULL) < 0) {
-            printf("Incorrect address \"%s\" format\n", RPC_NODES_URL);
-            return NULL;
-        }
-        memset(&hints, 0, sizeof(hints));
-        hints.ai_family = AF_INET;
-        hints.ai_socktype = SOCK_STREAM;
-
-        char port_str[6];
-        snprintf(port_str, sizeof(port_str), "%u", l_port);
-
-        if (getaddrinfo(l_ip, port_str, &hints, &res) != 0) {
-            fprintf(stderr, "Failed to resolve IP address\n");
-            return NULL;
-        }
-    } else {
-        const char *host_start = strstr(RPC_NODES_URL, "://");
-        if (!host_start) {
-            fprintf(stderr, "Invalid URL format\n");
-            return NULL;
-        }
-        host_start += 3;  // Move past "://"
+void s_cmd_request_free(struct cmd_request *a_cmd_request)
+{
+    if (!a_cmd_request)
+        return;
+
+#ifdef DAP_OS_WINDOWS
+    DeleteCriticalSection(&a_cmd_request->wait_crit_sec);
+#else
+    pthread_mutex_destroy(&a_cmd_request->wait_mutex);
+    pthread_cond_destroy(&a_cmd_request->wait_cond);
+#endif
+    DAP_DEL_MULTY(a_cmd_request->response, a_cmd_request);
+}
 
-        char host[256] = {0};
-        const char *path_start = strchr(host_start, '/');
-        size_t host_len = path_start ? (size_t)(path_start - host_start) : strlen(host_start);
-        if (host_len >= sizeof(host)) host_len = sizeof(host) - 1;
-        strncpy(host, host_start, host_len);
-        host[host_len] = '\0';  // Ensure null termination
+static void s_cmd_response_handler(void *a_response, size_t a_response_size, void *a_arg,
+                                            http_status_code_t http_status_code) {
+    (void)http_status_code;
+    struct cmd_request *l_cmd_request = (struct cmd_request *)a_arg;
+#ifdef DAP_OS_WINDOWS
+    EnterCriticalSection(&l_cmd_request->wait_crit_sec);
+#else
+    pthread_mutex_lock(&l_cmd_request->wait_mutex);
+#endif
+    l_cmd_request->response = DAP_DUP_SIZE(a_response, a_response_size);
+    l_cmd_request->response_size = a_response_size;
+#ifdef DAP_OS_WINDOWS
+    WakeConditionVariable(&l_cmd_request->wait_cond);
+    LeaveCriticalSection(&l_cmd_request->wait_crit_sec);
+#else
+    pthread_cond_signal(&l_cmd_request->wait_cond);
+    pthread_mutex_unlock(&l_cmd_request->wait_mutex);
+#endif
+}
 
-        printf("Extracted host: %s\n", host);  // Debugging output
+static void s_cmd_error_handler(int a_error_code, void *a_arg){
+    struct cmd_request * l_cmd_request = (struct cmd_request *)a_arg;
+#ifdef DAP_OS_WINDOWS
+    EnterCriticalSection(&l_cmd_request->wait_crit_sec);
+    l_cmd_request->response = NULL;
+    l_cmd_request->error_code = a_error_code;
+    WakeConditionVariable(&l_cmd_request->wait_cond);
+    LeaveCriticalSection(&l_cmd_request->wait_crit_sec);
+#else
+    pthread_mutex_lock(&l_cmd_request->wait_mutex);
+    l_cmd_request->response = NULL;
+    l_cmd_request->error_code = a_error_code;
+    pthread_cond_signal(&l_cmd_request->wait_cond);
+    pthread_mutex_unlock(&l_cmd_request->wait_mutex);
+#endif
+}
 
-        struct addrinfo hints = {0}, *res = NULL;
-        hints.ai_family = AF_INET;
-        hints.ai_socktype = SOCK_STREAM;
 
-        if (getaddrinfo(host, "80", &hints, &res) != 0) {
-            fprintf(stderr, "Failed to resolve hostname: %s\n", host);
-            return NULL;
+static int dap_chain_cmd_list_wait(struct cmd_request *a_cmd_request, int a_timeout_ms) {
+#ifdef DAP_OS_WINDOWS
+    EnterCriticalSection(&a_cmd_request->wait_crit_sec);
+    if (a_cmd_request->response)
+        return LeaveCriticalSection(&a_cmd_request->wait_crit_sec), 0;
+    while (!a_cmd_request->response) {
+        if (!SleepConditionVariableCS(&a_cmd_request->wait_cond, &a_cmd_request->wait_crit_sec, a_timeout_ms)) {
+            a_cmd_request->error_code = GetLastError() == ERROR_TIMEOUT ? 1 : 2;
+            break;
         }
     }
-
-    for (p = res; p != NULL; p = p->ai_next) {
-        sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
-        if (sockfd == -1) continue;
-
-        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == 0) {
+    LeaveCriticalSection(&a_cmd_request->wait_crit_sec);
+    return a_cmd_request->error_code;     
+#else
+    pthread_mutex_lock(&a_cmd_request->wait_mutex);
+    if(a_cmd_request->response) {
+        pthread_mutex_unlock(&a_cmd_request->wait_mutex);
+        return 0;
+    }
+    
+    struct timespec l_cond_timeout;
+#ifdef DAP_OS_DARWIN
+    l_cond_timeout.tv_sec = a_timeout_ms / 1000;
+    l_cond_timeout.tv_nsec = (a_timeout_ms % 1000) * 1000000;
+#else
+    clock_gettime(CLOCK_MONOTONIC, &l_cond_timeout);
+    l_cond_timeout.tv_sec += a_timeout_ms / 1000;
+    l_cond_timeout.tv_nsec += (a_timeout_ms % 1000) * 1000000;
+    if (l_cond_timeout.tv_nsec >= 1000000000) {
+        l_cond_timeout.tv_sec += l_cond_timeout.tv_nsec / 1000000000;
+        l_cond_timeout.tv_nsec %= 1000000000;
+    }
+#endif
+    
+    int ret = 0;
+    while (!a_cmd_request->response) {
+        int cond_ret;
+#ifdef DAP_OS_DARWIN
+        cond_ret = pthread_cond_timedwait_relative_np(&a_cmd_request->wait_cond, 
+                    &a_cmd_request->wait_mutex, &l_cond_timeout);
+#else
+        cond_ret = pthread_cond_timedwait(&a_cmd_request->wait_cond, 
+                    &a_cmd_request->wait_mutex, &l_cond_timeout);
+#endif
+        if (cond_ret == ETIMEDOUT) {
+            a_cmd_request->error_code = 1;
+            ret = 1;
+            break;
+        } else if (cond_ret != 0) {
+            a_cmd_request->error_code = 2;
+            ret = 2;
             break;
         }
-        
-        close(sockfd);
-        sockfd = -1;
-    }
-
-    freeaddrinfo(res);
-
-    if (sockfd == -1) {
-        fprintf(stderr, "Failed to connect to host\n");
-        return NULL;
     }
+    pthread_mutex_unlock(&a_cmd_request->wait_mutex);
+    return ret;
+#endif
+}
 
-    char http_request[1024];
-    snprintf(http_request, sizeof(http_request),
-             "POST %s HTTP/1.1\r\n"
-             "Host: %s\r\n"
-             "Content-Type: application/json\r\n"
-             "Content-Length: %zu\r\n"
-             "Connection: close\r\n\r\n"
-             "%s",
-             path, l_ip, strlen(request), request);
+static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_object **a_response_out, size_t *a_response_out_size)
+{
+    int ret = 0;
 
-    if (send(sockfd, http_request, strlen(http_request), 0) < 0) {
-        fprintf(stderr, "Failed to send request\n");
-        close(sockfd);
-        return NULL;
+    if (a_cmd_request->error_code) {
+        ret = - 1;
+    } else if (a_cmd_request->response) {
+            *a_response_out = json_tokener_parse(a_cmd_request->response);
+            *a_response_out_size = a_cmd_request->response_size;
+    } else {
+        ret = -2;
     }
 
-    dap_app_cli_cmd_state_t cmd = {
-        .cmd_res = DAP_NEW_Z_SIZE(char, MAX_RESPONSE_SIZE),
-        .cmd_res_cur = 0,
-        .hdr_len = 0  // Ensure this is initialized
-    };
+    return ret;
+}
 
-    if (!cmd.cmd_res) {
-        fprintf(stderr, "Memory allocation failed\n");
-        close(sockfd);
-        return NULL;
-    }
+static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name) {
+    json_object * l_response = NULL;
+    size_t l_response_size;
+    struct cmd_request* l_cmd_request = s_cmd_request_init();
 
-    int l_status = 1;
-    while (l_status > 0) {
-        l_status = dap_app_cli_http_read(sockfd, &cmd, l_status);
-    }
-    
-    close(sockfd);
+    dap_client_http_request(dap_worker_get_auto(),
+                                s_get_net_url(a_net_name),
+                                s_get_net_port(a_net_name),
+                                "POST", "application/json",
+                                NULL, request, strlen(request), NULL,
+                                s_cmd_response_handler, s_cmd_error_handler,
+                                l_cmd_request, NULL);
 
-    response = dap_json_rpc_response_from_string(cmd.cmd_res + cmd.hdr_len);
-    DAP_DELETE(cmd.cmd_res);
+    int l_ret = dap_chain_cmd_list_wait(l_cmd_request, 15000);
 
-    if (!response) {
-        return NULL;
+    if (!l_ret){
+        if (s_cmd_request_get_response(l_cmd_request, &l_response, &l_response_size)) {
+            printf( "Response error code: %d", l_cmd_request->error_code);
+        }
     }
-
-    response_json = response->result_json_object;
-    json_object_get(response_json);  // Prevent early free
-
+    json_object * l_result;
+    json_object_object_get_ex(l_response, "result", &l_result);
     json_object *errors_array;
-    if (json_object_is_type(response_json, json_type_array) && json_object_array_length(response_json) > 0) {
-        json_object *first_element = json_object_array_get_idx(response_json, 0);
+    if (json_object_is_type(l_result, json_type_array) && json_object_array_length(l_result) > 0) {
+        json_object *first_element = json_object_array_get_idx(l_result, 0);
         if (json_object_object_get_ex(first_element, "errors", &errors_array)) {
             int errors_len = json_object_array_length(errors_array);
             for (int j = 0; j < errors_len; j++) {
@@ -205,20 +289,21 @@ static json_object* s_request_command_to_rpc(const char *request) {
                     printf("Error %d: %s\n", json_object_get_int(error_code), json_object_get_string(error_message));
                 }
             }
-            json_object_put(response_json);  // Free memory
-            response_json = NULL;
+            json_object_put(l_result);
+            l_result = NULL;
         }
     }
-
-    dap_json_rpc_response_free(response);
-    return response_json;
+    s_cmd_request_free(l_cmd_request);
+    json_object_get(l_result);
+    json_object_put(l_response);
+    return l_result;
 }
 
 
 bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee) {
     char data[512];
     snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name);
-    json_object *l_json_get_fee = s_request_command_to_rpc(data);
+    json_object *l_json_get_fee = s_request_command_to_rpc(data, l_net_name);
     if (!l_json_get_fee) {
         return false;
     }
@@ -268,7 +353,7 @@ bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const c
     snprintf(data, sizeof(data), 
             "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
             dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name);
-    json_object *l_json_outs = s_request_command_to_rpc(data);
+    json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name);
     if (!l_json_outs) {
         return false;
     }
@@ -932,7 +1017,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name);
-    json_object *l_json_coins = s_request_command_to_rpc(data);
+    json_object *l_json_coins = s_request_command_to_rpc(data, a_net_name);
     if (!l_json_coins) {
         return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS
     }
@@ -946,7 +1031,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net
             "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
             dap_chain_addr_to_str(l_wallet_addr), a_net_name);
     DAP_DEL_Z(l_wallet_addr);
-    json_object *l_json_outs = s_request_command_to_rpc(data);
+    json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name);
     uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell);
 
     uint256_t l_value_sell = a_datoshi_sell;
@@ -982,7 +1067,7 @@ json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_n
     snprintf(data, sizeof(data), 
             "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
             dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name);
-    json_object *l_json_outs = s_request_command_to_rpc(data);
+    json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name);
     if (!l_json_outs) {
         return NULL;
     }
@@ -1458,7 +1543,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name);
-    json_object *l_json_coins = s_request_command_to_rpc(data);
+    json_object *l_json_coins = s_request_command_to_rpc(data, l_net_name);
     if (!l_json_coins) {
         return -4;
     }
@@ -1592,7 +1677,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
         dap_chain_addr_to_str(l_addr_holder), l_net_name);
     DAP_DEL_Z(l_addr_holder);
 
-    json_object *l_json_outs = s_request_command_to_rpc(data);
+    json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name);
     uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str);
     json_object_put(l_json_outs);
     if (compare256(l_value_balance, l_value) == -1) {
@@ -1847,7 +1932,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
             l_tx_str, l_net_str);
     
-    json_object *response = s_request_command_to_rpc(data);
+    json_object *response = s_request_command_to_rpc(data, l_net_str);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return -15;
@@ -2135,7 +2220,7 @@ uint256_t s_get_key_delegating_min_value(const char *a_net_str){
             "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", 
             a_net_str);
     
-    json_object *response = s_request_command_to_rpc(data);
+    json_object *response = s_request_command_to_rpc(data, a_net_str);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return l_key_delegating_min_value;
@@ -2281,7 +2366,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str);
-    json_object *l_json_coins = s_request_command_to_rpc(data);
+    json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str);
     if (!l_json_coins) {
         printf("Error: Can't get ledger coins list\n");
         return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 12867d60e9..4fe3739f61 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -33,27 +33,23 @@
 
  #include <json-c/json.h>
 
-
-
-
- // #define RPC_NODES_URL "http://rpc.cellframe.net"
-#define RPC_NODES_URL "45.76.140.191:8081"
-#define MAX_RESPONSE_SIZE 4096
 #define NET_COUNT 6
 
 typedef struct {
     char name[20];
     char native_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
     dap_chain_net_id_t net_id;
+    char url[128];
+    uint16_t port;
 } NetInfo;
 
 static NetInfo netinfo[NET_COUNT] = {
-    {"riemann",  "tKEL",  {.uint64 = 0x000000000000dddd}},
-    {"raiden",   "tCELL", {.uint64 = 0x000000000000bbbb}},
-    {"KelVPN",   "KEL",   {.uint64 = 0x1807202300000000}},
-    {"Backbone", "CELL",  {.uint64 = 0x0404202200000000}},
-    {"mileena",  "tMIL",  {.uint64 = 0x000000000000cccc}},
-    {"subzero",  "tCELL", {.uint64 = 0x000000000000acca}}
+    {"riemann",  "tKEL",  {.uint64 = 0x000000000000dddd}, "45.76.140.191", 8081},
+    {"raiden",   "tCELL", {.uint64 = 0x000000000000bbbb}, "http://rpc.cellframe.net", 8081},
+    {"KelVPN",   "KEL",   {.uint64 = 0x1807202300000000}, "http://rpc.cellframe.net", 8081},
+    {"Backbone", "CELL",  {.uint64 = 0x0404202200000000}, "http://rpc.cellframe.net", 8081},
+    {"mileena",  "tMIL",  {.uint64 = 0x000000000000cccc}, "http://rpc.cellframe.net", 8081},
+    {"subzero",  "tCELL", {.uint64 = 0x000000000000acca}, "http://rpc.cellframe.net", 8081}
 };
 
 #ifdef __cplusplus
-- 
GitLab


From 01ce7c26f822216922aadee7d1ab9a56504eef9b Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Fri, 28 Mar 2025 12:20:21 +0700
Subject: [PATCH 25/53] [+] -url -port

---
 modules/compose/dap_chain_tx_compose.c        | 1377 +++++++++--------
 .../compose/include/dap_chain_tx_compose.h    |   36 +-
 2 files changed, 729 insertions(+), 684 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index a992519a56..f0dbdd845e 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -39,7 +39,7 @@
 #include <netdb.h>
 #include <json-c/json.h>
 
-static json_object* s_request_command_to_rpc(const char *a_request, const char * a_net_name);
+static json_object* s_request_command_to_rpc(const char *a_request, const char * a_net_name, const char * a_url_str, uint16_t a_port);
 
 
 const char *arg_wallets_path = NULL;
@@ -254,14 +254,14 @@ static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_ob
     return ret;
 }
 
-static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name) {
+static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) {
     json_object * l_response = NULL;
     size_t l_response_size;
     struct cmd_request* l_cmd_request = s_cmd_request_init();
 
     dap_client_http_request(dap_worker_get_auto(),
-                                s_get_net_url(a_net_name),
-                                s_get_net_port(a_net_name),
+                                a_url_str ? a_url_str : s_get_net_url(a_net_name),
+                                a_port ? a_port : s_get_net_port(a_net_name),
                                 "POST", "application/json",
                                 NULL, request, strlen(request), NULL,
                                 s_cmd_response_handler, s_cmd_error_handler,
@@ -300,10 +300,10 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a
 }
 
 
-bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee) {
+bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, const char * a_url_str, uint16_t a_port) {
     char data[512];
     snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name);
-    json_object *l_json_get_fee = s_request_command_to_rpc(data, l_net_name);
+    json_object *l_json_get_fee = s_request_command_to_rpc(data, l_net_name, a_url_str, a_port);
     if (!l_json_get_fee) {
         return false;
     }
@@ -348,12 +348,13 @@ bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net
     return true;
 }
 
-bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count) {
+bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name,
+                                         json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port) {
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
             dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name);
-    json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name);
+    json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name, a_url_str, a_port);
     if (!l_json_outs) {
         return false;
     }
@@ -402,6 +403,9 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) {
     const char *l_value_str = NULL;
     const char *l_rate_str = NULL;
     const char *l_fee_str = NULL;
+    const char *l_url_str = NULL;
+    const char *l_port_str = NULL;
+    uint16_t l_port = 0;
 
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
@@ -425,12 +429,24 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) {
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_str);
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-rate", &l_rate_str);
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str);
 
     if (!l_net_name) {
         printf("xchange_create requires parameter '-net'");
         return -1;
     }
 
+    if (!l_url_str) {
+        l_url_str = s_get_net_url(l_net_name);
+    }
+
+    if (!l_port_str) {
+        l_port = s_get_net_port(l_net_name);
+    } else {
+        l_port = atoi(l_port_str);
+    }
+
     if (!l_token_buy) {
         printf("xchange_create requires parameter '-token_buy'");
         return -1;
@@ -477,7 +493,7 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) {
     }
 
     dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_net_name, l_token_buy,
-                                     l_token_sell, l_value, l_rate, l_fee, l_wallet);
+                                     l_token_sell, l_value, l_rate, l_fee, l_wallet, l_url_str, l_port);
     json_object *l_ret = json_object_new_object();
     dap_chain_net_tx_to_json(l_tx, l_ret);
     printf("%s", json_object_to_json_string(l_ret));
@@ -497,6 +513,8 @@ int dap_tx_create_compose(int argc, char ** argv) {
     const char * l_token_ticker = NULL;
     const char * l_net_name = NULL;
     const char * l_chain_name = NULL;
+    const char * l_url_str = NULL;
+    uint16_t l_port = 0;
 
     const char * l_hash_out_type = NULL;
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type);
@@ -528,6 +546,16 @@ int dap_tx_create_compose(int argc, char ** argv) {
         return -1;
     }
 
+    if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str)) {
+        l_url_str = s_get_net_url(l_net_name);
+    }
+    const char *l_port_str = NULL;
+    if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str)) {
+        l_port = s_get_net_port(l_net_name);
+    } else {
+        l_port = atoi(l_port_str);
+    }
+
     uint256_t *l_value = NULL;
     uint256_t l_value_fee = {};
     dap_chain_addr_t **l_addr_to = NULL;
@@ -648,7 +676,7 @@ int dap_tx_create_compose(int argc, char ** argv) {
     }
 
 
-    dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count);
+    dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count, l_url_str, l_port);
 
     json_object * l_json_obj_ret = json_object_new_object();
     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
@@ -696,8 +724,7 @@ int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx
 
 
 dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
-        const char* a_token_ticker,
-        uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num)
+        const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port)
 {
     if (!a_addr_from || !a_token_ticker || !a_value) {
         return NULL;
@@ -731,7 +758,7 @@ dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name,
     dap_list_t *l_list_fee_out = NULL;
     uint256_t l_net_fee = {};
     dap_chain_addr_t *l_addr_fee = NULL;
-    if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee)) {
+    if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port)) {
         return NULL;
     }
 
@@ -739,7 +766,7 @@ dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name,
     SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
     json_object *l_outs = NULL;
     int l_outputs_count = 0;
-    if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count)) {
+    if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) {
         return NULL;
     }
 
@@ -1001,9 +1028,9 @@ bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) {
 
 dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,
                                      const char *a_token_sell, uint256_t a_datoshi_sell,
-                                     uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet){
+                                     uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port){
     if (!a_net_name || !a_token_buy || !a_token_sell || !a_wallet) {
-        return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMENT
+        return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMEN
     }
     if (IS_ZERO_256(a_rate)) {
         return NULL; // XCHANGE_CREATE_ERROR_RATE_IS_ZERO
@@ -1017,7 +1044,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name);
-    json_object *l_json_coins = s_request_command_to_rpc(data, a_net_name);
+    json_object *l_json_coins = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
     if (!l_json_coins) {
         return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS
     }
@@ -1031,7 +1058,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net
             "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
             dap_chain_addr_to_str(l_wallet_addr), a_net_name);
     DAP_DEL_Z(l_wallet_addr);
-    json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name);
+    json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
     uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell);
 
     uint256_t l_value_sell = a_datoshi_sell;
@@ -1058,16 +1085,16 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net
     l_price->datoshi_sell = a_datoshi_sell;
     l_price->rate = a_rate;
     l_price->fee = a_fee;
-    dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name);
+    dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name, a_url_str, a_port);
     return l_tx;
 }
 
-json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_name,  dap_chain_addr_t * a_addr) { 
+json_object *dap_get_remote_tx_outs(const char *a_token_ticker, const char *a_net_name,  dap_chain_addr_t * a_addr, const char *a_url_str, uint16_t a_port) { 
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
             dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name);
-    json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name);
+    json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
     if (!l_json_outs) {
         return NULL;
     }
@@ -1107,7 +1134,7 @@ json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_n
 
 
 dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
-                                                                 const char *a_native_ticker, const char *a_net_name)
+                                                                 const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port)
 {
     if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) {
         return NULL;
@@ -1123,13 +1150,13 @@ dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xc
     dap_chain_addr_t * l_addr_net_fee = NULL;
     dap_list_t *l_list_fee_out = NULL;
 
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee);
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee, a_url_str, a_port);
     if (l_net_fee_used)
         SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
 
     dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name));
     dap_chain_addr_t l_seller_addr = *l_wallet_addr;
-    json_object *l_outs_native = get_tx_outs_by_curl(a_native_ticker, a_net_name, l_wallet_addr);
+    json_object *l_outs_native = dap_get_remote_tx_outs(a_native_ticker, a_net_name, l_wallet_addr, a_url_str, a_port);
     if (!l_outs_native) {
         return NULL;
     }
@@ -1138,7 +1165,7 @@ dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xc
     if (!dap_strcmp(a_price->token_sell, a_native_ticker)) {
         l_outs = l_outs_native;
     } else {
-        l_outs = get_tx_outs_by_curl(a_price->token_sell, a_net_name, l_wallet_addr);
+        l_outs = dap_get_remote_tx_outs(a_price->token_sell, a_net_name, l_wallet_addr, a_url_str, a_port);
     }
     DAP_DELETE(l_wallet_addr);
     int l_out_native_count = json_object_array_length(l_outs_native);
@@ -1265,6 +1292,9 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
     const char * l_srv_uid_str = NULL;
     uint256_t l_value_datoshi = {};    
     uint256_t l_value_fee = {};
+    const char * l_url_str = NULL;
+    const char * l_port_str = NULL;
+    uint16_t l_port = 0;
 
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
@@ -1289,6 +1319,8 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str);
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str);
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str);
 
     if(!l_token_ticker) {
         printf("tx_cond_create requires parameter '-token'\n");
@@ -1314,6 +1346,14 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
         printf("tx_cond_create requires parameter '-net'\n");
         return -7;
     }
+    if(!l_url_str) {
+        l_url_str = s_get_net_url(l_net_name);
+    }
+    if(!l_port_str) {
+        l_port = s_get_net_port(l_net_name);
+    } else {
+        l_port = atoi(l_port_str);
+    }
     if(!l_unit_str) {
         printf("tx_cond_create requires parameter '-unit'\n");
         return -8;
@@ -1374,7 +1414,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
     uint256_t l_value_per_unit_max = {};
     dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker,
                                                         l_value_datoshi, l_value_per_unit_max, l_price_unit,
-                                                        l_srv_uid, l_value_fee, NULL, 0);
+                                                        l_srv_uid, l_value_fee, NULL, 0, l_url_str, l_port);
     
     json_object * l_json_obj_ret = json_object_new_object();
     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
@@ -1394,7 +1434,7 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net
         uint256_t a_value, uint256_t a_value_per_unit_max,
         dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
         uint256_t a_value_fee, const void *a_cond,
-        size_t a_cond_size)
+        size_t a_cond_size, const char *a_url_str, uint16_t a_port)
 {
     // check valid param
     if (!a_net_name || !a_key_from || !a_key_cond ||
@@ -1408,7 +1448,7 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net
 
     uint256_t l_net_fee = {};
     dap_chain_addr_t* l_addr_fee = NULL;
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee);
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port);
     // find the transactions from which to take away coins
     uint256_t l_value_transfer = {}; // how many coins to transfer
     uint256_t l_value_need = {};
@@ -1422,7 +1462,7 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net
     // list of transaction with 'out' items
     json_object *l_outs = NULL;
     int l_outputs_count = 0;
-    if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count)) {
+    if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) {
         return NULL;
     }
     dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
@@ -1504,6 +1544,8 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
     dap_enc_key_t						*l_key_from;
     dap_chain_wallet_t					*l_wallet;
     dap_chain_addr_t					*l_addr_holder;
+    const char                          *l_url_str = NULL;
+    uint16_t                            l_port = 0;
 
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
@@ -1540,10 +1582,21 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
         return -3;
     }
 
+    if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) {
+        l_url_str = s_get_net_url(l_net_name);
+    }
+
+    const char *l_port_str = NULL;
+    if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) {
+        l_port = s_get_net_port(l_net_name);
+    } else {
+        l_port = atoi(l_port_str);
+    }
+
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name);
-    json_object *l_json_coins = s_request_command_to_rpc(data, l_net_name);
+    json_object *l_json_coins = s_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
     if (!l_json_coins) {
         return -4;
     }
@@ -1677,7 +1730,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
         dap_chain_addr_to_str(l_addr_holder), l_net_name);
     DAP_DEL_Z(l_addr_holder);
 
-    json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name);
+    json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
     uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str);
     json_object_put(l_json_outs);
     if (compare256(l_value_balance, l_value) == -1) {
@@ -1692,7 +1745,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
     dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_net_name, l_key_from,
                                                            l_ticker_str, l_value, l_value_fee,
                                                            l_time_staking, l_reinvest_percent,
-                                                           l_delegated_ticker_str, l_value_delegated, l_chain_id_str);
+                                                           l_delegated_ticker_str, l_value_delegated, l_chain_id_str, l_url_str, l_port);
 
     json_object * l_json_obj_ret = json_object_new_object();
     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
@@ -1711,7 +1764,8 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_nam
                                                     const char *a_main_ticker,
                                                     uint256_t a_value, uint256_t a_value_fee,
                                                     dap_time_t a_time_staking, uint256_t a_reinvest_percent,
-                                                    const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * l_chain_id_str)
+                                                    const char *a_delegated_ticker_str, uint256_t a_delegated_value,
+                                                    const char * l_chain_id_str, const char *l_url_str, uint16_t l_port)
 {
     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
     // check valid param
@@ -1728,10 +1782,10 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_nam
     dap_chain_addr_t l_addr = {};
 
     dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name));
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee);
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port);
     SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
 
-    json_object *l_outs_native = get_tx_outs_by_curl(l_native_ticker, a_net_name, &l_addr);
+    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port);
     if (!l_outs_native) {
         return NULL;
     }
@@ -1740,7 +1794,7 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_nam
     if (!dap_strcmp(a_main_ticker, l_native_ticker)) {
         l_outs_main = l_outs_native;
     } else {
-        l_outs_main = get_tx_outs_by_curl(a_main_ticker, a_net_name, &l_addr);
+        l_outs_main = dap_get_remote_tx_outs(a_main_ticker, a_net_name, &l_addr, l_url_str, l_port);
     }
     int l_out_native_count = json_object_array_length(l_outs_native);
     int l_out_main_count = json_object_array_length(l_outs_main);
@@ -1880,6 +1934,8 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
     dap_hash_fast_t						l_tx_hash;
     dap_chain_tx_out_cond_t				*l_cond_tx = NULL;
     dap_enc_key_t						*l_owner_key;
+    const char                          *l_url_str = NULL;
+    uint16_t                            l_port = 0;
 
 
     const char *l_wallet_path = NULL;
@@ -1897,6 +1953,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
         arg_wallets_path = dap_strdup(l_wallet_path);
     }
 
+
     const char *l_hash_out_type = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
     if (!l_hash_out_type)
@@ -1911,6 +1968,17 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
         return -2;
     }
 
+    if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) {
+        l_url_str = s_get_net_url(l_net_str);
+    }
+
+    const char *l_port_str = NULL;
+    if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) {
+        l_port = s_get_net_port(l_net_str);
+    } else {
+        l_port = atoi(l_port_str);
+    }
+
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str);
     if (!l_chain_id_str) {
         printf("Error: Missing or invalid chain_id argument\n");
@@ -1932,7 +2000,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
             l_tx_str, l_net_str);
     
-    json_object *response = s_request_command_to_rpc(data, l_net_str);
+    json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return -15;
@@ -2038,7 +2106,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
     }
     dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_net_str, l_owner_key, &l_tx_hash, l_prev_cond_idx,
                                           l_ticker_str, l_cond_tx->header.value, l_value_fee,
-                                          l_delegated_ticker_str, l_value_delegated);
+                                          l_delegated_ticker_str, l_value_delegated, l_url_str, l_port);
 
     json_object * l_json_obj_ret = json_object_new_object();
     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
@@ -2056,7 +2124,8 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_na
                                                dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
                                                const char *a_main_ticker, uint256_t a_value,
                                                uint256_t a_value_fee,
-                                               const char *a_delegated_ticker_str, uint256_t a_delegated_value)
+                                               const char *a_delegated_ticker_str, uint256_t a_delegated_value,
+                                               const char *l_url_str, uint16_t l_port)
 {
     // check valid param
     if (!a_net_name | !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) {
@@ -2075,14 +2144,14 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_na
     dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name));
     dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL;
 
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee);
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port);
 
-    json_object *l_outs_native = get_tx_outs_by_curl(l_native_ticker, a_net_name, &l_addr);
+    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port);
     if (!l_outs_native) {
         return NULL;
     }
 
-    json_object *l_outs_delegated = get_tx_outs_by_curl(a_delegated_ticker_str, a_net_name, &l_addr);
+    json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, a_net_name, &l_addr, l_url_str, l_port);
     int l_out_native_count = json_object_array_length(l_outs_native);
     int l_out_delegated_count = json_object_array_length(l_outs_delegated);
 
@@ -2213,14 +2282,14 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_na
     return l_tx;
 }
 
-uint256_t s_get_key_delegating_min_value(const char *a_net_str){
+uint256_t s_get_key_delegating_min_value(const char *a_net_str, const char *l_url_str, uint16_t l_port){
     uint256_t l_key_delegating_min_value = uint256_0;
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", 
             a_net_str);
     
-    json_object *response = s_request_command_to_rpc(data, a_net_str);
+    json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return l_key_delegating_min_value;
@@ -2271,7 +2340,8 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
     const char* l_wallet_str = NULL;
     const char* l_net_str = NULL;
     const char* l_token_str = NULL;
-
+    const char* l_url_str = NULL;
+    uint16_t l_port = 0;
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
     if (!l_wallet_path) {
@@ -2294,6 +2364,17 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
         return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING;
     }
 
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-url", &l_url_str)) {
+        l_url_str = s_get_net_url(l_net_str);
+    }
+
+    const char *l_port_str = NULL;
+    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str)) {
+        l_port = s_get_net_port(l_net_str);
+    } else {
+        l_port = atoi(l_port_str);
+    }
+
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str);
     if (!l_question_str){
         printf("Voting requires a question parameter to be valid.\n");
@@ -2366,7 +2447,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str);
-    json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str);
+    json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
     if (!l_json_coins) {
         printf("Error: Can't get ledger coins list\n");
         return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
@@ -2378,7 +2459,9 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
     }
     json_object_put(l_json_coins);
 
-    dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net_str, l_token_str);
+    dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count,
+                                                                l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, 
+                                                                l_wallet_fee, l_net_str, l_token_str, l_url_str, l_port);
     dap_list_free(l_options_list);
     dap_chain_wallet_close(l_wallet_fee);
     json_object * l_json_obj_ret = json_object_new_object();
@@ -2392,7 +2475,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
 dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
-                              const char *a_net_str, const char *a_token_ticker) {
+                              const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port) {
 
     if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
         return NULL;
@@ -2417,12 +2500,12 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question,
     const char *l_native_ticker = s_get_native_ticker(a_net_str);
     uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer;
     dap_chain_addr_t *l_addr_fee = NULL;
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee);
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port);
     SUM_256_256(l_net_fee, a_fee, &l_total_fee);
 
     json_object *l_outs = NULL;
     int l_outputs_count = 0;
-    if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count)) {
+    if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count, l_url_str, l_port)) {
         return NULL;
     }
 
@@ -2893,17 +2976,15 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
 */
 
 
-/**
+/** 
 static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
 {
     const char *l_net_str = NULL,
                *l_wallet_str = NULL,
                *l_cert_str = NULL,
                *l_fee_str = NULL,
-               *l_tx_hash_str = NULL,
-               *l_poa_cert_str = NULL,
-               *l_signing_pkey_hash_str = NULL,
-               *l_signing_pkey_type_str = NULL;
+               *l_tx_hash_str = NULL;
+               
     int l_arg_index = 1;
     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
     if (!l_net_str) {
@@ -2914,42 +2995,26 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
     uint256_t l_fee = {};
     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
     if (!l_wallet_str) {
-        dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-poa_cert", &l_poa_cert_str);
-        if (!l_poa_cert_str) {
-            printf("Command 'invalidate' requires parameter -w or -poa_cert\n");
-            return -1;
-        }
-    } else {
-        dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
-        if (!l_fee_str) {
-            printf("Command 'delegate' requires parameter -fee\n");
-            return -1;
-        }
-        l_fee = dap_chain_balance_scan(l_fee_str);
-        if (IS_ZERO_256(l_fee)) {
-            printf("Unrecognized number in '-fee' param\n");
-            return -1;
-        }
+        printf("Command 'invalidate' requires parameter -w\n");
+        return -1;
+    }
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
+    if (!l_fee_str) {
+        printf("Command 'delegate' requires parameter -fee\n");
+        return -1;
+    }
+    l_fee = dap_chain_balance_scan(l_fee_str);
+    if (IS_ZERO_256(l_fee)) {
+        printf("Unrecognized number in '-fee' param\n");
+        return -1;
     }
 
     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tx", &l_tx_hash_str);
     if (!l_tx_hash_str) {
         dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str);
         if (!l_cert_str) {
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-signing_pkey_hash", &l_signing_pkey_hash_str);
-            if (!l_signing_pkey_hash_str) {
-                printf("Command 'invalidate' requires parameter -tx or -cert or -signing_pkey_hash\n");
-                return -1;
-            }
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-signing_pkey_type", &l_signing_pkey_type_str);
-            if (!l_signing_pkey_type_str) {
-                printf("Command 'invalidate' requires parameter -signing_pkey_type\n");
-                return -1;
-            }
-            if (dap_sign_type_from_str(l_signing_pkey_type_str).type == SIG_TYPE_NULL) {
-                printf("Invalid signing_pkey_type %s\n", l_signing_pkey_type_str);
-                return -3;
-            }
+            printf("Command 'invalidate' requires parameter -tx or -cert\n");
+            return -1;
         }
     }
 
@@ -3091,47 +3156,22 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
         }
     }
     dap_chain_datum_tx_t *l_tx = NULL;
-    if (l_wallet_str) {
-        const char* l_sign_str = "";
-        dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config),NULL);
-        if (!l_wallet) {
-            printf("Specified wallet not found\n");
-            return -14;
-        } else {
-            l_sign_str = dap_chain_wallet_check_sign(l_wallet);
-        }
-        dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
-        l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key);
-        dap_chain_wallet_close(l_wallet);
-        dap_enc_key_delete(l_enc_key);
+    const char* l_sign_str = "";
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config),NULL);
+    if (!l_wallet) {
+        printf("Specified wallet not found\n");
+        return -14;
     } else {
-        dap_cert_t *l_poa_cert = dap_cert_find_by_name(l_poa_cert_str);
-        if (!l_poa_cert) {
-            printf("Specified certificate not found\n");
-            return -4;
-        }
-        if (!s_srv_stake_is_poa_cert(l_net, l_poa_cert->enc_key)) {
-            printf("Specified certificate is not PoA root one\n");
-            return -16;
-        }
-        dap_chain_datum_decree_t *l_decree = s_stake_decree_invalidate(l_net, &l_tx_hash, l_poa_cert);
-        char *l_decree_hash_str = NULL;
-        if (l_decree && (l_decree_hash_str = s_stake_decree_put(l_decree, l_net))) {
-            json_object* l_json_object_invalidate = json_object_new_object();
-            json_object_object_add(l_json_object_invalidate, "status", json_object_new_string("success"));
-            json_object_object_add(l_json_object_invalidate, "decree", json_object_new_string(l_decree_hash_str));
-            json_object_object_add(l_json_object_invalidate, "message", json_object_new_string("Specified delegated key invalidated. Try to execute this command with -w to return m-tokens to owner"));
-            json_object_array_add(*a_json_arr_reply, l_json_object_invalidate);
-            DAP_DELETE(l_decree);
-            DAP_DELETE(l_decree_hash_str);
-        } else {
-            char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
-            dap_chain_hash_fast_to_str(&l_tx, l_tx_hash_str, sizeof(l_tx_hash_str));
-            printf("Can't invalidate transaction %s, examine log files for details\n", l_tx_hash_str);
-            DAP_DEL_Z(l_decree);
-            return -15;
-        }
+        l_sign_str = dap_chain_wallet_check_sign(l_wallet);
     }
+    dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
+    l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key);
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
+    dap_chain_wallet_close(l_wallet);
+    dap_enc_key_delete(l_enc_key);
     return 0;
 }
 
@@ -3139,7 +3179,8 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
 {
 
 
-    dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
+    dap_chain_datum_tx_t *l_cond_tx = 
+    dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
     if (!l_cond_tx) {
         printf("Requested conditional transaction not found\n");
         return NULL;
@@ -3186,7 +3227,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     // list of transaction with 'out' items to sell
     uint256_t l_net_fee, l_fee_total = a_fee;
     dap_chain_addr_t l_net_fee_addr;
-    bool l_net_fee_used = dap_chain_net_tx_get_fee(a_net->pub.id, &l_net_fee, &l_net_fee_addr);
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(s_get_net_id(a_net_str), &l_net_fee, &l_net_fee_addr);
     if (l_net_fee_used)
         SUM_256_256(l_fee_total, l_net_fee, &l_fee_total);
     dap_list_t *l_list_fee_out = NULL; 
@@ -3250,578 +3291,574 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     return l_tx;
 }
 */
+/** 
+dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){
+    dap_chain_net_srv_order_t* l_order = NULL;
+    json_object *orders_array = json_object_array_get_idx(response, 0);
+    size_t orders_count = json_object_array_length(orders_array);
+    for (size_t i = 0; i < orders_count; i++) {
+        json_object *order_obj = json_object_array_get_idx(orders_array, i);
+        const char *order_hash_str = json_object_get_string(json_object_object_get(order_obj, "order"));
+
+        if (strcmp(order_hash_str, l_order_hash_str) == 0) {
+            l_order = DAP_NEW_Z_SIZE(dap_chain_net_srv_order_t, sizeof(dap_chain_net_srv_order_t));
+            l_order->version = json_object_get_int(json_object_object_get(order_obj, "version"));
+            l_order->direction = dap_chain_net_srv_order_direction_from_str(json_object_get_string(json_object_object_get(order_obj, "direction")));
+            l_order->ts_created = dap_time_from_str(json_object_get_string(json_object_object_get(order_obj, "created")));
+            l_order->srv_uid.uint64 = dap_chain_net_srv_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "srv_uid"))).uint64;
+            l_order->price = dap_uint256_scan_uninteger(json_object_get_string(json_object_object_get(order_obj, "price datoshi")));
+            strncpy(l_order->price_ticker, json_object_get_string(json_object_object_get(order_obj, "price token")), DAP_CHAIN_TICKER_SIZE_MAX);
+            l_order->units = json_object_get_int(json_object_object_get(order_obj, "units"));
+            l_order->price_unit = dap_chain_net_srv_price_unit_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "price unit")));
+            dap_chain_node_addr_from_str(&l_order->node_addr, json_object_get_string(json_object_object_get(order_obj, "node_addr")));
+            dap_chain_hash_fast_from_str(&l_order->tx_cond_hash, json_object_get_string(json_object_object_get(order_obj, "tx_cond_hash")));
+            l_order->ext_size = json_object_get_int(json_object_object_get(order_obj, "ext_size"));
+            if (l_order->ext_size > 0) {
+                const char *tax_str = json_object_get_string(json_object_object_get(order_obj, "tax"));
+                const char *value_max_str = json_object_get_string(json_object_object_get(order_obj, "maximum_value"));
+                *a_tax = dap_uint256_scan_decimal(tax_str);
+                *a_value_max = dap_uint256_scan_decimal(value_max_str);
+            }
 
-// dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){
-//     dap_chain_net_srv_order_t* l_order = NULL;
-//     json_object *orders_array = json_object_array_get_idx(response, 0);
-//     size_t orders_count = json_object_array_length(orders_array);
-//     for (size_t i = 0; i < orders_count; i++) {
-//         json_object *order_obj = json_object_array_get_idx(orders_array, i);
-//         const char *order_hash_str = json_object_get_string(json_object_object_get(order_obj, "order"));
-
-//         if (strcmp(order_hash_str, l_order_hash_str) == 0) {
-//             l_order = DAP_NEW_Z_SIZE(dap_chain_net_srv_order_t, sizeof(dap_chain_net_srv_order_t));
-//             l_order->version = json_object_get_int(json_object_object_get(order_obj, "version"));
-//             l_order->direction = dap_chain_net_srv_order_direction_from_str(json_object_get_string(json_object_object_get(order_obj, "direction")));
-//             l_order->ts_created = dap_time_from_str(json_object_get_string(json_object_object_get(order_obj, "created")));
-//             l_order->srv_uid.uint64 = dap_chain_net_srv_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "srv_uid"))).uint64;
-//             l_order->price = dap_uint256_scan_uninteger(json_object_get_string(json_object_object_get(order_obj, "price datoshi")));
-//             strncpy(l_order->price_ticker, json_object_get_string(json_object_object_get(order_obj, "price token")), DAP_CHAIN_TICKER_SIZE_MAX);
-//             l_order->units = json_object_get_int(json_object_object_get(order_obj, "units"));
-//             l_order->price_unit = dap_chain_net_srv_price_unit_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "price unit")));
-//             dap_chain_node_addr_from_str(&l_order->node_addr, json_object_get_string(json_object_object_get(order_obj, "node_addr")));
-//             dap_chain_hash_fast_from_str(&l_order->tx_cond_hash, json_object_get_string(json_object_object_get(order_obj, "tx_cond_hash")));
-//             l_order->ext_size = json_object_get_int(json_object_object_get(order_obj, "ext_size"));
-//             if (l_order->ext_size > 0) {
-//                 const char *tax_str = json_object_get_string(json_object_object_get(order_obj, "tax"));
-//                 const char *value_max_str = json_object_get_string(json_object_object_get(order_obj, "maximum_value"));
-//                 *a_tax = dap_uint256_scan_decimal(tax_str);
-//                 *a_value_max = dap_uint256_scan_decimal(value_max_str);
-//             }
-
-//             json_object *conditional_tx_params = json_object_object_get(order_obj, "conditional_tx_params");
-//             if (conditional_tx_params) {
-//                 const char *sovereign_tax_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_tax"));
-//                 const char *sovereign_addr_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_addr"));
-//                 *a_sovereign_tax = dap_uint256_scan_decimal(sovereign_tax_str);
-//                 a_sovereign_addr = dap_chain_addr_from_str(sovereign_addr_str);
-//             }
-//             break;
-//         }
-//     }
-//     return l_order;
-// }
+            json_object *conditional_tx_params = json_object_object_get(order_obj, "conditional_tx_params");
+            if (conditional_tx_params) {
+                const char *sovereign_tax_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_tax"));
+                const char *sovereign_addr_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_addr"));
+                *a_sovereign_tax = dap_uint256_scan_decimal(sovereign_tax_str);
+                a_sovereign_addr = dap_chain_addr_from_str(sovereign_addr_str);
+            }
+            break;
+        }
+    }
+    return l_order;
+}
 
-// dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax){
-//     char data[512];
-//     snprintf(data, sizeof(data), 
-//             "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", 
-//             l_net_str);
-//     json_object *response = s_request_command_to_rpc(data);
-//     if (!response) {
-//         printf("Error: Failed to get response from remote node\n");
-//         return NULL;
-//     }
+dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax){
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", 
+            l_net_str);
+    json_object *response = s_request_command_to_rpc(data);
+    if (!response) {
+        printf("Error: Failed to get response from remote node\n");
+        return NULL;
+    }
 
-//     dap_chain_net_srv_order_t *l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response);
-//     json_object_put(response);
-
-//     if (!l_order) {
-//         snprintf(data, sizeof(data), 
-//                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", 
-//                 l_net_str);
-//         response = s_request_command_to_rpc(data);
-//         if (!response) {
-//             printf("Error: Failed to get response from remote node\n");
-//             return NULL;
-//         }
-//         l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response);
-//         json_object_put(response);
-//     }
-//     return l_order;
-// }
+    dap_chain_net_srv_order_t *l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response);
+    json_object_put(response);
+
+    if (!l_order) {
+        snprintf(data, sizeof(data), 
+                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", 
+                l_net_str);
+        response = s_request_command_to_rpc(data);
+        if (!response) {
+            printf("Error: Failed to get response from remote node\n");
+            return NULL;
+        }
+        l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response);
+        json_object_put(response);
+    }
+    return l_order;
+}
 
 
 
 
-// static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
-// {
-//     int l_arg_index = 0;
-//     const char *l_net_str = NULL,
-//                *l_wallet_str = NULL,
-//                *l_cert_str = NULL,
-//                *l_pkey_str = NULL,
-//                *l_pkey_full_str = NULL,
-//                *l_sign_type_str = NULL,
-//                *l_value_str = NULL,
-//                *l_fee_str = NULL,
-//                *l_node_addr_str = NULL,
-//                *l_order_hash_str = NULL;
+static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
+{
+    int l_arg_index = 0;
+    const char *l_net_str = NULL,
+               *l_wallet_str = NULL,
+               *l_cert_str = NULL,
+               *l_pkey_str = NULL,
+               *l_pkey_full_str = NULL,
+               *l_sign_type_str = NULL,
+               *l_value_str = NULL,
+               *l_fee_str = NULL,
+               *l_node_addr_str = NULL,
+               *l_order_hash_str = NULL;
     
-//     dap_pkey_t *l_pkey = NULL;
-//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-net", &l_net_str);
-//     if (!l_net_str) {
-//         printf("Command 'delegate' requires parameter -net\n");
-//         return -1;
-//     }
+    dap_pkey_t *l_pkey = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-net", &l_net_str);
+    if (!l_net_str) {
+        printf("Command 'delegate' requires parameter -net\n");
+        return -1;
+    }
 
-//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-w", &l_wallet_str);
-//     if (!l_wallet_str) {
-//         printf("Command 'delegate' requires parameter -w\n");
-//         return -1;
-//     }
-//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL);
-//     if (!l_wallet) {
-//         printf("Specified wallet not found\n");
-//         return -2;
-//     }
-//     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
-//     dap_chain_wallet_close(l_wallet);
-//     dap_chain_addr_t l_signing_addr, l_sovereign_addr = {};
-//     uint256_t l_sovereign_tax = uint256_0;
-//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-cert", &l_cert_str);
-//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str);
-//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-sign_type", &l_sign_type_str);
-//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-order", &l_order_hash_str);
-//     if (!l_cert_str && !l_order_hash_str && !l_pkey_full_str) {
-//         printf("Command 'delegate' requires parameter -cert and/or -order and/or -pkey\n");
-//         dap_enc_key_delete(l_enc_key);
-//         return -1;
-//     }
-//     if (l_pkey_full_str) {
-//         printf("Command 'delegate' requires only one, -pkey or -pkey_full\n");
-//         dap_enc_key_delete(l_enc_key);
-//         return -1;
-//     }
-//     if (( l_pkey_full_str) && !l_sign_type_str) {
-//         printf("Command 'delegate' requires parameter -sign_type for pkey\n");
-//         dap_enc_key_delete(l_enc_key);
-//         return -1;
-//     }
-//     uint256_t l_value = uint256_0;
-//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-value", &l_value_str);
-//     if (!l_value_str) {
-//         if (!l_order_hash_str) {
-//             printf("Command 'delegate' requires parameter -value\n");
-//             dap_enc_key_delete(l_enc_key);
-//             return -1;
-//         }
-//     } else {
-//         l_value = dap_chain_balance_scan(l_value_str);
-//         if (IS_ZERO_256(l_value)) {
-//             printf("Unrecognized number in '-value' param\n");
-//             dap_enc_key_delete(l_enc_key);
-//             return -1;
-//         }
-//     }
-//     dap_chain_datum_tx_t *l_prev_tx = NULL;
-//     if (l_cert_str) {
-//         dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str);
-//         if (!l_signing_cert) {
-//             printf("Specified certificate not found\n");
-//             dap_enc_key_delete(l_enc_key);
-//             return -3;
-//         }
-//         if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(l_net_str))) {
-//             printf("Specified certificate is wrong\n");
-//             dap_enc_key_delete(l_enc_key);
-//             return -4;
-//         }
-//         l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key);
-//         dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
-//     } 
-//     else if (l_pkey_full_str) {
-//         dap_sign_type_t l_type = dap_sign_type_from_str(l_sign_type_str);
-//         if (l_type.type == SIG_TYPE_NULL) {
-//             printf("Wrong sign type\n");
-//             dap_enc_key_delete(l_enc_key);
-//             return -5;
-//         }
-//         l_pkey = dap_pkey_get_from_str(l_pkey_full_str);
-//         if (!l_pkey) {
-//             printf("Invalid pkey string format, can't get pkey_full\n");
-//             dap_enc_key_delete(l_enc_key);
-//             return -6;
-//         }
-//         if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) {
-//             printf("pkey and sign types is different\n");
-//             dap_enc_key_delete(l_enc_key);
-//             return -6;
-//         }
-//         dap_chain_hash_fast_t l_hash_public_key = {0};
-//         if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) {
-//             printf("Invalid pkey hash format\n");
-//             dap_enc_key_delete(l_enc_key);
-//             return -6;
-//         }
-//         dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(l_net_str));
-//         dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
-//     }
+    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-w", &l_wallet_str);
+    if (!l_wallet_str) {
+        printf("Command 'delegate' requires parameter -w\n");
+        return -1;
+    }
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL);
+    if (!l_wallet) {
+        printf("Specified wallet not found\n");
+        return -2;
+    }
+    dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
+    dap_chain_wallet_close(l_wallet);
+    dap_chain_addr_t l_signing_addr, l_sovereign_addr = {};
+    uint256_t l_sovereign_tax = uint256_0;
+    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-cert", &l_cert_str);
+    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str);
+    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-sign_type", &l_sign_type_str);
+    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-order", &l_order_hash_str);
+    if (!l_cert_str && !l_order_hash_str && !l_pkey_full_str) {
+        printf("Command 'delegate' requires parameter -cert and/or -order and/or -pkey\n");
+        dap_enc_key_delete(l_enc_key);
+        return -1;
+    }
+    if (l_pkey_full_str) {
+        printf("Command 'delegate' requires only one, -pkey or -pkey_full\n");
+        dap_enc_key_delete(l_enc_key);
+        return -1;
+    }
+    if (( l_pkey_full_str) && !l_sign_type_str) {
+        printf("Command 'delegate' requires parameter -sign_type for pkey\n");
+        dap_enc_key_delete(l_enc_key);
+        return -1;
+    }
+    uint256_t l_value = uint256_0;
+    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-value", &l_value_str);
+    if (!l_value_str) {
+        if (!l_order_hash_str) {
+            printf("Command 'delegate' requires parameter -value\n");
+            dap_enc_key_delete(l_enc_key);
+            return -1;
+        }
+    } else {
+        l_value = dap_chain_balance_scan(l_value_str);
+        if (IS_ZERO_256(l_value)) {
+            printf("Unrecognized number in '-value' param\n");
+            dap_enc_key_delete(l_enc_key);
+            return -1;
+        }
+    }
+    dap_chain_datum_tx_t *l_prev_tx = NULL;
+    if (l_cert_str) {
+        dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str);
+        if (!l_signing_cert) {
+            printf("Specified certificate not found\n");
+            dap_enc_key_delete(l_enc_key);
+            return -3;
+        }
+        if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(l_net_str))) {
+            printf("Specified certificate is wrong\n");
+            dap_enc_key_delete(l_enc_key);
+            return -4;
+        }
+        l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key);
+        dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
+    } 
+    else if (l_pkey_full_str) {
+        dap_sign_type_t l_type = dap_sign_type_from_str(l_sign_type_str);
+        if (l_type.type == SIG_TYPE_NULL) {
+            printf("Wrong sign type\n");
+            dap_enc_key_delete(l_enc_key);
+            return -5;
+        }
+        l_pkey = dap_pkey_get_from_str(l_pkey_full_str);
+        if (!l_pkey) {
+            printf("Invalid pkey string format, can't get pkey_full\n");
+            dap_enc_key_delete(l_enc_key);
+            return -6;
+        }
+        if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) {
+            printf("pkey and sign types is different\n");
+            dap_enc_key_delete(l_enc_key);
+            return -6;
+        }
+        dap_chain_hash_fast_t l_hash_public_key = {0};
+        if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) {
+            printf("Invalid pkey hash format\n");
+            dap_enc_key_delete(l_enc_key);
+            return -6;
+        }
+        dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(l_net_str));
+        dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
+    }
+
+    dap_chain_node_addr_t l_node_addr = g_node_addr;
+    if (l_node_addr_str) {
+        if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) {
+            printf("Unrecognized node addr %s\n", l_node_addr_str);
+            dap_enc_key_delete(l_enc_key);
+            return -7;
+        }
+    }
+    if (l_order_hash_str) {
+        uint256_t l_tax;
+        uint256_t l_value_max;
+        int l_prev_tx_count = 0;
+        dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax);
+
+        if (l_order->direction == SERV_DIR_BUY) { // Staker order
+            if (!l_cert_str) {
+                printf("Command 'delegate' requires parameter -cert with this order type\n");
+                dap_enc_key_delete(l_enc_key);
+                return -1;
+            }
+            if (l_order->ext_size != 0) {
+                printf("Specified order has invalid size\n");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -9;
+            }
 
-//     dap_chain_node_addr_t l_node_addr = g_node_addr;
-//     if (l_node_addr_str) {
-//         if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) {
-//             printf("Unrecognized node addr %s\n", l_node_addr_str);
-//             dap_enc_key_delete(l_enc_key);
-//             return -7;
-//         }
-//     }
-//     if (l_order_hash_str) {
-
-//         uint256_t l_tax;
-//         uint256_t l_value_max;
-//         int l_prev_tx_count = 0;
-//         dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax);
-
-//         if (l_order->direction == SERV_DIR_BUY) { // Staker order
-//             if (!l_cert_str) {
-//                 printf("Command 'delegate' requires parameter -cert with this order type\n");
-//                 dap_enc_key_delete(l_enc_key);
-//                 return -1;
-//             }
-//             if (l_order->ext_size != 0) {
-//                 printf("Specified order has invalid size\n");
-//                 dap_enc_key_delete(l_enc_key);
-//                 DAP_DELETE(l_order);
-//                 return -9;
-//             }
-
-//             dap_chain_tx_out_cond_t *l_cond_tx = NULL;
-//             char data[512];
-//             snprintf(data, sizeof(data), 
-//                     "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-//                     l_order->tx_cond_hash, l_net_str);
+            dap_chain_tx_out_cond_t *l_cond_tx = NULL;
+            char data[512];
+            snprintf(data, sizeof(data), 
+                    "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+                    l_order->tx_cond_hash, l_net_str);
             
-//             json_object *response = s_request_command_to_rpc(data);
-//             if (!response) {
-//                 printf("Error: Failed to get response from remote node\n");
-//                 return -15;
-//             }
+            json_object *response = s_request_command_to_rpc(data);
+            if (!response) {
+                printf("Error: Failed to get response from remote node\n");
+                return -15;
+            }
             
-//             json_object *items = json_object_object_get(response, "ITEMS");
-//             if (!items) {
-//                 printf("Error: No items found in response\n");
-//                 return -16;
-//             }
-//             int items_count = json_object_array_length(items);
-//             for (int i = 0; i < items_count; i++) {
-//                 json_object *item = json_object_array_get_idx(items, i);
-//                 const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
-//                 if (dap_strcmp(item_type, "OUT COND") == 0) {
-//                     const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
-//                     if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE")) {
-//                         l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
-//                         l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
-//                         l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
-//                         l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE;
-//                         l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
-//                         l_cond_tx->header.ts_expires = dap_time_from_str(json_object_get_string(json_object_object_get(item, "ts_expires")));
-//                         l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr")));
-//                         if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) {
-//                             printf("Error: Failed to parse signer node address\n");
-//                             return -17;
-//                         }
-//                         l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
-//                         l_prev_tx_count++;
-//                         break;
-//                     }
-//                 } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) {
-//                     l_prev_tx_count++;
-//                 }
-//             }
-//             if (!l_cond_tx) {
-//                 printf("Error: No transaction output condition found\n");
-//                 return -7;
-//             }
-
-//             json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
-//             const char *spent_outs_value = json_object_get_string(spent_outs);
-//             if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
-//                 printf("Error: Transaction output item already used\n");
-//                 return -9;
-//             }
-
-
-
-//             // l_prev_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash);
-//             // if (!l_prev_tx) {
-//             //     printf("The order's conditional transaction not found in ledger\n");
-//             //     dap_enc_key_delete(l_enc_key);
-//             //     DAP_DELETE(l_order);
-//             //     return -10;
-//             // }
-//             // int l_out_num = 0;
-//             // dap_chain_tx_out_cond_t *l_cond_tx = dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
-//             // if (!l_cond) {
-//             //     printf("The order's conditional transaction has invalid type\n");
-//             //     dap_enc_key_delete(l_enc_key);
-//             //     DAP_DELETE(l_order);
-//             //     return -11;
-//             // }
-//             // if (dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_order->tx_cond_hash, l_out_num, NULL)) {
-//             //     printf("The order's conditional transaction is already spent\n");
-//             //     dap_enc_key_delete(l_enc_key);
-//             //     DAP_DELETE(l_order);
-//             //     return -12;
-//             // }
-
-//             char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
-//             dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(l_net_str));
-//             const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker"));
-//             if (!l_token_ticker) {
-//                 printf("Error: Token ticker not found in response\n");
-//                 return -18;
-//             }
-//             json_object_put(response);
-//             if (dap_strcmp(l_token_ticker, l_delegated_ticker)) {
-//                 printf("Requested conditional transaction have another ticker (not %s)\n", l_delegated_ticker);
-//                 return -13;
-//             }
-//             if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) {
-//                 printf("The order's conditional transaction has invalid format\n");
-//                 dap_enc_key_delete(l_enc_key);
-//                 DAP_DELETE(l_order);
-//                 return -14;
-//             }
-//             if (compare256(l_cond_tx->header.value, l_order->price)) {
-//                 printf("The order's conditional transaction has different value\n");
-//                 dap_enc_key_delete(l_enc_key);
-//                 DAP_DELETE(l_order);
-//                 return -15;
-//             }
-//             if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) ||
-//                     l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) {
-//                 printf("The order's conditional transaction gas not blank address or key\n");
-//                 dap_enc_key_delete(l_enc_key);
-//                 DAP_DELETE(l_order);
-//                 return -16;
-//             }
-//             l_value = l_order->price;
-//             // dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR);
-//             // l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE);
-//             // l_sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t);
-//             // MULT_256_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
-//         }
-//         /** TODO add new command to get l_pkey from order
-//          * else {
-//             if (!l_value_str) {
-//                 printf("Command 'delegate' requires parameter -value with this order type\n");
-//                 dap_enc_key_delete(l_enc_key);
-//                 return -1;
-//             }
-//             const char *l_sovereign_addr_str = NULL;
-//             dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str);
-//             if (l_sovereign_addr_str) {
-//                 dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str);
-//                 if (!l_spec_addr) {
-//                     printf("Specified address is ivalid\n");
-//                     return -17;
-//                 }
-//                 l_sovereign_addr = *l_spec_addr;
-//                 DAP_DELETE(l_spec_addr);
-//             } else
-//                 dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, s_get_net_id(l_net_str));
-
-//             if (l_order_hash_str && compare256(l_value, l_order->price) == -1) {
-//                 const char *l_coin_min_str, *l_value_min_str =
-//                     dap_uint256_to_char(l_order->price, &l_coin_min_str);
-//                 printf("Number in '-value' param %s is lower than order minimum allowed value %s(%s)\n",
-//                                                   l_value_str, l_coin_min_str, l_value_min_str);
-//                 dap_enc_key_delete(l_enc_key);
-//                 return -18;
-//             }
-//             if (l_order_hash_str && compare256(l_value, l_value_max) == 1) {
-//                 const char *l_coin_max_str, *l_value_max_str =
-//                     dap_uint256_to_char(l_value_max, &l_coin_max_str);
-//                 printf("Number in '-value' param %s is higher than order minimum allowed value %s(%s)\n",
-//                                                   l_value_str, l_coin_max_str, l_value_max_str);
-//                 dap_enc_key_delete(l_enc_key);
-//                 return -19;
-//             }
-//             dap_sign_t *l_sign = (dap_sign_t *)(l_order->ext_n_sign + l_order->ext_size);
-//             if (l_sign->header.type.type == SIG_TYPE_NULL) {
-//                 printf("Specified order is unsigned\n");
-//                 dap_enc_key_delete(l_enc_key);
-//                 DAP_DELETE(l_order);
-//                 return -20;
-//             }
-//             dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_net->pub.id);
-//             l_pkey = dap_pkey_get_from_sign(l_sign);
-//             char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX];
-//             dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_net->pub.native_ticker);
-//             if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) {
-//                 printf("Specified order is invalid\n");
-//                 dap_enc_key_delete(l_enc_key);
-//                 DAP_DELETE(l_order);
-//                 return -21;
-//             }
-//             l_node_addr = l_order->node_addr;
-//         }
-//         DAP_DELETE(l_order);
-//         if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 ||
-//                 compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) {
-//             printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n");
-//             dap_enc_key_delete(l_enc_key);
-//             return -22;
-//         }
-//         DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
-//     }
-//     */
-//     if (!l_pkey) {
-//         printf("pkey not defined\n");
-//         dap_enc_key_delete(l_enc_key);
-//         return -6;
-//     }
+            json_object *items = json_object_object_get(response, "ITEMS");
+            if (!items) {
+                printf("Error: No items found in response\n");
+                return -16;
+            }
+            int items_count = json_object_array_length(items);
+            for (int i = 0; i < items_count; i++) {
+                json_object *item = json_object_array_get_idx(items, i);
+                const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+                if (dap_strcmp(item_type, "OUT COND") == 0) {
+                    const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+                    if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE")) {
+                        l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+                        l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+                        l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+                        l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE;
+                        l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+                        l_cond_tx->header.ts_expires = dap_time_from_str(json_object_get_string(json_object_object_get(item, "ts_expires")));
+                        l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr")));
+                        if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) {
+                            printf("Error: Failed to parse signer node address\n");
+                            return -17;
+                        }
+                        l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
+                        l_prev_tx_count++;
+                        break;
+                    }
+                } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) {
+                    l_prev_tx_count++;
+                }
+            }
+            if (!l_cond_tx) {
+                printf("Error: No transaction output condition found\n");
+                return -7;
+            }
 
-//     int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr);
-//     if (l_check_result) {
-//         printf("Key and node verification error\n");
-//         dap_enc_key_delete(l_enc_key);
-//         return l_check_result;
-//     }
+            json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
+            const char *spent_outs_value = json_object_get_string(spent_outs);
+            if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
+                printf("Error: Transaction output item already used\n");
+                return -9;
+            }
+
+
+
+            l_prev_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash);
+            if (!l_prev_tx) {
+                printf("The order's conditional transaction not found in ledger\n");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -10;
+            }
+            int l_out_num = 0;
+            dap_chain_tx_out_cond_t *l_cond_tx = dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
+            if (!l_cond) {
+                printf("The order's conditional transaction has invalid type\n");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -11;
+            }
+            if (dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_order->tx_cond_hash, l_out_num, NULL)) {
+                printf("The order's conditional transaction is already spent\n");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -12;
+            }
+
+            char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+            dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(l_net_str));
+            const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker"));
+            if (!l_token_ticker) {
+                printf("Error: Token ticker not found in response\n");
+                return -18;
+            }
+            json_object_put(response);
+            if (dap_strcmp(l_token_ticker, l_delegated_ticker)) {
+                printf("Requested conditional transaction have another ticker (not %s)\n", l_delegated_ticker);
+                return -13;
+            }
+            if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) {
+                printf("The order's conditional transaction has invalid format\n");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -14;
+            }
+            if (compare256(l_cond_tx->header.value, l_order->price)) {
+                printf("The order's conditional transaction has different value\n");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -15;
+            }
+            if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) ||
+                    l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) {
+                printf("The order's conditional transaction gas not blank address or key\n");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -16;
+            }
+            l_value = l_order->price;
+            // dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR);
+            // l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE);
+            // l_sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t);
+            // MULT_256_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
+        } else {
+            if (!l_value_str) {
+                printf("Command 'delegate' requires parameter -value with this order type\n");
+                dap_enc_key_delete(l_enc_key);
+                return -1;
+            }
+            const char *l_sovereign_addr_str = NULL;
+            dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str);
+            if (l_sovereign_addr_str) {
+                dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str);
+                if (!l_spec_addr) {
+                    printf("Specified address is ivalid\n");
+                    return -17;
+                }
+                l_sovereign_addr = *l_spec_addr;
+                DAP_DELETE(l_spec_addr);
+            } else
+                dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, s_get_net_id(l_net_str));
+
+            if (l_order_hash_str && compare256(l_value, l_order->price) == -1) {
+                const char *l_coin_min_str, *l_value_min_str =
+                    dap_uint256_to_char(l_order->price, &l_coin_min_str);
+                printf("Number in '-value' param %s is lower than order minimum allowed value %s(%s)\n",
+                                                  l_value_str, l_coin_min_str, l_value_min_str);
+                dap_enc_key_delete(l_enc_key);
+                return -18;
+            }
+            if (l_order_hash_str && compare256(l_value, l_value_max) == 1) {
+                const char *l_coin_max_str, *l_value_max_str =
+                    dap_uint256_to_char(l_value_max, &l_coin_max_str);
+                printf("Number in '-value' param %s is higher than order minimum allowed value %s(%s)\n",
+                                                  l_value_str, l_coin_max_str, l_value_max_str);
+                dap_enc_key_delete(l_enc_key);
+                return -19;
+            }
+            dap_sign_t *l_sign = (dap_sign_t *)(l_order->ext_n_sign + l_order->ext_size);
+            if (l_sign->header.type.type == SIG_TYPE_NULL) {
+                printf("Specified order is unsigned\n");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -20;
+            }
+            dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_net->pub.id);
+            l_pkey = dap_pkey_get_from_sign(l_sign);
+            char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX];
+            dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_net->pub.native_ticker);
+            if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) {
+                printf("Specified order is invalid\n");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -21;
+            }
+            l_node_addr = l_order->node_addr;
+        }
+        DAP_DELETE(l_order);
+        if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 ||
+                compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) {
+            printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n");
+            dap_enc_key_delete(l_enc_key);
+            return -22;
+        }
+        DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
+    }
+    if (!l_pkey) {
+        printf("pkey not defined\n");
+        dap_enc_key_delete(l_enc_key);
+        return -6;
+    }
+
+    int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr);
+    if (l_check_result) {
+        printf("Key and node verification error\n");
+        dap_enc_key_delete(l_enc_key);
+        return l_check_result;
+    }
  
 
-//     uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str);
-//     if (compare256(l_value, l_allowed_min) == -1) {
-//         const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str);
-//         printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n",
-//                                           l_value_str, l_coin_min_str, l_value_min_str);
-//         dap_enc_key_delete(l_enc_key);
-//         return -23;
-//     }
-//     dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-fee", &l_fee_str);
-//     if (!l_fee_str) {
-//         printf("Command 'delegate' requires parameter -fee\n");
-//         dap_enc_key_delete(l_enc_key);
-//         return -1;
-//     }
-//     uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
-//     if (IS_ZERO_256(l_fee)) {
-//         printf("Unrecognized number in '-fee' param\n");
-//         dap_enc_key_delete(l_enc_key);
-//         return -1;
-//     }
+    uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str);
+    if (compare256(l_value, l_allowed_min) == -1) {
+        const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str);
+        printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n",
+                                          l_value_str, l_coin_min_str, l_value_min_str);
+        dap_enc_key_delete(l_enc_key);
+        return -23;
+    }
+    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-fee", &l_fee_str);
+    if (!l_fee_str) {
+        printf("Command 'delegate' requires parameter -fee\n");
+        dap_enc_key_delete(l_enc_key);
+        return -1;
+    }
+    uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+    if (IS_ZERO_256(l_fee)) {
+        printf("Unrecognized number in '-fee' param\n");
+        dap_enc_key_delete(l_enc_key);
+        return -1;
+    }
 
-//     // Create conditional transaction
-//     dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr,
-//                                                    l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_prev_tx_count, l_pkey);
-//     dap_enc_key_delete(l_enc_key);
-//     DAP_DELETE(l_pkey);
+    // Create conditional transaction
+    dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr,
+                                                   l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_prev_tx_count, l_pkey);
+    dap_enc_key_delete(l_enc_key);
+    DAP_DELETE(l_pkey);
 
-//     DAP_DELETE(l_tx);
+    DAP_DELETE(l_tx);
 
-//     return 0;
+    return 0;
 
-// }
+}
 
-// // Freeze staker's funds when delegating a key
-// dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc_key_t *a_key,
-//                                                uint256_t a_value, uint256_t a_fee,
-//                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
-//                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
-//                                                dap_chain_datum_tx_t *a_prev_tx, int l_prev_tx_count, dap_pkey_t *a_pkey)
-// {
-//     dap_return_val_if_pass (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr, NULL);
-
-//     const char *l_native_ticker = s_get_native_ticker(a_net_str);
-//     char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
-//     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker);
-//     uint256_t l_value_transfer = {}, l_fee_transfer = {}; // how many coins to transfer
-//     // list of transaction with 'out' items to sell
-//     dap_chain_addr_t l_owner_addr;
-//     dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str));
-//     uint256_t l_net_fee, l_fee_total = a_fee;
-//     dap_chain_addr_t l_net_fee_addr;
-//     bool l_net_fee_used = get_remote_net_fee(a_net_str, l_native_ticker, &l_net_fee, &l_net_fee_addr);
-//     if (l_net_fee_used)
-//         SUM_256_256(l_fee_total, l_net_fee, &l_fee_total);
-
-//     dap_list_t *l_list_fee_out = NULL;
-//     if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101)
-//         l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker,
-//                                                                       &l_owner_addr, l_fee_total, &l_fee_transfer);
-//     if (!l_list_fee_out) {
-//         log_it(L_WARNING, "Nothing to pay for fee (not enough funds)");
-//         return NULL;
-//     }
+// Freeze staker's funds when delegating a key
+dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc_key_t *a_key,
+                                               uint256_t a_value, uint256_t a_fee,
+                                               dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
+                                               dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
+                                               dap_chain_datum_tx_t *a_prev_tx, int l_prev_tx_count, dap_pkey_t *a_pkey)
+{
+    dap_return_val_if_pass (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr, NULL);
 
-//     // create empty transaction
-//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-
-//     if (!a_prev_tx) {
-//         dap_list_t *l_list_used_out = NULL  ;
-//         if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_delegated_ticker, &l_owner_addr, &l_list_used_out, a_value, &l_value_transfer) == -101)
-//             l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_delegated_ticker,
-//                                                                            &l_owner_addr, a_value, &l_value_transfer);
-//         if (!l_list_used_out) {
-//             log_it(L_WARNING, "Nothing to pay for delegate (not enough funds)");
-//             goto tx_fail;
-//         }
-//         // add 'in' items to pay for delegate
-//         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-//         dap_list_free_full(l_list_used_out, NULL);
-//         if (!EQUAL_256(l_value_to_items, l_value_transfer)) {
-//             log_it(L_ERROR, "Can't compose the transaction input");
-//             goto tx_fail;
-//         }
-//     } else {
-//         dap_hash_fast_t l_prev_tx_hash;
-//         dap_hash_fast(a_prev_tx, dap_chain_datum_tx_get_size(a_prev_tx), &l_prev_tx_hash);
-//         int l_out_num = 0;
-//         dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
-//         // add 'in' item to buy from conditional transaction
-//         if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_prev_tx_count, -1)) {
-//             log_it(L_ERROR, "Can't compose the transaction conditional input");
-//             goto tx_fail;
-//         }
-//     }
-//     // add 'in' items to pay fee
-//     uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-//     dap_list_free_full(l_list_fee_out, NULL);
-//     if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
-//         log_it(L_ERROR, "Can't compose the fee transaction input");
-//         goto tx_fail;
-//     }
+    const char *l_native_ticker = s_get_native_ticker(a_net_str);
+    char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+    dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker);
+    uint256_t l_value_transfer = {}, l_fee_transfer = {}; // how many coins to transfer
+    // list of transaction with 'out' items to sell
+    dap_chain_addr_t l_owner_addr;
+    dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str));
+    uint256_t l_net_fee, l_fee_total = a_fee;
+    dap_chain_addr_t l_net_fee_addr;
+    bool l_net_fee_used = get_remote_net_fee(a_net_str, l_native_ticker, &l_net_fee, &l_net_fee_addr);
+    if (l_net_fee_used)
+        SUM_256_256(l_fee_total, l_net_fee, &l_fee_total);
 
-//     // add 'out_cond' & 'out_ext' items
-//     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID };
-//     dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_value, a_signing_addr, a_node_addr,
-//                                                                                           a_sovereign_addr, a_sovereign_tax, a_pkey);
+    dap_list_t *l_list_fee_out = NULL;
+    if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101)
+        l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker,
+                                                                      &l_owner_addr, l_fee_total, &l_fee_transfer);
+    if (!l_list_fee_out) {
+        log_it(L_WARNING, "Nothing to pay for fee (not enough funds)");
+        return NULL;
+    }
 
-//     if (!l_tx_out) {
-//         log_it(L_ERROR, "Can't compose the transaction conditional output");
-//         goto tx_fail;
-//     }
-//     dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
-//     DAP_DELETE(l_tx_out);
-//     if (!a_prev_tx) {
-//         // coin back
-//         uint256_t l_value_back = {};
-//         SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back);
-//         if (!IS_ZERO_256(l_value_back)) {
-//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) {
-//                 log_it(L_ERROR, "Cant add coin back output");
-//                 goto tx_fail;
-//             }
-//         }
-//     }
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
-//     // add fee items
-//     if (l_net_fee_used) {
-//         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
-//             log_it(L_ERROR, "Cant add net fee output");
-//             goto tx_fail;
-//         }
-//     }
-//     if (!IS_ZERO_256(a_fee)) {
-//         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
-//             log_it(L_ERROR, "Cant add validator fee output");
-//             goto tx_fail;
-//         }
-//     }
-//     uint256_t l_fee_back = {};
-//     // fee coin back
-//     SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back);
-//     if (!IS_ZERO_256(l_fee_back)) {
-//         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) {
-//             log_it(L_ERROR, "Cant add fee back output");
-//             goto tx_fail;
-//         }
-//     }
+    if (!a_prev_tx) {
+        dap_list_t *l_list_used_out = NULL  ;
+        if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_delegated_ticker, &l_owner_addr, &l_list_used_out, a_value, &l_value_transfer) == -101)
+            l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_delegated_ticker,
+                                                                           &l_owner_addr, a_value, &l_value_transfer);
+        if (!l_list_used_out) {
+            log_it(L_WARNING, "Nothing to pay for delegate (not enough funds)");
+            goto tx_fail;
+        }
+        // add 'in' items to pay for delegate
+        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+        dap_list_free_full(l_list_used_out, NULL);
+        if (!EQUAL_256(l_value_to_items, l_value_transfer)) {
+            log_it(L_ERROR, "Can't compose the transaction input");
+            goto tx_fail;
+        }
+    } else {
+        dap_hash_fast_t l_prev_tx_hash;
+        dap_hash_fast(a_prev_tx, dap_chain_datum_tx_get_size(a_prev_tx), &l_prev_tx_hash);
+        int l_out_num = 0;
+        dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
+        // add 'in' item to buy from conditional transaction
+        if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_prev_tx_count, -1)) {
+            log_it(L_ERROR, "Can't compose the transaction conditional input");
+            goto tx_fail;
+        }
+    }
+    // add 'in' items to pay fee
+    uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+    dap_list_free_full(l_list_fee_out, NULL);
+    if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
+        log_it(L_ERROR, "Can't compose the fee transaction input");
+        goto tx_fail;
+    }
 
-//     // add 'sign' item
-//     if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) {
-//         log_it(L_ERROR, "Can't add sign output");
-//         goto tx_fail;
-//     }
+    // add 'out_cond' & 'out_ext' items
+    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID };
+    dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_value, a_signing_addr, a_node_addr,
+                                                                                          a_sovereign_addr, a_sovereign_tax, a_pkey);
 
-//     return l_tx;
+    if (!l_tx_out) {
+        log_it(L_ERROR, "Can't compose the transaction conditional output");
+        goto tx_fail;
+    }
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
+    DAP_DELETE(l_tx_out);
+    if (!a_prev_tx) {
+        // coin back
+        uint256_t l_value_back = {};
+        SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back);
+        if (!IS_ZERO_256(l_value_back)) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) {
+                log_it(L_ERROR, "Cant add coin back output");
+                goto tx_fail;
+            }
+        }
+    }
 
-// tx_fail:
-//     dap_chain_datum_tx_delete(l_tx);
-//     return NULL;
-// }
+    // add fee items
+    if (l_net_fee_used) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
+            log_it(L_ERROR, "Cant add net fee output");
+            goto tx_fail;
+        }
+    }
+    if (!IS_ZERO_256(a_fee)) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
+            log_it(L_ERROR, "Cant add validator fee output");
+            goto tx_fail;
+        }
+    }
+    uint256_t l_fee_back = {};
+    // fee coin back
+    SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back);
+    if (!IS_ZERO_256(l_fee_back)) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) {
+            log_it(L_ERROR, "Cant add fee back output");
+            goto tx_fail;
+        }
+    }
+
+    // add 'sign' item
+    if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) {
+        log_it(L_ERROR, "Can't add sign output");
+        goto tx_fail;
+    }
+
+    return l_tx;
 
+tx_fail:
+    dap_chain_datum_tx_delete(l_tx);
+    return NULL;
+}
+*/
 
 // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value>
 // int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) {
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 4fe3739f61..6f07efe7b2 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -44,7 +44,7 @@ typedef struct {
 } NetInfo;
 
 static NetInfo netinfo[NET_COUNT] = {
-    {"riemann",  "tKEL",  {.uint64 = 0x000000000000dddd}, "45.76.140.191", 8081},
+    {"riemann",  "tKEL",  {.uint64 = 0x000000000000dddd}, "http://rpc.cellframe.net", 8081},
     {"raiden",   "tCELL", {.uint64 = 0x000000000000bbbb}, "http://rpc.cellframe.net", 8081},
     {"KelVPN",   "KEL",   {.uint64 = 0x1807202300000000}, "http://rpc.cellframe.net", 8081},
     {"Backbone", "CELL",  {.uint64 = 0x0404202200000000}, "http://rpc.cellframe.net", 8081},
@@ -67,30 +67,38 @@ int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
 
 dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer);
 dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
-                                                        const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num);
-dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,const char *a_token_sell, 
-                                                        uint256_t a_datoshi_sell, uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet);
+        const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port);
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, const char *a_token_sell, uint256_t a_datoshi_sell,
+                                     uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port);
 dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
-                                                                const char *a_native_ticker, const char *a_net_name);
+                                                                const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port);
 dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name,
         dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
         const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
         uint256_t a_value, uint256_t a_value_per_unit_max,
         dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
         uint256_t a_value_fee, const void *a_cond,
-        size_t a_cond_size);
-bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee);
-bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count);
-dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, const char *a_main_ticker,
-                                                    uint256_t a_value, uint256_t a_value_fee, dap_time_t a_time_staking, uint256_t a_reinvest_percent,
-                                                    const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * l_chain_id_str);
+        size_t a_cond_size, const char *a_url_str, uint16_t a_port);
+bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, const char * a_url_str, uint16_t a_port);
+bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name,
+                                         json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port);
+dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
+                                                    const char *a_main_ticker,
+                                                    uint256_t a_value, uint256_t a_value_fee,
+                                                    dap_time_t a_time_staking, uint256_t a_reinvest_percent,
+                                                    const char *a_delegated_ticker_str, uint256_t a_delegated_value,
+                                                    const char * l_chain_id_str, const char *l_url_str, uint16_t l_port);
 bool check_token_in_ledger(json_object *l_json_coins, const char *a_token);
-dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
-                                               const char *a_main_ticker, uint256_t a_value, uint256_t a_value_fee, const char *a_delegated_ticker_str, uint256_t a_delegated_value);
+dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
+                                               dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
+                                               const char *a_main_ticker, uint256_t a_value,
+                                               uint256_t a_value_fee,
+                                               const char *a_delegated_ticker_str, uint256_t a_delegated_value,
+                                               const char *l_url_str, uint16_t l_port);
 dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
-                              const char *a_net_str, const char *a_token_ticker);
+                              const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port);
 
 #ifdef __cplusplus
 }
-- 
GitLab


From 9cdcc78bf87a463f744e7fac78b948152247319c Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Fri, 28 Mar 2025 12:21:18 +0700
Subject: [PATCH 26/53] [*] fix

---
 modules/compose/include/dap_chain_tx_compose.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 6f07efe7b2..d88f925cd2 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -44,7 +44,7 @@ typedef struct {
 } NetInfo;
 
 static NetInfo netinfo[NET_COUNT] = {
-    {"riemann",  "tKEL",  {.uint64 = 0x000000000000dddd}, "http://rpc.cellframe.net", 8081},
+    {"riemann",  "tKEL",  {.uint64 = 0x000000000000dddd}, "45.76.140.191", 8081},
     {"raiden",   "tCELL", {.uint64 = 0x000000000000bbbb}, "http://rpc.cellframe.net", 8081},
     {"KelVPN",   "KEL",   {.uint64 = 0x1807202300000000}, "http://rpc.cellframe.net", 8081},
     {"Backbone", "CELL",  {.uint64 = 0x0404202200000000}, "http://rpc.cellframe.net", 8081},
-- 
GitLab


From 34a1b177b82e686d80facaa05d7fdc7992861764 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Fri, 28 Mar 2025 15:41:57 +0700
Subject: [PATCH 27/53] [*] invalidate

---
 dap-sdk                                |  2 +-
 modules/compose/dap_chain_tx_compose.c | 54 ++++++++++++++++----------
 2 files changed, 35 insertions(+), 21 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index 5afcf73284..695db02acc 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 5afcf7328475a0dfce4eb7630876cf1d79fa0329
+Subproject commit 695db02acc05add13e8ba75c13812148aaeb6e63
diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index f0dbdd845e..114103eb1f 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -2976,14 +2976,17 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
 */
 
 
-/** 
+/**
 static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
 {
     const char *l_net_str = NULL,
                *l_wallet_str = NULL,
                *l_cert_str = NULL,
                *l_fee_str = NULL,
-               *l_tx_hash_str = NULL;
+               *l_tx_hash_str = NULL,
+               *l_url_str = NULL,
+               *l_port_str = NULL;
+    uint16_t l_port = 0;
                
     int l_arg_index = 1;
     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
@@ -2991,6 +2994,14 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
         printf("Command 'invalidate' requires parameter -net\n");
         return -1;
     }
+    if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
+        l_url_str = s_get_net_url(l_net_str);
+    }
+    if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
+        l_port = atoi(l_port_str);
+    } else {
+        l_port = s_get_net_port(l_net_str);
+    }
 
     uint256_t l_fee = {};
     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
@@ -3037,20 +3048,13 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
                 printf("Specified certificate is wrong\n");
                 return -6;
             }
-        } else {
-            dap_hash_fast_t l_pkey_hash = {};
-            if (dap_chain_hash_fast_from_str(l_signing_pkey_hash_str, &l_pkey_hash)) {
-                printf("Invalid pkey hash format\n");
-                return -7;
-            }
-            dap_chain_addr_fill(&l_signing_addr, dap_sign_type_from_str(l_signing_pkey_type_str), &l_pkey_hash, s_get_net_id(l_net_str));
         }
+        const char *l_addr_str = dap_chain_addr_to_str_static(&l_signing_addr);
 
-        
         char data[512];
         snprintf(data, sizeof(data), 
                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", l_net_str);
-        json_object *l_json_coins = s_request_command_to_rpc(data);
+        json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
         if (!l_json_coins) {
             printf("Error: Failed to retrieve coins from ledger\n");
             return -4;
@@ -3060,8 +3064,8 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
         bool found = false;
         for (int i = 0; i < items_count; i++) {
             json_object *item = json_object_array_get_idx(l_json_coins, i);
-            const char *pkey_hash_str = json_object_get_string(json_object_object_get(item, "pkey_hash"));
-            if (l_signing_pkey_hash_str && !dap_strcmp(l_signing_pkey_hash_str, pkey_hash_str)) {
+            const char *node_addr_str = json_object_get_string(json_object_object_get(item, "node_addr"));
+            if (node_addr_str && !dap_strcmp(l_addr_str, node_addr_str)) {
                 const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash"));
                 if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) {
                     printf("Invalid transaction hash format\n");
@@ -3072,7 +3076,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
             }
         }
         if (!found) {
-            printf("Specified certificate/pkey hash is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n");
+            printf("Specified address is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n");
             return -9;
         }
     }
@@ -3082,7 +3086,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str);
-    json_object *l_json_response = s_request_command_to_rpc(data);
+    json_object *l_json_response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
     if (!l_json_response) {
         printf("Error: Failed to retrieve transaction info from ledger\n");
         return -4;
@@ -3124,7 +3128,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
                 l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash);
                 snprintf(data, sizeof(data), 
                         "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str);
-                json_object *l_json_prev_tx = s_request_command_to_rpc(data);
+                json_object *l_json_prev_tx = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
                 if (!l_json_prev_tx) {
                     printf("Previous transaction %s is not found\n", l_tx_hash_str_tmp);
                     return -12;
@@ -3138,7 +3142,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
         char data[512];
         snprintf(data, sizeof(data), 
                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", l_net_str);
-        json_object *l_json_coins = s_request_command_to_rpc(data);
+        json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
         if (!l_json_coins) {
             printf("Error: Failed to retrieve coins from ledger\n");
             return -4;
@@ -3165,7 +3169,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
         l_sign_str = dap_chain_wallet_check_sign(l_wallet);
     }
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
-    l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key);
+    l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key, l_url_str, l_port);
     json_object * l_json_obj_ret = json_object_new_object();
     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
     printf("%s", json_object_to_json_string(l_json_obj_ret));
@@ -3175,9 +3179,19 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
     return 0;
 }
 
-dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key)
+dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port)
 {
-
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+            a_tx_hash, a_net_str);
+    
+    json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+    if (!response) {
+        printf("Error: Failed to get response from remote node\n"); 
+        return -15;
+    }
+    dap_chain_datum_tx_t *l_cond_tx = NULL;
 
     dap_chain_datum_tx_t *l_cond_tx = 
     dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
-- 
GitLab


From 5e77f4cdc6607f88e279f9a6b77c0df9d0628fef Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Mon, 31 Mar 2025 12:13:39 +0700
Subject: [PATCH 28/53] [+] need sign

---
 modules/net/dap_chain_node_cli_cmd_tx.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index d8d718c9e7..eac3b5e6ec 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -1104,6 +1104,8 @@ int com_ledger(int a_argc, char ** a_argv, void **reply)
         dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hash", &l_tx_hash_str);
         //get net
         dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
+        const char * l_need_sign;
+        dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-need_sign", &l_need_sign);
         //get search type
         bool l_unspent_flag = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-unspent", NULL);
         //check input
@@ -1140,6 +1142,21 @@ int com_ledger(int a_argc, char ** a_argv, void **reply)
             DAP_DEL_Z(l_tx_hash);
             return DAP_CHAIN_NODE_CLI_COM_LEDGER_TX_HASH_ERR;
         }
+        if (l_need_sign) {
+            byte_t *item; size_t l_size;
+            TX_ITEM_ITER_TX(item, l_size, l_datum_tx) {
+                if (*item == TX_ITEM_TYPE_SIG) {
+                    json_object *json_obj_item = json_object_new_object();
+                    dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t*)item);
+                    char *l_sign_b64 = DAP_NEW_Z_SIZE(char, DAP_ENC_BASE64_ENCODE_SIZE(dap_sign_get_size(l_sign)) + 1);
+                    size_t l_sign_size = dap_sign_get_size(l_sign);
+                    dap_enc_base64_encode(l_sign, l_sign_size, l_sign_b64, DAP_ENC_DATA_TYPE_B64_URLSAFE);
+                    json_object_object_add(json_obj_item, "sig_b64_size",   json_object_new_uint64(l_sign_size));
+                    json_object_object_add(json_obj_item, "sig_b64",    json_object_new_string(l_sign_b64));
+                    json_object_array_add(json_datum, json_obj_item);
+                }
+            }
+        }
         DAP_DEL_Z(l_tx_hash);
         if (json_datum){
             json_object_array_add(*a_json_arr_reply, json_datum);
-- 
GitLab


From e8a430db05a4df3d463757ace9a2404c2bbe6f0c Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Mon, 31 Mar 2025 16:38:54 +0700
Subject: [PATCH 29/53] [+] invalidate

---
 dap-sdk                                       |   2 +-
 modules/compose/dap_chain_tx_compose.c        | 202 +++++++++++++-----
 .../compose/include/dap_chain_tx_compose.h    |   2 +
 modules/net/dap_chain_node_cli_cmd_tx.c       |  24 ++-
 4 files changed, 161 insertions(+), 69 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index 695db02acc..e303f12da9 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 695db02acc05add13e8ba75c13812148aaeb6e63
+Subproject commit e303f12da9e8a8b632e296e8897319b952837a62
diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 114103eb1f..ef7a8fc4f3 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -35,6 +35,7 @@
 #include "dap_json_rpc.h"
 #include "dap_app_cli_net.h"
 #include "dap_cli_server.h"
+#include "dap_enc_base64.h"
 
 #include <netdb.h>
 #include <json-c/json.h>
@@ -289,12 +290,12 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a
                     printf("Error %d: %s\n", json_object_get_int(error_code), json_object_get_string(error_message));
                 }
             }
-            json_object_put(l_result);
             l_result = NULL;
         }
     }
     s_cmd_request_free(l_cmd_request);
-    json_object_get(l_result);
+    if (l_result)
+        json_object_get(l_result);
     json_object_put(l_response);
     return l_result;
 }
@@ -2152,6 +2153,10 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_na
     }
 
     json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, a_net_name, &l_addr, l_url_str, l_port);
+    if (!l_outs_delegated) {
+        return NULL;
+    }
+
     int l_out_native_count = json_object_array_length(l_outs_native);
     int l_out_delegated_count = json_object_array_length(l_outs_delegated);
 
@@ -2976,8 +2981,8 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
 */
 
 
-/**
-static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
+
+int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
 {
     const char *l_net_str = NULL,
                *l_wallet_str = NULL,
@@ -2994,13 +2999,28 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
         printf("Command 'invalidate' requires parameter -net\n");
         return -1;
     }
-    if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
         l_url_str = s_get_net_url(l_net_str);
     }
-    if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
+        l_port = s_get_net_port(l_net_str);
+    } else {
         l_port = atoi(l_port_str);
+    }
+
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        arg_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
     } else {
-        l_port = s_get_net_port(l_net_str);
+        arg_wallets_path = dap_strdup(l_wallet_path);
     }
 
     uint256_t l_fee = {};
@@ -3085,14 +3105,15 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
 
     char data[512];
     snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str);
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str);
     json_object *l_json_response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
     if (!l_json_response) {
         printf("Error: Failed to retrieve transaction info from ledger\n");
         return -4;
     }
 
-    json_object *l_json_items = json_object_object_get(l_json_response, "ITEMS");
+    json_object *l_json_items = json_object_array_get_idx(l_json_response, 0);
+    l_json_items = json_object_object_get(l_json_items, "ITEMS");
     bool has_delegate_out = false;
     if (l_json_items) {
         int items_count = json_object_array_length(l_json_items);
@@ -3111,6 +3132,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
 
     if (!has_delegate_out) {
         printf("Transaction %s does not have a delegate out\n", l_tx_hash_str_tmp);
+        json_object_put(l_json_response);
         return -11;
     }
 
@@ -3160,13 +3182,11 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
         }
     }
     dap_chain_datum_tx_t *l_tx = NULL;
-    const char* l_sign_str = "";
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config),NULL);
+
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path,NULL);
     if (!l_wallet) {
         printf("Specified wallet not found\n");
         return -14;
-    } else {
-        l_sign_str = dap_chain_wallet_check_sign(l_wallet);
     }
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
     l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key, l_url_str, l_port);
@@ -3180,52 +3200,102 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv)
 }
 
 dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port)
-{
+{ 
     char data[512];
     snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-            a_tx_hash, a_net_str);
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-need_sign;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+            dap_hash_fast_to_str_static(a_tx_hash), a_net_str);
     
     json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
     if (!response) {
         printf("Error: Failed to get response from remote node\n"); 
-        return -15;
+        return NULL;
     }
-    dap_chain_datum_tx_t *l_cond_tx = NULL;
-
-    dap_chain_datum_tx_t *l_cond_tx = 
-    dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
-    if (!l_cond_tx) {
-        printf("Requested conditional transaction not found\n");
+    json_object *l_items_array = json_object_array_get_idx(response, 0);
+    l_items_array = json_object_object_get(l_items_array, "ITEMS");
+    if (!l_items_array) {
+        printf("Error: ITEMS array not found in JSON response\n");
         return NULL;
     }
+
+    json_object *l_unspent_outs = json_object_object_get(response, "all OUTs yet unspent");
+    if (l_unspent_outs) {
+        const char *all_unspent = json_object_get_string(l_unspent_outs);
+        if (all_unspent && strcmp(all_unspent, "yes") == 0) {
+            printf("Error: All outputs are spent\n");
+            json_object_put(response);
+            return NULL;
+        }
+    }
+
+    dap_chain_tx_out_cond_t *l_tx_out_cond = NULL;
+    const char * l_tx_prev_hash = NULL;
     int l_prev_cond_idx = 0;
-    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx,
-                                                  DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_prev_cond_idx);
-    if (!l_tx_out_cond) {
-        printf("Requested conditional transaction requires conditional output\n");
-        return NULL;
+
+    size_t items_count = json_object_array_length(l_items_array);
+    for (size_t i = 0; i < items_count; i++) {
+        json_object *l_item = json_object_array_get_idx(l_items_array, i);
+        const char *item_type = json_object_get_string(json_object_object_get(l_item, "item type"));
+
+        if (item_type && strcmp(item_type, "OUT COND") == 0) {
+            l_tx_out_cond = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+            l_tx_out_cond->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE;
+            l_tx_out_cond->header.value = dap_uint256_scan_uninteger(json_object_get_string(json_object_object_get(l_item, "value")));
+        } else if (item_type && strcmp(item_type, "IN COND") == 0) {
+            l_tx_prev_hash = json_object_get_string(json_object_object_get(l_item, "Tx_prev_hash"));
+            if (!l_tx_prev_hash) {
+                printf("Error: Tx_prev_hash not found in ITEMS array\n");
+                return NULL;
+            }
+            l_prev_cond_idx = json_object_get_int(json_object_object_get(l_item, "Tx_out_prev_idx"));
+            snprintf(data, sizeof(data), 
+                    "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+                    l_tx_prev_hash, a_net_str);
+            
+            json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+            if (!response) {
+                printf("Error: Request conditional transaction failed\n"); 
+                return NULL;
+            }
+        }
     }
-    dap_hash_fast_t l_spender_hash = { };
-    if (dap_ledger_tx_hash_is_used_out_item(l_ledger, a_tx_hash, l_prev_cond_idx, &l_spender_hash)) {
-        char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
-        dap_chain_hash_fast_to_str(&l_spender_hash, l_hash_str, sizeof(l_hash_str));
-        printf("Requested conditional transaction is already used out by %s\n", l_hash_str);
+
+    if (!l_tx_out_cond || !l_tx_prev_hash) {
+        printf("Error: Required conditional transaction structures not found\n");
         return NULL;
     }
-    dap_chain_tx_in_cond_t *l_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(l_cond_tx, NULL, NULL, TX_ITEM_TYPE_IN_COND, NULL);
-    if (l_in_cond) {
-        l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, &l_in_cond->header.tx_prev_hash);
-        if (!l_cond_tx) {
-            printf("Requested conditional transaction is unchained\n");
-            return NULL;
+
+    json_object *l_sig_item = NULL;
+    for (size_t i = 0; i < items_count; i++) {
+        json_object *l_item = json_object_array_get_idx(l_items_array, i);
+        const char *item_type = json_object_get_string(json_object_object_get(l_item, "item type"));
+        if (item_type && strcmp(item_type, "SIG") == 0) {
+            l_sig_item = l_item;
+            break;
         }
     }
-    // Get sign item
-    dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(l_cond_tx, NULL, NULL,
-            TX_ITEM_TYPE_SIG, NULL);
-    // Get sign from sign item
-    // TODO Can't get sign from sign item required new command for remote node
+
+    if (!l_sig_item) {
+        printf("Error: SIG item not found in ITEMS array\n");
+        return NULL;
+    }
+
+    const char *l_sign_b64_str = json_object_get_string(json_object_object_get(l_sig_item, "sig_b64"));
+    if (!l_sign_b64_str) {
+        printf("Error: Can't get base64-encoded sign from SIG item\n");
+        return NULL;
+    }
+
+    int64_t l_sign_b64_strlen = json_object_get_string_len(json_object_object_get(l_sig_item, "sig_b64"));
+    int64_t l_sign_decoded_size = DAP_ENC_BASE64_DECODE_SIZE(l_sign_b64_strlen);
+    dap_chain_tx_sig_t *l_tx_sig = DAP_NEW_Z_SIZE(dap_chain_tx_sig_t, sizeof(dap_chain_tx_sig_t) + l_sign_decoded_size);
+    *l_tx_sig = (dap_chain_tx_sig_t) {
+        .header = {
+            .type = TX_ITEM_TYPE_SIG, .version = 1,
+            .sig_size = dap_enc_base64_decode(l_sign_b64_str, l_sign_b64_strlen, l_tx_sig->sig, DAP_ENC_DATA_TYPE_B64_URLSAFE)
+        }
+    };
+
     dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
     dap_chain_addr_t l_owner_addr;
     dap_chain_addr_fill_from_sign(&l_owner_addr, l_sign, s_get_net_id(a_net_str));
@@ -3235,21 +3305,41 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         printf("Trying to invalidate delegating tx with not a owner wallet\n");
         return NULL;
     }
+    
     const char *l_native_ticker = s_get_native_ticker(a_net_str);
-    const char *l_delegated_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, a_tx_hash);
+
+    json_object *l_json_tiker = json_object_array_get_idx(response, 0);
+    json_object *token_ticker_obj = json_object_object_get(l_json_tiker, "Token_ticker");
+    if (!token_ticker_obj) {
+        token_ticker_obj = json_object_object_get(l_json_tiker, "token ticker");
+        if (!token_ticker_obj) {
+            printf("Error: Token ticker not found in response\n");
+            json_object_put(response);
+            return NULL;
+        }
+    }
+    const char *l_delegated_ticker = json_object_get_string(token_ticker_obj);
+
+    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
+    if (!l_outs_native) {
+        return NULL;
+    }
+
+    int l_out_native_count = json_object_array_length(l_outs_native);
     uint256_t l_fee_transfer = {}; // how many coins to transfer
     // list of transaction with 'out' items to sell
     uint256_t l_net_fee, l_fee_total = a_fee;
-    dap_chain_addr_t l_net_fee_addr;
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(s_get_net_id(a_net_str), &l_net_fee, &l_net_fee_addr);
+    dap_chain_addr_t*l_net_fee_addr = NULL;
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_net_fee_addr, l_url_str, l_port);
     if (l_net_fee_used)
         SUM_256_256(l_fee_total, l_net_fee, &l_fee_total);
     dap_list_t *l_list_fee_out = NULL; 
-    if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101)
-        l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker,
-                                                                            &l_owner_addr, l_fee_total, &l_fee_transfer);
+    l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+                                                                l_fee_total, 
+                                                                &l_fee_transfer);
     if (!l_list_fee_out) {
-        printf("Nothing to pay for fee (not enough funds)\n");
+        printf("Not enough funds to pay fee");
+        json_object_put(l_outs_native);
         return NULL;
     }
 
@@ -3276,7 +3366,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     }
     // add fee items
     if (l_net_fee_used) {
-        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
             dap_chain_datum_tx_delete(l_tx);
             return NULL;
         }
@@ -3296,15 +3386,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             return NULL;
         }
     }
-    // add 'sign' items
-    if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) {
-        dap_chain_datum_tx_delete(l_tx);
-        printf("Can't add sign output\n");
-        return NULL;
-    }
     return l_tx;
 }
-*/
+
 /** 
 dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){
     dap_chain_net_srv_order_t* l_order = NULL;
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index d88f925cd2..74773d5440 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -62,6 +62,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv);
 int dap_cli_hold_compose(int a_argc, char **a_argv);
 int dap_cli_take_compose(int a_argc, char **a_argv);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
+int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv);
 
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
 
@@ -99,6 +100,7 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
                               const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port);
+dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port);
 
 #ifdef __cplusplus
 }
diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index eac3b5e6ec..b56cb4bcc6 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -46,6 +46,7 @@
 #include "dap_chain_mempool.h"
 #include "dap_math_convert.h"
 #include "dap_json_rpc_errors.h"
+#include "dap_enc_base64.h"
 
 #include "dap_chain_wallet_cache.h"
 
@@ -1100,13 +1101,9 @@ int com_ledger(int a_argc, char ** a_argv, void **reply)
         }
         return 0;
     } else if (l_cmd == CMD_TX_INFO){
-        //GET hash
         dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hash", &l_tx_hash_str);
-        //get net
         dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
-        const char * l_need_sign;
-        dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-need_sign", &l_need_sign);
-        //get search type
+        bool l_need_sign  = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-need_sign", NULL);
         bool l_unspent_flag = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-unspent", NULL);
         //check input
         if (l_tx_hash_str == NULL){
@@ -1146,14 +1143,23 @@ int com_ledger(int a_argc, char ** a_argv, void **reply)
             byte_t *item; size_t l_size;
             TX_ITEM_ITER_TX(item, l_size, l_datum_tx) {
                 if (*item == TX_ITEM_TYPE_SIG) {
-                    json_object *json_obj_item = json_object_new_object();
                     dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t*)item);
                     char *l_sign_b64 = DAP_NEW_Z_SIZE(char, DAP_ENC_BASE64_ENCODE_SIZE(dap_sign_get_size(l_sign)) + 1);
                     size_t l_sign_size = dap_sign_get_size(l_sign);
                     dap_enc_base64_encode(l_sign, l_sign_size, l_sign_b64, DAP_ENC_DATA_TYPE_B64_URLSAFE);
-                    json_object_object_add(json_obj_item, "sig_b64_size",   json_object_new_uint64(l_sign_size));
-                    json_object_object_add(json_obj_item, "sig_b64",    json_object_new_string(l_sign_b64));
-                    json_object_array_add(json_datum, json_obj_item);
+                    
+                    json_object *json_items = json_object_object_get(json_datum, "ITEMS");
+                    if (json_items && json_object_is_type(json_items, json_type_array)) {
+                        int array_len = json_object_array_length(json_items);
+                        for (int i = 0; i < array_len; i++) {
+                            json_object *item = json_object_array_get_idx(json_items, i);
+                            const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+                            if (item_type && strcmp(item_type, "SIG") == 0) {
+                                json_object_object_add(item, "sig_b64", json_object_new_string(l_sign_b64));
+                                json_object_object_add(item, "sig_b64_size", json_object_new_uint64(l_sign_size));
+                            }
+                        }
+                    }
                 }
             }
         }
-- 
GitLab


From bd03ccda6747fb7c8d3438e7ee75270f54c2ba90 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Mon, 31 Mar 2025 16:48:21 +0700
Subject: [PATCH 30/53] [*] fix

---
 modules/compose/dap_chain_tx_compose.c | 66 ++++++++++++++++++++++++--
 1 file changed, 62 insertions(+), 4 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index ef7a8fc4f3..f26d40dac2 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -2981,7 +2981,6 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
 */
 
 
-
 int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
 {
     const char *l_net_str = NULL,
@@ -3089,12 +3088,14 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
                 const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash"));
                 if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) {
                     printf("Invalid transaction hash format\n");
+                    json_object_put(l_json_coins);
                     return -8;
                 }
                 found = true;
                 break;
             }
         }
+        json_object_put(l_json_coins);
         if (!found) {
             printf("Specified address is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n");
             return -9;
@@ -3145,6 +3146,7 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
             if (spent_by_tx) {
                 if (dap_chain_hash_fast_from_str(spent_by_tx, &l_tx_hash)) {
                     printf("Invalid transaction hash format in response\n");
+                    json_object_put(l_json_response);
                     return -8;
                 }
                 l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash);
@@ -3153,8 +3155,10 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
                 json_object *l_json_prev_tx = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
                 if (!l_json_prev_tx) {
                     printf("Previous transaction %s is not found\n", l_tx_hash_str_tmp);
+                    json_object_put(l_json_response);
                     return -12;
                 }
+                json_object_put(l_json_prev_tx);
                 break; 
             }
         }
@@ -3167,25 +3171,30 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
         json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
         if (!l_json_coins) {
             printf("Error: Failed to retrieve coins from ledger\n");
+            json_object_put(l_json_response);
             return -4;
         }
 
         bool tx_exists = false;
         int tx_count = json_object_array_length(l_json_coins);
         for (int i = 0; i < tx_count; i++) {
-            json_object *tx_item = json_object_array_get_idx(l_json_items, i);
+            json_object *tx_item = json_object_array_get_idx(l_json_coins, i);
             const char *tx_hash = json_object_get_string(json_object_object_get(tx_item, "tx_hash"));
             if (tx_hash && strcmp(tx_hash, l_tx_hash_str_tmp) == 0) {
                 printf("Error: Transaction %s already exists in the ledger\n", l_tx_hash_str_tmp);
+                json_object_put(l_json_coins);
+                json_object_put(l_json_response);
                 return -13;
             }
         }
+        json_object_put(l_json_coins);
     }
     dap_chain_datum_tx_t *l_tx = NULL;
 
     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path,NULL);
     if (!l_wallet) {
         printf("Specified wallet not found\n");
+        json_object_put(l_json_response);
         return -14;
     }
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
@@ -3196,9 +3205,11 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
     json_object_put(l_json_obj_ret);
     dap_chain_wallet_close(l_wallet);
     dap_enc_key_delete(l_enc_key);
+    json_object_put(l_json_response);
     return 0;
 }
 
+
 dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port)
 { 
     char data[512];
@@ -3215,6 +3226,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     l_items_array = json_object_object_get(l_items_array, "ITEMS");
     if (!l_items_array) {
         printf("Error: ITEMS array not found in JSON response\n");
+        json_object_put(response);
         return NULL;
     }
 
@@ -3245,6 +3257,8 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             l_tx_prev_hash = json_object_get_string(json_object_object_get(l_item, "Tx_prev_hash"));
             if (!l_tx_prev_hash) {
                 printf("Error: Tx_prev_hash not found in ITEMS array\n");
+                json_object_put(response);
+                DAP_DELETE(l_tx_out_cond);
                 return NULL;
             }
             l_prev_cond_idx = json_object_get_int(json_object_object_get(l_item, "Tx_out_prev_idx"));
@@ -3252,16 +3266,21 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
                     "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
                     l_tx_prev_hash, a_net_str);
             
-            json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
-            if (!response) {
+            json_object *response_cond = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+            if (!response_cond) {
                 printf("Error: Request conditional transaction failed\n"); 
+                json_object_put(response);
+                DAP_DELETE(l_tx_out_cond);
                 return NULL;
             }
+            json_object_put(response_cond);
         }
     }
 
     if (!l_tx_out_cond || !l_tx_prev_hash) {
         printf("Error: Required conditional transaction structures not found\n");
+        json_object_put(response);
+        DAP_DELETE(l_tx_out_cond);
         return NULL;
     }
 
@@ -3277,12 +3296,16 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
 
     if (!l_sig_item) {
         printf("Error: SIG item not found in ITEMS array\n");
+        json_object_put(response);
+        DAP_DELETE(l_tx_out_cond);
         return NULL;
     }
 
     const char *l_sign_b64_str = json_object_get_string(json_object_object_get(l_sig_item, "sig_b64"));
     if (!l_sign_b64_str) {
         printf("Error: Can't get base64-encoded sign from SIG item\n");
+        json_object_put(response);
+        DAP_DELETE(l_tx_out_cond);
         return NULL;
     }
 
@@ -3303,6 +3326,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     dap_chain_addr_fill_from_key(&l_wallet_addr, a_key, s_get_net_id(a_net_str));
     if (!dap_chain_addr_compare(&l_owner_addr, &l_wallet_addr)) {
         printf("Trying to invalidate delegating tx with not a owner wallet\n");
+        json_object_put(response);
+        DAP_DELETE(l_tx_out_cond);
+        DAP_DELETE(l_tx_sig);
         return NULL;
     }
     
@@ -3315,6 +3341,8 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         if (!token_ticker_obj) {
             printf("Error: Token ticker not found in response\n");
             json_object_put(response);
+            DAP_DELETE(l_tx_out_cond);
+            DAP_DELETE(l_tx_sig);
             return NULL;
         }
     }
@@ -3322,6 +3350,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
 
     json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
     if (!l_outs_native) {
+        json_object_put(response);
+        DAP_DELETE(l_tx_out_cond);
+        DAP_DELETE(l_tx_sig);
         return NULL;
     }
 
@@ -3340,6 +3371,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (!l_list_fee_out) {
         printf("Not enough funds to pay fee");
         json_object_put(l_outs_native);
+        json_object_put(response);
+        DAP_DELETE(l_tx_out_cond);
+        DAP_DELETE(l_tx_sig);
         return NULL;
     }
 
@@ -3355,6 +3389,10 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
         printf("Can't compose the transaction input\n");
         dap_chain_datum_tx_delete(l_tx);
+        json_object_put(l_outs_native);
+        json_object_put(response);
+        DAP_DELETE(l_tx_out_cond);
+        DAP_DELETE(l_tx_sig);
         return NULL;
     }
 
@@ -3362,18 +3400,30 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_tx_out_cond->header.value, l_delegated_ticker) == -1) {
         dap_chain_datum_tx_delete(l_tx);
         printf("Cant add returning coins output\n");
+        json_object_put(l_outs_native);
+        json_object_put(response);
+        DAP_DELETE(l_tx_out_cond);
+        DAP_DELETE(l_tx_sig);
         return NULL;
     }
     // add fee items
     if (l_net_fee_used) {
         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
             dap_chain_datum_tx_delete(l_tx);
+            json_object_put(l_outs_native);
+            json_object_put(response);
+            DAP_DELETE(l_tx_out_cond);
+            DAP_DELETE(l_tx_sig);
             return NULL;
         }
     }
     if (!IS_ZERO_256(a_fee)) {
         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
             dap_chain_datum_tx_delete(l_tx);
+            json_object_put(l_outs_native);
+            json_object_put(response);
+            DAP_DELETE(l_tx_out_cond);
+            DAP_DELETE(l_tx_sig);
             return NULL;
         }
     }
@@ -3383,9 +3433,17 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if(!IS_ZERO_256(l_fee_back)) {
         if(dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) {
             dap_chain_datum_tx_delete(l_tx);
+            json_object_put(l_outs_native);
+            json_object_put(response);
+            DAP_DELETE(l_tx_out_cond);
+            DAP_DELETE(l_tx_sig);
             return NULL;
         }
     }
+    json_object_put(l_outs_native);
+    json_object_put(response);
+    DAP_DELETE(l_tx_out_cond);
+    DAP_DELETE(l_tx_sig);
     return l_tx;
 }
 
-- 
GitLab


From 6d06dafa226b82e4078eb2417aae3080bed01b51 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Tue, 1 Apr 2025 17:55:39 +0700
Subject: [PATCH 31/53] [+] srv_stake delegate

---
 modules/compose/dap_chain_tx_compose.c        | 203 ++++++++++--------
 .../compose/include/dap_chain_tx_compose.h    |   6 +
 2 files changed, 124 insertions(+), 85 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index f26d40dac2..e64e75107b 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -36,6 +36,8 @@
 #include "dap_app_cli_net.h"
 #include "dap_cli_server.h"
 #include "dap_enc_base64.h"
+#include "dap_chain_net_srv_order.h"
+#include "dap_chain_net_srv_stake_pos_delegate.h"
 
 #include <netdb.h>
 #include <json-c/json.h>
@@ -3447,8 +3449,19 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     return l_tx;
 }
 
-/** 
-dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){
+dap_chain_net_srv_order_direction_t dap_chain_net_srv_order_direction_from_str(const char* str) {
+    dap_chain_net_srv_order_direction_t direction = SERV_DIR_UNDEFINED;
+    if (strcmp(str, "BUY") == 0) {
+        direction = SERV_DIR_BUY;
+    } else if (strcmp(str, "SELL") == 0) {
+        direction = SERV_DIR_SELL;
+    }
+    return direction;
+}
+
+
+dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax,
+                                                    uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){
     dap_chain_net_srv_order_t* l_order = NULL;
     json_object *orders_array = json_object_array_get_idx(response, 0);
     size_t orders_count = json_object_array_length(orders_array);
@@ -3460,14 +3473,17 @@ dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, con
             l_order = DAP_NEW_Z_SIZE(dap_chain_net_srv_order_t, sizeof(dap_chain_net_srv_order_t));
             l_order->version = json_object_get_int(json_object_object_get(order_obj, "version"));
             l_order->direction = dap_chain_net_srv_order_direction_from_str(json_object_get_string(json_object_object_get(order_obj, "direction")));
-            l_order->ts_created = dap_time_from_str(json_object_get_string(json_object_object_get(order_obj, "created")));
+            l_order->ts_created = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(order_obj, "created")));
             l_order->srv_uid.uint64 = dap_chain_net_srv_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "srv_uid"))).uint64;
             l_order->price = dap_uint256_scan_uninteger(json_object_get_string(json_object_object_get(order_obj, "price datoshi")));
             strncpy(l_order->price_ticker, json_object_get_string(json_object_object_get(order_obj, "price token")), DAP_CHAIN_TICKER_SIZE_MAX);
             l_order->units = json_object_get_int(json_object_object_get(order_obj, "units"));
             l_order->price_unit = dap_chain_net_srv_price_unit_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "price unit")));
             dap_chain_node_addr_from_str(&l_order->node_addr, json_object_get_string(json_object_object_get(order_obj, "node_addr")));
-            dap_chain_hash_fast_from_str(&l_order->tx_cond_hash, json_object_get_string(json_object_object_get(order_obj, "tx_cond_hash")));
+            const char *tx_cond_hash_str = json_object_get_string(json_object_object_get(order_obj, "tx_cond_hash"));
+            if (tx_cond_hash_str) {
+                dap_chain_hash_fast_from_str(tx_cond_hash_str, &l_order->tx_cond_hash);
+            }
             l_order->ext_size = json_object_get_int(json_object_object_get(order_obj, "ext_size"));
             if (l_order->ext_size > 0) {
                 const char *tax_str = json_object_get_string(json_object_object_get(order_obj, "tax"));
@@ -3489,12 +3505,14 @@ dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, con
     return l_order;
 }
 
-dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax){
+dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax,
+                                                    uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax,
+                                                    const char* l_url_str, uint16_t l_port){
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", 
             l_net_str);
-    json_object *response = s_request_command_to_rpc(data);
+    json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return NULL;
@@ -3507,7 +3525,7 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const
         snprintf(data, sizeof(data), 
                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", 
                 l_net_str);
-        response = s_request_command_to_rpc(data);
+        response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
         if (!response) {
             printf("Error: Failed to get response from remote node\n");
             return NULL;
@@ -3521,7 +3539,7 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const
 
 
 
-static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
+int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
 {
     int l_arg_index = 0;
     const char *l_net_str = NULL,
@@ -3533,16 +3551,43 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                *l_value_str = NULL,
                *l_fee_str = NULL,
                *l_node_addr_str = NULL,
-               *l_order_hash_str = NULL;
+               *l_order_hash_str = NULL,
+               *l_url_str = NULL,
+               *l_port_str = NULL;
+    int l_port = 0;
     
     dap_pkey_t *l_pkey = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-net", &l_net_str);
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
     if (!l_net_str) {
         printf("Command 'delegate' requires parameter -net\n");
         return -1;
     }
 
-    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-w", &l_wallet_str);
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
+        l_url_str = s_get_net_url(l_net_str);
+    }
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
+        l_port = s_get_net_port(l_net_str);
+    } else {
+        l_port = atoi(l_port_str);
+    }
+
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        arg_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
+    } else {
+        arg_wallets_path = dap_strdup(l_wallet_path);
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
     if (!l_wallet_str) {
         printf("Command 'delegate' requires parameter -w\n");
         return -1;
@@ -3556,10 +3601,10 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
     dap_chain_wallet_close(l_wallet);
     dap_chain_addr_t l_signing_addr, l_sovereign_addr = {};
     uint256_t l_sovereign_tax = uint256_0;
-    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-cert", &l_cert_str);
-    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str);
-    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-sign_type", &l_sign_type_str);
-    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-order", &l_order_hash_str);
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str);
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str);
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-sign_type", &l_sign_type_str);
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str);
     if (!l_cert_str && !l_order_hash_str && !l_pkey_full_str) {
         printf("Command 'delegate' requires parameter -cert and/or -order and/or -pkey\n");
         dap_enc_key_delete(l_enc_key);
@@ -3576,7 +3621,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
         return -1;
     }
     uint256_t l_value = uint256_0;
-    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-value", &l_value_str);
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str);
     if (!l_value_str) {
         if (!l_order_hash_str) {
             printf("Command 'delegate' requires parameter -value\n");
@@ -3605,9 +3650,8 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
             return -4;
         }
         l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key);
-        dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
-    } 
-    else if (l_pkey_full_str) {
+        dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
+    }  else if (l_pkey_full_str) {
         dap_sign_type_t l_type = dap_sign_type_from_str(l_sign_type_str);
         if (l_type.type == SIG_TYPE_NULL) {
             printf("Wrong sign type\n");
@@ -3632,7 +3676,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
             return -6;
         }
         dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(l_net_str));
-        dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
+        dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
     }
 
     dap_chain_node_addr_t l_node_addr = g_node_addr;
@@ -3647,7 +3691,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
         uint256_t l_tax;
         uint256_t l_value_max;
         int l_prev_tx_count = 0;
-        dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax);
+        dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, l_url_str, l_port);
 
         if (l_order->direction == SERV_DIR_BUY) { // Staker order
             if (!l_cert_str) {
@@ -3666,9 +3710,9 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
             char data[512];
             snprintf(data, sizeof(data), 
                     "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-                    l_order->tx_cond_hash, l_net_str);
+                    dap_chain_hash_fast_to_str_static(&l_order->tx_cond_hash), l_net_str);
             
-            json_object *response = s_request_command_to_rpc(data);
+            json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
             if (!response) {
                 printf("Error: Failed to get response from remote node\n");
                 return -15;
@@ -3691,7 +3735,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                         l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
                         l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE;
                         l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
-                        l_cond_tx->header.ts_expires = dap_time_from_str(json_object_get_string(json_object_object_get(item, "ts_expires")));
+                        l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
                         l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr")));
                         if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) {
                             printf("Error: Failed to parse signer node address\n");
@@ -3717,30 +3761,6 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                 return -9;
             }
 
-
-
-            l_prev_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash);
-            if (!l_prev_tx) {
-                printf("The order's conditional transaction not found in ledger\n");
-                dap_enc_key_delete(l_enc_key);
-                DAP_DELETE(l_order);
-                return -10;
-            }
-            int l_out_num = 0;
-            dap_chain_tx_out_cond_t *l_cond_tx = dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
-            if (!l_cond) {
-                printf("The order's conditional transaction has invalid type\n");
-                dap_enc_key_delete(l_enc_key);
-                DAP_DELETE(l_order);
-                return -11;
-            }
-            if (dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_order->tx_cond_hash, l_out_num, NULL)) {
-                printf("The order's conditional transaction is already spent\n");
-                dap_enc_key_delete(l_enc_key);
-                DAP_DELETE(l_order);
-                return -12;
-            }
-
             char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
             dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(l_net_str));
             const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker"));
@@ -3773,10 +3793,6 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                 return -16;
             }
             l_value = l_order->price;
-            // dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR);
-            // l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE);
-            // l_sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t);
-            // MULT_256_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
         } else {
             if (!l_value_str) {
                 printf("Command 'delegate' requires parameter -value with this order type\n");
@@ -3784,7 +3800,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                 return -1;
             }
             const char *l_sovereign_addr_str = NULL;
-            dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str);
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str);
             if (l_sovereign_addr_str) {
                 dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str);
                 if (!l_spec_addr) {
@@ -3819,10 +3835,10 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                 DAP_DELETE(l_order);
                 return -20;
             }
-            dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_net->pub.id);
+            dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, s_get_net_id(l_net_str));
             l_pkey = dap_pkey_get_from_sign(l_sign);
             char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX];
-            dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_net->pub.native_ticker);
+            dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, s_get_native_ticker(l_net_str));
             if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) {
                 printf("Specified order is invalid\n");
                 dap_enc_key_delete(l_enc_key);
@@ -3854,7 +3870,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
     }
  
 
-    uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str);
+    uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str, l_url_str, l_port);
     if (compare256(l_value, l_allowed_min) == -1) {
         const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str);
         printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n",
@@ -3862,7 +3878,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
         dap_enc_key_delete(l_enc_key);
         return -23;
     }
-    dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-fee", &l_fee_str);
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
     if (!l_fee_str) {
         printf("Command 'delegate' requires parameter -fee\n");
         dap_enc_key_delete(l_enc_key);
@@ -3877,7 +3893,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
 
     // Create conditional transaction
     dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr,
-                                                   l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_prev_tx_count, l_pkey);
+                                                   l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, l_url_str, l_port);
     dap_enc_key_delete(l_enc_key);
     DAP_DELETE(l_pkey);
 
@@ -3888,14 +3904,14 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
 }
 
 // Freeze staker's funds when delegating a key
-dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc_key_t *a_key,
+static dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
-                                               dap_chain_datum_tx_t *a_prev_tx, int l_prev_tx_count, dap_pkey_t *a_pkey)
+                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port)
 {
-    dap_return_val_if_pass (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr, NULL);
-
+    if  (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr)
+        return NULL;
     const char *l_native_ticker = s_get_native_ticker(a_net_str);
     char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker);
@@ -3904,17 +3920,34 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc
     dap_chain_addr_t l_owner_addr;
     dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str));
     uint256_t l_net_fee, l_fee_total = a_fee;
-    dap_chain_addr_t l_net_fee_addr;
-    bool l_net_fee_used = get_remote_net_fee(a_net_str, l_native_ticker, &l_net_fee, &l_net_fee_addr);
+    dap_chain_addr_t * l_net_fee_addr = NULL;
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, l_net_fee_addr, l_url_str, l_port);
     if (l_net_fee_used)
         SUM_256_256(l_fee_total, l_net_fee, &l_fee_total);
 
     dap_list_t *l_list_fee_out = NULL;
-    if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101)
-        l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker,
-                                                                      &l_owner_addr, l_fee_total, &l_fee_transfer);
+
+
+    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
+    if (!l_outs_native) {
+        return NULL;
+    }
+
+    json_object *l_outs_delegated = dap_get_remote_tx_outs(l_delegated_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
+    if (!l_outs_delegated) {
+        return NULL;
+    }
+
+    int l_out_native_count = json_object_array_length(l_outs_native);
+    int l_out_delegated_count = json_object_array_length(l_outs_delegated);
+
+    l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+                                                    l_fee_total, 
+                                                    &l_fee_transfer);
     if (!l_list_fee_out) {
-        log_it(L_WARNING, "Nothing to pay for fee (not enough funds)");
+        printf("Not enough funds to pay fee");
+        json_object_put(l_outs_native);
+        json_object_put(l_outs_delegated);
         return NULL;
     }
 
@@ -3922,19 +3955,20 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc
     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
     if (!a_prev_tx) {
-        dap_list_t *l_list_used_out = NULL  ;
-        if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_delegated_ticker, &l_owner_addr, &l_list_used_out, a_value, &l_value_transfer) == -101)
-            l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_delegated_ticker,
-                                                                           &l_owner_addr, a_value, &l_value_transfer);
+        dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count,
+                                                               a_value, 
+                                                               &l_value_transfer);
         if (!l_list_used_out) {
-            log_it(L_WARNING, "Nothing to pay for delegate (not enough funds)");
-            goto tx_fail;
+            printf("Not enough funds to pay fee");
+            json_object_put(l_outs_native);
+            json_object_put(l_outs_delegated);
+            return NULL;
         }
         // add 'in' items to pay for delegate
         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
         dap_list_free_full(l_list_used_out, NULL);
         if (!EQUAL_256(l_value_to_items, l_value_transfer)) {
-            log_it(L_ERROR, "Can't compose the transaction input");
+            printf("Can't compose the transaction input\n");
             goto tx_fail;
         }
     } else {
@@ -3943,8 +3977,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc
         int l_out_num = 0;
         dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
         // add 'in' item to buy from conditional transaction
-        if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_prev_tx_count, -1)) {
-            log_it(L_ERROR, "Can't compose the transaction conditional input");
+        if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_out_num, -1)) {
+            printf("Can't compose the transaction conditional input\n");
             goto tx_fail;
         }
     }
@@ -3952,7 +3986,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc
     uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
     dap_list_free_full(l_list_fee_out, NULL);
     if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
-        log_it(L_ERROR, "Can't compose the fee transaction input");
+        printf("Can't compose the fee transaction input\n");
         goto tx_fail;
     }
 
@@ -3962,7 +3996,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc
                                                                                           a_sovereign_addr, a_sovereign_tax, a_pkey);
 
     if (!l_tx_out) {
-        log_it(L_ERROR, "Can't compose the transaction conditional output");
+        printf("Can't compose the transaction conditional output\n");
         goto tx_fail;
     }
     dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
@@ -3973,7 +4007,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc
         SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back);
         if (!IS_ZERO_256(l_value_back)) {
             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) {
-                log_it(L_ERROR, "Cant add coin back output");
+                printf("Cant add coin back output\n");
                 goto tx_fail;
             }
         }
@@ -3982,13 +4016,13 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc
     // add fee items
     if (l_net_fee_used) {
         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
-            log_it(L_ERROR, "Cant add net fee output");
+            printf("Cant add net fee output\n");
             goto tx_fail;
         }
     }
     if (!IS_ZERO_256(a_fee)) {
         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
-            log_it(L_ERROR, "Cant add validator fee output");
+            printf("Cant add validator fee output\n");
             goto tx_fail;
         }
     }
@@ -3997,14 +4031,14 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc
     SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back);
     if (!IS_ZERO_256(l_fee_back)) {
         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) {
-            log_it(L_ERROR, "Cant add fee back output");
+            printf("Cant add fee back output\n");
             goto tx_fail;
         }
     }
 
     // add 'sign' item
     if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) {
-        log_it(L_ERROR, "Can't add sign output");
+        printf("Can't add sign output\n");
         goto tx_fail;
     }
 
@@ -4014,7 +4048,6 @@ tx_fail:
     dap_chain_datum_tx_delete(l_tx);
     return NULL;
 }
-*/
 
 // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value>
 // int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) {
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 74773d5440..e8bf8ab3bd 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -63,6 +63,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv);
 int dap_cli_take_compose(int a_argc, char **a_argv);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv);
+int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv);
 
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
 
@@ -101,6 +102,11 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
                               const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port);
 dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port);
+static dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
+                                               uint256_t a_value, uint256_t a_fee,
+                                               dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
+                                               dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
+                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port);
 
 #ifdef __cplusplus
 }
-- 
GitLab


From 6fa0a995905fa63b60d2cf9df926204a37b2f287 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Wed, 2 Apr 2025 12:47:02 +0700
Subject: [PATCH 32/53] [*] dap_request_command_to_rpc

---
 modules/compose/dap_chain_tx_compose.c        | 99 +++++++++++++------
 .../compose/include/dap_chain_tx_compose.h    |  4 +-
 2 files changed, 70 insertions(+), 33 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index e64e75107b..bb14cf0ec5 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -42,7 +42,6 @@
 #include <netdb.h>
 #include <json-c/json.h>
 
-static json_object* s_request_command_to_rpc(const char *a_request, const char * a_net_name, const char * a_url_str, uint16_t a_port);
 
 
 const char *arg_wallets_path = NULL;
@@ -259,9 +258,14 @@ static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_ob
 
 static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) {
     json_object * l_response = NULL;
-    size_t l_response_size;
+    size_t l_response_size = 0; // Initialize to avoid potential undefined behavior
     struct cmd_request* l_cmd_request = s_cmd_request_init();
 
+    if (!l_cmd_request) {
+        printf("Error: Failed to initialize command request\n");
+        return NULL;
+    }
+
     dap_client_http_request(dap_worker_get_auto(),
                                 a_url_str ? a_url_str : s_get_net_url(a_net_name),
                                 a_port ? a_port : s_get_net_port(a_net_name),
@@ -276,17 +280,34 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a
         if (s_cmd_request_get_response(l_cmd_request, &l_response, &l_response_size)) {
             printf( "Response error code: %d", l_cmd_request->error_code);
         }
+    } else {
+        printf("Error: Command list wait failed with code %d\n", l_ret);
+    }
+
+    s_cmd_request_free(l_cmd_request);
+    return l_response;
+}
+
+static json_object* s_request_command_parse(json_object *l_response) {
+    if (!l_response) {
+        printf("Error: Response is NULL\n");
+        return NULL;
+    }
+
+    json_object * l_result = NULL;
+    if (!json_object_object_get_ex(l_response, "result", &l_result)) {
+        printf("Error: Failed to get 'result' from response\n");
+        return NULL;
     }
-    json_object * l_result;
-    json_object_object_get_ex(l_response, "result", &l_result);
-    json_object *errors_array;
+
+    json_object *errors_array = NULL;
     if (json_object_is_type(l_result, json_type_array) && json_object_array_length(l_result) > 0) {
         json_object *first_element = json_object_array_get_idx(l_result, 0);
         if (json_object_object_get_ex(first_element, "errors", &errors_array)) {
             int errors_len = json_object_array_length(errors_array);
             for (int j = 0; j < errors_len; j++) {
                 json_object *error_obj = json_object_array_get_idx(errors_array, j);
-                json_object *error_code, *error_message;
+                json_object *error_code = NULL, *error_message = NULL;
                 if (json_object_object_get_ex(error_obj, "code", &error_code) &&
                     json_object_object_get_ex(error_obj, "message", &error_message)) {
                     printf("Error %d: %s\n", json_object_get_int(error_code), json_object_get_string(error_message));
@@ -295,9 +316,18 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a
             l_result = NULL;
         }
     }
-    s_cmd_request_free(l_cmd_request);
-    if (l_result)
-        json_object_get(l_result);
+    json_object_get(l_result);
+    return l_result;
+}
+
+json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) {
+    json_object * l_response = s_request_command_to_rpc(request, a_net_name, a_url_str, a_port);
+    if (!l_response) {
+        printf("Error: Failed to get response from RPC request\n");
+        return NULL;
+    }
+
+    json_object * l_result = s_request_command_parse(l_response);
     json_object_put(l_response);
     return l_result;
 }
@@ -306,7 +336,7 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a
 bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, const char * a_url_str, uint16_t a_port) {
     char data[512];
     snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name);
-    json_object *l_json_get_fee = s_request_command_to_rpc(data, l_net_name, a_url_str, a_port);
+    json_object *l_json_get_fee = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port);
     if (!l_json_get_fee) {
         return false;
     }
@@ -357,7 +387,7 @@ bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const c
     snprintf(data, sizeof(data), 
             "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
             dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name);
-    json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name, a_url_str, a_port);
+    json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port);
     if (!l_json_outs) {
         return false;
     }
@@ -392,7 +422,7 @@ bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const c
 
     *l_outputs_count = json_object_array_length(*l_outs);
     json_object_get(*l_outs);
-    json_object_put(l_json_outs); // Clean up the JSON object
+    json_object_put(l_json_outs);
     return true;
 }
 
@@ -1047,7 +1077,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name);
-    json_object *l_json_coins = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
+    json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
     if (!l_json_coins) {
         return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS
     }
@@ -1061,7 +1091,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net
             "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
             dap_chain_addr_to_str(l_wallet_addr), a_net_name);
     DAP_DEL_Z(l_wallet_addr);
-    json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
+    json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
     uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell);
 
     uint256_t l_value_sell = a_datoshi_sell;
@@ -1097,7 +1127,7 @@ json_object *dap_get_remote_tx_outs(const char *a_token_ticker, const char *a_ne
     snprintf(data, sizeof(data), 
             "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
             dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name);
-    json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
+    json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
     if (!l_json_outs) {
         return NULL;
     }
@@ -1599,7 +1629,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name);
-    json_object *l_json_coins = s_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
+    json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
     if (!l_json_coins) {
         return -4;
     }
@@ -1733,7 +1763,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
         dap_chain_addr_to_str(l_addr_holder), l_net_name);
     DAP_DEL_Z(l_addr_holder);
 
-    json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
+    json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
     uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str);
     json_object_put(l_json_outs);
     if (compare256(l_value_balance, l_value) == -1) {
@@ -2003,7 +2033,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
             l_tx_str, l_net_str);
     
-    json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+    json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return -15;
@@ -2296,7 +2326,7 @@ uint256_t s_get_key_delegating_min_value(const char *a_net_str, const char *l_ur
             "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", 
             a_net_str);
     
-    json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+    json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return l_key_delegating_min_value;
@@ -2454,7 +2484,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str);
-    json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+    json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
     if (!l_json_coins) {
         printf("Error: Can't get ledger coins list\n");
         return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
@@ -2739,7 +2769,7 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"voting\",\"params\": [\"voting;dump;-hash;%s\"],\"id\": \"2\"}", l_hash_str);
-    json_object *l_json_voting = s_request_command_to_rpc(data);
+    json_object *l_json_voting = dap_request_command_to_rpc(data);
     if (!l_json_voting) {
         printf("Error: Can't get voting info\n");
         return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
@@ -2793,7 +2823,7 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
         char data[512];
         snprintf(data, sizeof(data), 
                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str);
-        json_object *l_json_coins = s_request_command_to_rpc(data);
+        json_object *l_json_coins = dap_request_command_to_rpc(data);
         if (!l_json_coins) {
             printf("Error: Failed to retrieve coins from ledger\n");
             return -4;
@@ -3075,7 +3105,7 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
         char data[512];
         snprintf(data, sizeof(data), 
                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", l_net_str);
-        json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+        json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
         if (!l_json_coins) {
             printf("Error: Failed to retrieve coins from ledger\n");
             return -4;
@@ -3109,7 +3139,7 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str);
-    json_object *l_json_response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+    json_object *l_json_response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
     if (!l_json_response) {
         printf("Error: Failed to retrieve transaction info from ledger\n");
         return -4;
@@ -3154,7 +3184,7 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
                 l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash);
                 snprintf(data, sizeof(data), 
                         "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str);
-                json_object *l_json_prev_tx = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+                json_object *l_json_prev_tx = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
                 if (!l_json_prev_tx) {
                     printf("Previous transaction %s is not found\n", l_tx_hash_str_tmp);
                     json_object_put(l_json_response);
@@ -3170,7 +3200,7 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
         char data[512];
         snprintf(data, sizeof(data), 
                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", l_net_str);
-        json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+        json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
         if (!l_json_coins) {
             printf("Error: Failed to retrieve coins from ledger\n");
             json_object_put(l_json_response);
@@ -3219,7 +3249,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-need_sign;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
             dap_hash_fast_to_str_static(a_tx_hash), a_net_str);
     
-    json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+    json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
     if (!response) {
         printf("Error: Failed to get response from remote node\n"); 
         return NULL;
@@ -3268,7 +3298,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
                     "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
                     l_tx_prev_hash, a_net_str);
             
-            json_object *response_cond = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+            json_object *response_cond = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
             if (!response_cond) {
                 printf("Error: Request conditional transaction failed\n"); 
                 json_object_put(response);
@@ -3512,7 +3542,7 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const
     snprintf(data, sizeof(data), 
             "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", 
             l_net_str);
-    json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+    json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return NULL;
@@ -3525,7 +3555,7 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const
         snprintf(data, sizeof(data), 
                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", 
                 l_net_str);
-        response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+        response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
         if (!response) {
             printf("Error: Failed to get response from remote node\n");
             return NULL;
@@ -3692,6 +3722,11 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
         uint256_t l_value_max;
         int l_prev_tx_count = 0;
         dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, l_url_str, l_port);
+        if (!l_order) {
+            printf("Error: Failed to get order from remote node\n");
+            dap_enc_key_delete(l_enc_key);
+            return -8;
+        }
 
         if (l_order->direction == SERV_DIR_BUY) { // Staker order
             if (!l_cert_str) {
@@ -3712,7 +3747,7 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                     "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
                     dap_chain_hash_fast_to_str_static(&l_order->tx_cond_hash), l_net_str);
             
-            json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+            json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
             if (!response) {
                 printf("Error: Failed to get response from remote node\n");
                 return -15;
@@ -3904,7 +3939,7 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
 }
 
 // Freeze staker's funds when delegating a key
-static dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
+dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index e8bf8ab3bd..04300c7145 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -65,6 +65,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv);
 
+json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port);
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
 
 dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer);
@@ -102,12 +103,13 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
                               const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port);
 dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port);
-static dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
+dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
                                                dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port);
 
+
 #ifdef __cplusplus
 }
 #endif
\ No newline at end of file
-- 
GitLab


From 956571a6661973583ba0fb34e3001a23fa1e8e58 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Wed, 2 Apr 2025 15:37:28 +0700
Subject: [PATCH 33/53] [+] order sign

---
 modules/compose/dap_chain_tx_compose.c        | 49 ++++++++++++++++---
 modules/net/srv/dap_chain_net_srv.c           |  7 +--
 modules/net/srv/dap_chain_net_srv_order.c     | 11 ++++-
 .../net/srv/include/dap_chain_net_srv_order.h |  2 +-
 .../dap_chain_net_srv_stake_pos_delegate.c    |  2 +-
 5 files changed, 58 insertions(+), 13 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index bb14cf0ec5..0e1d3964fb 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -3489,7 +3489,6 @@ dap_chain_net_srv_order_direction_t dap_chain_net_srv_order_direction_from_str(c
     return direction;
 }
 
-
 dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax,
                                                     uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){
     dap_chain_net_srv_order_t* l_order = NULL;
@@ -3515,15 +3514,19 @@ dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, con
                 dap_chain_hash_fast_from_str(tx_cond_hash_str, &l_order->tx_cond_hash);
             }
             l_order->ext_size = json_object_get_int(json_object_object_get(order_obj, "ext_size"));
+            
             if (l_order->ext_size > 0) {
-                const char *tax_str = json_object_get_string(json_object_object_get(order_obj, "tax"));
-                const char *value_max_str = json_object_get_string(json_object_object_get(order_obj, "maximum_value"));
-                *a_tax = dap_uint256_scan_decimal(tax_str);
-                *a_value_max = dap_uint256_scan_decimal(value_max_str);
+                json_object *external_params = json_object_object_get(order_obj, "external_params");
+                if (external_params) {
+                    const char *tax_str = json_object_get_string(json_object_object_get(external_params, "tax"));
+                    const char *value_max_str = json_object_get_string(json_object_object_get(external_params, "maximum_value"));
+                    *a_tax = dap_uint256_scan_decimal(tax_str);
+                    *a_value_max = dap_uint256_scan_decimal(value_max_str);
+                }
             }
 
             json_object *conditional_tx_params = json_object_object_get(order_obj, "conditional_tx_params");
-            if (conditional_tx_params) {
+            if (conditional_tx_params && json_object_is_type(conditional_tx_params, json_type_object)) {
                 const char *sovereign_tax_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_tax"));
                 const char *sovereign_addr_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_addr"));
                 *a_sovereign_tax = dap_uint256_scan_decimal(sovereign_tax_str);
@@ -3566,6 +3569,37 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const
     return l_order;
 }
 
+dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_order_hash_str, size_t* a_sign_size,
+                                                    const char* l_url_str, uint16_t l_port){
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"net_srv\",\"params\": [\"net_srv;-net;%s;order;dump;-hash;%s;-need_sign\"],\"id\": \"1\"}", 
+            l_net_str, l_order_hash_str);
+    json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+    if (!response) {
+        printf("Error: Failed to get response from remote node\n");
+        return NULL;
+    }
+    const char *l_sign_b64_str = json_object_get_string(json_object_object_get(response, "sig_b64"));
+    if (!l_sign_b64_str) {
+        printf("Error: Can't get base64-encoded sign from SIG item\n");
+        json_object_put(response);
+        return NULL;
+    }
+
+    int64_t l_sign_b64_strlen = json_object_get_string_len(l_sign_b64_str);
+    int64_t l_sign_decoded_size = DAP_ENC_BASE64_DECODE_SIZE(l_sign_b64_strlen);
+    dap_chain_tx_sig_t *l_tx_sig = DAP_NEW_Z_SIZE(dap_chain_tx_sig_t, sizeof(dap_chain_tx_sig_t) + l_sign_decoded_size);
+    *l_tx_sig = (dap_chain_tx_sig_t) {
+        .header = {
+            .type = TX_ITEM_TYPE_SIG, .version = 1,
+            .sig_size = dap_enc_base64_decode(l_sign_b64_str, l_sign_b64_strlen, l_tx_sig->sig, DAP_ENC_DATA_TYPE_B64_URLSAFE)
+        }
+    };
+    *a_sign_size = l_tx_sig->header.sig_size;
+    return dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
+}
+
 
 
 
@@ -3863,7 +3897,8 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                 dap_enc_key_delete(l_enc_key);
                 return -19;
             }
-            dap_sign_t *l_sign = (dap_sign_t *)(l_order->ext_n_sign + l_order->ext_size);
+            size_t l_sign_size = 0;
+            dap_sign_t *l_sign = dap_get_remote_srv_order_sign(l_net_str, l_order_hash_str, &l_sign_size, l_url_str, l_port);
             if (l_sign->header.type.type == SIG_TYPE_NULL) {
                 printf("Specified order is unsigned\n");
                 dap_enc_key_delete(l_enc_key);
diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c
index f0a757bc49..c2ae7b50ce 100644
--- a/modules/net/srv/dap_chain_net_srv.c
+++ b/modules/net/srv/dap_chain_net_srv.c
@@ -404,7 +404,7 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply)
                     for (dap_list_t *l_temp = l_orders; l_temp; l_temp = l_temp->next){
                         json_object* json_obj_order = json_object_new_object();
                         dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t*)l_temp->data;
-                        dap_chain_net_srv_order_dump_to_json(l_order, json_obj_order, l_hash_out_type, l_net->pub.native_ticker);
+                        dap_chain_net_srv_order_dump_to_json(l_order, json_obj_order, l_hash_out_type, l_net->pub.native_ticker, false);
                         json_object_array_add(json_arr_out, json_obj_order);
                     }
                     json_object_object_add(json_obj_net_srv, "orders", json_arr_out);
@@ -416,11 +416,12 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply)
                 }
             } else if(!dap_strcmp( l_order_str, "dump" )) {
                 // Select with specified service uid
+                bool l_need_sign = dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-need_sign", NULL);
                 if ( l_order_hash_str ){
                     dap_chain_net_srv_order_t * l_order = dap_chain_net_srv_order_find_by_hash_str( l_net, l_order_hash_hex_str );
                     json_obj_net_srv = json_object_new_object();                    
                     if (l_order) {
-                        dap_chain_net_srv_order_dump_to_json(l_order, json_obj_net_srv, l_hash_out_type, l_net->pub.native_ticker);
+                        dap_chain_net_srv_order_dump_to_json(l_order, json_obj_net_srv, l_hash_out_type, l_net->pub.native_ticker, l_need_sign);
                         l_ret = 0;
                     }else{                        
                         if(!dap_strcmp(l_hash_out_type,"hex"))
@@ -447,7 +448,7 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply)
                         for(dap_list_t *l_temp = l_orders;l_temp; l_temp = l_orders->next) {
                             json_object* json_obj_order = json_object_new_object();
                             dap_chain_net_srv_order_t *l_order =(dap_chain_net_srv_order_t *) l_temp->data;
-                            dap_chain_net_srv_order_dump_to_json(l_order, json_obj_order, l_hash_out_type, l_net->pub.native_ticker);
+                            dap_chain_net_srv_order_dump_to_json(l_order, json_obj_order, l_hash_out_type, l_net->pub.native_ticker, l_need_sign);
                             json_object_array_add(json_arr_out, json_obj_order);
                         }
                         json_object_object_add(json_obj_net_srv, "orders", json_arr_out);
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index d584f33e9a..8033ad28b2 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -28,6 +28,7 @@
 #include "dap_chain_net_srv_order.h"
 #include "dap_hash.h"
 #include "dap_enc_base58.h"
+#include "dap_enc_base64.h"
 #include "dap_global_db.h"
 #include "dap_chain_net_srv_countries.h"
 #include "dap_chain_net_srv_stake_pos_delegate.h"
@@ -561,7 +562,7 @@ void dap_chain_net_srv_order_dump_to_string(const dap_chain_net_srv_order_t *a_o
  * @param a_str_out
  */
 void dap_chain_net_srv_order_dump_to_json(const dap_chain_net_srv_order_t *a_order, json_object *a_json_obj_out,
-                                            const char *a_hash_out_type, const char *a_native_ticker)
+                                            const char *a_hash_out_type, const char *a_native_ticker, bool a_need_sign)
 {
     if (a_order && a_json_obj_out ){
         dap_chain_hash_fast_t l_hash;
@@ -632,6 +633,14 @@ void dap_chain_net_srv_order_dump_to_json(const dap_chain_net_srv_order_t *a_ord
         //     DAP_DELETE(l_ext_out);
         // }
         dap_sign_t *l_sign = (dap_sign_t*)((byte_t*)a_order->ext_n_sign + a_order->ext_size);
+        if (a_need_sign) {
+            char *l_sign_b64 = DAP_NEW_Z_SIZE(char, DAP_ENC_BASE64_ENCODE_SIZE(dap_sign_get_size(l_sign)) + 1);
+            size_t l_sign_size = dap_sign_get_size(l_sign);
+            dap_enc_base64_encode(l_sign, l_sign_size, l_sign_b64, DAP_ENC_DATA_TYPE_B64_URLSAFE);
+            json_object_object_add(a_json_obj_out, "sig_b64", json_object_new_string(l_sign_b64));
+            json_object_object_add(a_json_obj_out, "sig_b64_size", json_object_new_uint64(l_sign_size));
+        }
+        
         dap_hash_fast_t l_sign_pkey = {0};
         dap_sign_get_pkey_hash(l_sign, &l_sign_pkey);
         const char *l_sign_pkey_hash_str = dap_hash_fast_to_str_static(&l_sign_pkey);
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 e0271c10a8..93166f6d59 100644
--- a/modules/net/srv/include/dap_chain_net_srv_order.h
+++ b/modules/net/srv/include/dap_chain_net_srv_order.h
@@ -142,7 +142,7 @@ char *dap_chain_net_srv_order_save(dap_chain_net_t *a_net, dap_chain_net_srv_ord
 void dap_chain_net_srv_order_dump_to_string(const dap_chain_net_srv_order_t *a_order, dap_string_t *a_str_out,
                                             const char *a_hash_out_type, const char *a_native_ticker);
 void dap_chain_net_srv_order_dump_to_json(const dap_chain_net_srv_order_t *a_order, json_object *a_json_obj_out,
-                                            const char *a_hash_out_type, const char *a_native_ticker);
+                                            const char *a_hash_out_type, const char *a_native_ticker, bool a_need_sign);
 
 void dap_chain_net_srv_order_add_notify_callback(dap_chain_net_t *a_net, dap_store_obj_callback_notify_t a_callback, void *a_cb_arg);
 /**
diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
index 73fe463d10..8b0e976581 100644
--- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
+++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
@@ -1987,7 +1987,7 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, voi
                 }
                 // TODO add filters to list (token, address, etc.)
                 json_object* l_json_obj_order = json_object_new_object();
-                dap_chain_net_srv_order_dump_to_json(l_order, l_json_obj_order, a_hash_out_type, l_net->pub.native_ticker);
+                dap_chain_net_srv_order_dump_to_json(l_order, l_json_obj_order, a_hash_out_type, l_net->pub.native_ticker, false);
                 if (l_order->srv_uid.uint64 == DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ORDERS) {
                     if (l_order->direction == SERV_DIR_SELL) {
                         json_object_object_add(l_json_obj_order, "message", 
-- 
GitLab


From adf4b8ce6ccd4d3a75ecfb9413d89ea90e2b8de8 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Wed, 2 Apr 2025 16:43:08 +0700
Subject: [PATCH 34/53] [*] fix delegate

---
 modules/compose/dap_chain_tx_compose.c | 57 +++++++++++++++++---------
 1 file changed, 37 insertions(+), 20 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 0e1d3964fb..48f0bb940d 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -3569,7 +3569,7 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const
     return l_order;
 }
 
-dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_order_hash_str, size_t* a_sign_size,
+dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_order_hash_str,
                                                     const char* l_url_str, uint16_t l_port){
     char data[512];
     snprintf(data, sizeof(data), 
@@ -3580,14 +3580,22 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o
         printf("Error: Failed to get response from remote node\n");
         return NULL;
     }
-    const char *l_sign_b64_str = json_object_get_string(json_object_object_get(response, "sig_b64"));
+    json_object *l_response_array = json_object_array_get_idx(response, 0);
+    if (!l_response_array) {
+        printf("Error: Can't get the first element from the response array\n");
+        json_object_put(response);
+        return NULL;
+    }
+
+    const char *l_sign_b64_str = json_object_get_string(json_object_object_get(l_response_array, "sig_b64"));
     if (!l_sign_b64_str) {
         printf("Error: Can't get base64-encoded sign from SIG item\n");
         json_object_put(response);
         return NULL;
     }
 
-    int64_t l_sign_b64_strlen = json_object_get_string_len(l_sign_b64_str);
+    // *a_sign_size = json_object_get_int(json_object_object_get(l_response_array, "sig_b64_size"));
+    int64_t l_sign_b64_strlen = json_object_get_string_len(json_object_object_get(l_response_array, "sig_b64"));
     int64_t l_sign_decoded_size = DAP_ENC_BASE64_DECODE_SIZE(l_sign_b64_strlen);
     dap_chain_tx_sig_t *l_tx_sig = DAP_NEW_Z_SIZE(dap_chain_tx_sig_t, sizeof(dap_chain_tx_sig_t) + l_sign_decoded_size);
     *l_tx_sig = (dap_chain_tx_sig_t) {
@@ -3596,8 +3604,11 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o
             .sig_size = dap_enc_base64_decode(l_sign_b64_str, l_sign_b64_strlen, l_tx_sig->sig, DAP_ENC_DATA_TYPE_B64_URLSAFE)
         }
     };
-    *a_sign_size = l_tx_sig->header.sig_size;
-    return dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
+
+    dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
+    DAP_DELETE(l_tx_sig);
+    json_object_put(response);
+    return l_sign;
 }
 
 
@@ -3761,6 +3772,7 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
             dap_enc_key_delete(l_enc_key);
             return -8;
         }
+        l_sovereign_tax = l_tax;
 
         if (l_order->direction == SERV_DIR_BUY) { // Staker order
             if (!l_cert_str) {
@@ -3898,8 +3910,8 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                 return -19;
             }
             size_t l_sign_size = 0;
-            dap_sign_t *l_sign = dap_get_remote_srv_order_sign(l_net_str, l_order_hash_str, &l_sign_size, l_url_str, l_port);
-            if (l_sign->header.type.type == SIG_TYPE_NULL) {
+            dap_sign_t *l_sign = dap_get_remote_srv_order_sign(l_net_str, l_order_hash_str, l_url_str, l_port);
+            if (!l_sign) {
                 printf("Specified order is unsigned\n");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
@@ -3932,12 +3944,13 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
         return -6;
     }
 
-    int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr);
-    if (l_check_result) {
-        printf("Key and node verification error\n");
-        dap_enc_key_delete(l_enc_key);
-        return l_check_result;
-    }
+    // TODO: need to make sure that the key and node are required verification 
+    // int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr);
+    // if (l_check_result) {
+    //     printf("Key and node verification error\n");
+    //     dap_enc_key_delete(l_enc_key);
+    //     return l_check_result;
+    // }
  
 
     uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str, l_url_str, l_port);
@@ -3967,6 +3980,10 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
     dap_enc_key_delete(l_enc_key);
     DAP_DELETE(l_pkey);
 
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
     DAP_DELETE(l_tx);
 
     return 0;
@@ -3991,7 +4008,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str));
     uint256_t l_net_fee, l_fee_total = a_fee;
     dap_chain_addr_t * l_net_fee_addr = NULL;
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, l_net_fee_addr, l_url_str, l_port);
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_net_fee_addr, l_url_str, l_port);
     if (l_net_fee_used)
         SUM_256_256(l_fee_total, l_net_fee, &l_fee_total);
 
@@ -4085,7 +4102,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
 
     // add fee items
     if (l_net_fee_used) {
-        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
             printf("Cant add net fee output\n");
             goto tx_fail;
         }
@@ -4106,11 +4123,11 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
         }
     }
 
-    // add 'sign' item
-    if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) {
-        printf("Can't add sign output\n");
-        goto tx_fail;
-    }
+    // // add 'sign' item
+    // if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) {
+    //     printf("Can't add sign output\n");
+    //     goto tx_fail;
+    // }
 
     return l_tx;
 
-- 
GitLab


From 8c29d6c9ef71563d0226fd4018618846ec037e54 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Wed, 2 Apr 2025 17:09:45 +0700
Subject: [PATCH 35/53] [+] order create staker

---
 modules/compose/dap_chain_tx_compose.c        | 161 ++++++++++++++++++
 .../compose/include/dap_chain_tx_compose.h    |   1 +
 2 files changed, 162 insertions(+)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 48f0bb940d..2479a6d1c3 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -4136,6 +4136,167 @@ tx_fail:
     return NULL;
 }
 
+static dap_chain_datum_tx_t *dap_order_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
+                                               uint256_t a_value, uint256_t a_fee,
+                                                uint256_t a_sovereign_tax, dap_chain_addr_t *a_sovereign_addr,
+                                                const char *l_url_str, int l_port)
+{
+    dap_chain_node_addr_t l_node_addr = {};
+    return dap_stake_tx_create_compose(a_net_str, a_key, a_value, a_fee,
+                             (dap_chain_addr_t *)&c_dap_chain_addr_blank, &l_node_addr,
+                             a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port);
+}
+
+//srv_stake order create staker -net <net_name> -w <wallet_with_m_tokens> -value <stake_value> -fee <value> -tax <percent> [-addr <for_tax_collecting>]  [-cert <for_order_signing>] [-H {hex(default) | base58}]
+int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
+    int l_arg_index = 1;
+    const char *l_value_str = NULL,
+               *l_wallet_str = NULL,
+               *l_tax_str = NULL,
+               *l_addr_str = NULL,
+               *l_fee_str = NULL,
+               *l_url_str = NULL,
+               *l_port_str = NULL,
+               *l_net_str = NULL;
+    int l_port = 0;
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
+    if (!l_net_str) {
+        printf("Command 'order' requires parameter -net");
+        return -1;
+    }
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
+        l_url_str = s_get_net_url(l_net_str);
+    }
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
+        l_port = s_get_net_port(l_net_str);
+    } else {
+        l_port = atoi(l_port_str);
+    }
+
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        arg_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
+    } else {
+        arg_wallets_path = dap_strdup(l_wallet_path);
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str);
+    if (!l_value_str) {
+        printf("Staker order creation requires parameter -value\n");
+        return -1;
+    }
+    uint256_t l_value = dap_chain_balance_scan(l_value_str);
+    if (IS_ZERO_256(l_value)) { 
+        printf("Format -value <256 bit integer>\n");
+        return -2;
+    }
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
+    if (!l_fee_str) {
+        printf("Staker order creation requires parameter -fee\n");
+        return -3;
+    }
+    uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+    if (IS_ZERO_256(l_fee)) {
+        printf("Format -fee <256 bit integer>\n");
+        return -4;
+    }
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax", &l_tax_str);
+    if (!l_tax_str) {
+        printf("Staker order creation requires parameter -tax\n");
+        return -5;
+    }
+    uint256_t l_tax = dap_chain_coins_to_balance(l_tax_str);
+    if (compare256(l_tax, dap_chain_coins_to_balance("100.0")) == 1 ||
+            compare256(l_tax, GET_256_FROM_64(100)) == -1) {
+        printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n");
+        return -6;
+    }
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
+    if (!l_wallet_str) {
+        printf("Staker order creation requires parameter -w\n");
+        return -7;
+    }
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
+    if (!l_wallet) {
+        printf("Specified wallet not found\n");
+        return -8;
+    }
+    // Create conditional transaction for order
+    const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet);
+    dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
+    dap_chain_wallet_close(l_wallet);
+    dap_chain_addr_t l_addr = {};
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_addr_str);
+    if (l_addr_str) {
+        dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str);
+        if (!l_spec_addr) {
+            printf("Specified address is ivalid\n");
+            DAP_DELETE(l_enc_key);
+            return -9;
+        }
+        l_addr = *l_spec_addr;
+        DAP_DELETE(l_spec_addr);
+    } else
+        dap_chain_addr_fill_from_key(&l_addr, l_enc_key, s_get_net_id(l_net_str));
+    DIV_256(l_tax, GET_256_FROM_64(100), &l_tax);
+    dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, &l_addr, l_url_str, l_port);
+    DAP_DEL_Z(l_enc_key);
+    // char *l_tx_hash_str = NULL;
+    // if (!l_tx || !(l_tx_hash_str = s_stake_tx_put(l_tx, l_net, a_hash_out_type))) {
+    //     printf("Can't compose transaction for order, examine log files for details\n");
+    //     DAP_DEL_Z(l_tx);
+    //     return -10;
+    // }
+
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
+    DAP_DELETE(l_tx);
+    // Create the order & put it in GDB
+
+    // dap_hash_fast_t l_tx_hash = {};
+    // dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash);
+    // char *l_cert_str = NULL;
+    // dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", (const char **)&l_cert_str);
+    // if (!l_cert_str)
+    //     l_cert_str = "node-addr";
+    // dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str);
+    // if (!l_cert) {
+    //     printf("Can't load cert %s\n", l_cert_str);
+    //     DAP_DELETE(l_tx_hash_str);
+    //     return -11;
+    // }
+    // if (!l_cert->enc_key || !l_cert->enc_key->priv_key_data || !l_cert->enc_key->priv_key_data_size) {
+    //     printf("Certificate \"%s\" has no private key\n", l_cert_str);
+    //     return -12;
+    // }
+    // char *l_order_hash_str = s_staker_order_create(l_net, l_value, &l_tx_hash, l_cert->enc_key, a_hash_out_type);
+    // if (!l_order_hash_str) {
+    //     printf("Can't compose the order\n");
+    //     DAP_DELETE(l_tx_hash_str);
+    //     return -13;
+    // }
+    // json_object * l_json_obj_create_val = json_object_new_object();
+    // json_object_object_add(l_json_obj_create_val, "status", json_object_new_string("success"));
+    // if (dap_strcmp(l_sign_str, ""))
+    //     json_object_object_add(l_json_obj_create_val, "sign", json_object_new_string(l_sign_str));
+    // json_object_object_add(l_json_obj_create_val, "order_hash", json_object_new_string(l_order_hash_str));
+    // json_object_object_add(l_json_obj_create_val, "tx_hash", json_object_new_string(l_tx_hash_str));
+    // json_object_array_add(*a_json_arr_reply, l_json_obj_create_val);
+    // DAP_DELETE(l_order_hash_str);
+    // DAP_DELETE(l_tx_hash_str);
+}
+
 // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value>
 // int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) {
 //     int arg_index = 1;
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 04300c7145..b01ad80d24 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -64,6 +64,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv);
+int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv);
 
 json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port);
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
-- 
GitLab


From a8ae075e4cc49bdd9d24da79d9e63055039f7020 Mon Sep 17 00:00:00 2001
From: konstantin <konstantin.kuharenko@demlabs.net>
Date: Thu, 3 Apr 2025 08:18:01 +0300
Subject: [PATCH 36/53] [*] fix enc method for wallet

---
 dap-sdk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dap-sdk b/dap-sdk
index e303f12da9..f4d4efa7f6 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit e303f12da9e8a8b632e296e8897319b952837a62
+Subproject commit f4d4efa7f6b4628eedf947b908438cc3db2b02e8
-- 
GitLab


From 0ed0cbecca75fe206faad14553c2eb5649041ab5 Mon Sep 17 00:00:00 2001
From: konstantin <konstantin.kuharenko@demlabs.net>
Date: Thu, 3 Apr 2025 13:59:28 +0300
Subject: [PATCH 37/53] [*] add extern C

---
 dap-sdk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dap-sdk b/dap-sdk
index f4d4efa7f6..b3dfc55196 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit f4d4efa7f6b4628eedf947b908438cc3db2b02e8
+Subproject commit b3dfc55196d4ce1815c2805a7211f3eb3d08940e
-- 
GitLab


From ea1819a12fe7168f345f39352e936b13dc1c9c52 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Mon, 7 Apr 2025 16:42:13 +0700
Subject: [PATCH 38/53] [+] xchange remove

---
 modules/compose/dap_chain_tx_compose.c        | 571 ++++++++++++++++--
 .../compose/include/dap_chain_tx_compose.h    |   4 +
 2 files changed, 515 insertions(+), 60 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 2479a6d1c3..4b742936b7 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -1470,8 +1470,8 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net
         size_t a_cond_size, const char *a_url_str, uint16_t a_port)
 {
     // check valid param
-    if (!a_net_name || !a_key_from || !a_key_cond ||
-            !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value))
+    if (!a_net_name || !*a_net_name || !a_key_from || !a_key_cond ||
+            !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value) || !a_url_str || !*a_url_str || a_port == 0)
         return NULL;
 
     if (dap_strcmp(s_get_native_ticker(a_net_name), a_token_ticker)) {
@@ -1669,8 +1669,6 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
         return -9;
     }
 
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_str);
-
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str);
     if (!l_chain_id_str) {
         printf("Error: Missing or invalid chain_id argument\n");
@@ -3243,7 +3241,9 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
 
 
 dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port)
-{ 
+{
+    if(!a_net_str || !*a_net_str || !a_tx_hash || !a_key || !l_url_str || !*l_url_str || l_port == 0)
+        return NULL;
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-need_sign;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
@@ -4159,9 +4159,9 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
                *l_port_str = NULL,
                *l_net_str = NULL;
     int l_port = 0;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
-    if (!l_net_str) {
-        printf("Command 'order' requires parameter -net");
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str) || !l_net_str) {
+        printf("Command 'order' requires parameter -net\n");
         return -1;
     }
 
@@ -4189,8 +4189,7 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
         arg_wallets_path = dap_strdup(l_wallet_path);
     }
 
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str);
-    if (!l_value_str) {
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str) || !l_value_str) {
         printf("Staker order creation requires parameter -value\n");
         return -1;
     }
@@ -4199,8 +4198,8 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
         printf("Format -value <256 bit integer>\n");
         return -2;
     }
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
-    if (!l_fee_str) {
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str) || !l_fee_str) {
         printf("Staker order creation requires parameter -fee\n");
         return -3;
     }
@@ -4209,8 +4208,8 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
         printf("Format -fee <256 bit integer>\n");
         return -4;
     }
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax", &l_tax_str);
-    if (!l_tax_str) {
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax", &l_tax_str) || !l_tax_str) {
         printf("Staker order creation requires parameter -tax\n");
         return -5;
     }
@@ -4220,8 +4219,8 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
         printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n");
         return -6;
     }
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
-    if (!l_wallet_str) {
+
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) {
         printf("Staker order creation requires parameter -w\n");
         return -7;
     }
@@ -4230,18 +4229,23 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
         printf("Specified wallet not found\n");
         return -8;
     }
-    // Create conditional transaction for order
+
     const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet);
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
     dap_chain_wallet_close(l_wallet);
+
+    if (!l_enc_key) {
+        printf("Failed to retrieve encryption key\n");
+        return -9;
+    }
+
     dap_chain_addr_t l_addr = {};
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_addr_str);
-    if (l_addr_str) {
+    if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_addr_str) && l_addr_str) {
         dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str);
         if (!l_spec_addr) {
-            printf("Specified address is ivalid\n");
+            printf("Specified address is invalid\n");
             DAP_DELETE(l_enc_key);
-            return -9;
+            return -10;
         }
         l_addr = *l_spec_addr;
         DAP_DELETE(l_spec_addr);
@@ -4250,53 +4254,500 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
     DIV_256(l_tax, GET_256_FROM_64(100), &l_tax);
     dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, &l_addr, l_url_str, l_port);
     DAP_DEL_Z(l_enc_key);
-    // char *l_tx_hash_str = NULL;
-    // if (!l_tx || !(l_tx_hash_str = s_stake_tx_put(l_tx, l_net, a_hash_out_type))) {
-    //     printf("Can't compose transaction for order, examine log files for details\n");
-    //     DAP_DEL_Z(l_tx);
-    //     return -10;
-    // }
 
-    json_object * l_json_obj_ret = json_object_new_object();
+    if (!l_tx) {
+        printf("Failed to create transaction\n");
+        return -11;
+    }
+
+    json_object *l_json_obj_ret = json_object_new_object();
+    if (!l_json_obj_ret) {
+        printf("Failed to create JSON object\n");
+        DAP_DELETE(l_tx);
+        return -12;
+    }
+
     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
     printf("%s", json_object_to_json_string(l_json_obj_ret));
     json_object_put(l_json_obj_ret);
     DAP_DELETE(l_tx);
-    // Create the order & put it in GDB
-
-    // dap_hash_fast_t l_tx_hash = {};
-    // dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash);
-    // char *l_cert_str = NULL;
-    // dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", (const char **)&l_cert_str);
-    // if (!l_cert_str)
-    //     l_cert_str = "node-addr";
-    // dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str);
-    // if (!l_cert) {
-    //     printf("Can't load cert %s\n", l_cert_str);
-    //     DAP_DELETE(l_tx_hash_str);
-    //     return -11;
-    // }
-    // if (!l_cert->enc_key || !l_cert->enc_key->priv_key_data || !l_cert->enc_key->priv_key_data_size) {
-    //     printf("Certificate \"%s\" has no private key\n", l_cert_str);
-    //     return -12;
-    // }
-    // char *l_order_hash_str = s_staker_order_create(l_net, l_value, &l_tx_hash, l_cert->enc_key, a_hash_out_type);
-    // if (!l_order_hash_str) {
-    //     printf("Can't compose the order\n");
-    //     DAP_DELETE(l_tx_hash_str);
-    //     return -13;
+    return 0;
+}
+
+int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) {
+    int l_arg_index = 1;
+    const char * l_order_hash_str = NULL;
+    const char * l_fee_str = NULL;
+    const char * l_net_str = NULL;
+    const char * l_wallet_str = NULL;
+    const char * l_url_str = NULL;
+    const char * l_port_str = NULL;
+    int l_port = 0;
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
+    if (!l_net_str) {
+        printf("Command 'order remove' requires parameter -net\n");
+        return -1;
+    }
+
+        if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
+        l_url_str = s_get_net_url(l_net_str);
+    }
+    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
+        l_port = s_get_net_port(l_net_str);
+    } else {
+        l_port = atoi(l_port_str);
+    }
+
+    const char *l_wallet_path = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
+    if (!l_wallet_path) {
+        arg_wallets_path =
+        #ifdef DAP_OS_WINDOWS
+                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+        #elif defined DAP_OS_MAC
+                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+        #elif defined DAP_OS_UNIX
+                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+        #endif
+    } else {
+        arg_wallets_path = dap_strdup(l_wallet_path);
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
+    if (!l_wallet_str) {
+        printf("Command 'order remove' requires parameter -w\n");
+        return -3;
+    }
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
+    if (!l_wallet) {
+        printf("Specified wallet not found\n");
+        return -4;
+    }
+    const char* l_sign_str = dap_chain_wallet_check_sign(l_wallet);
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str);
+    if (!l_order_hash_str) {
+        printf("Command 'order remove' requires parameter -order\n");
+        return -5;
+    }
+    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
+    if (!l_fee_str) {
+        printf("Command 'order remove' requires parameter -fee\n");
+        return -6;
+    }
+    uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+    dap_hash_fast_t l_tx_hash = {};
+    dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash);
+    char *l_tx_hash_ret = NULL;
+    dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_remove_compose(l_net_str, &l_tx_hash, l_fee, l_wallet, l_url_str, l_port);
+    dap_chain_wallet_close(l_wallet);
+    
+    return 0;
+}
+
+bool process_ledger_response(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, 
+                                                dap_chain_hash_fast_t *a_tx_hash, const char *a_url_str, int a_port, dap_chain_hash_fast_t *a_out_hash) {
+    *a_out_hash = *a_tx_hash;
+    int l_prev_tx_count = 0;
+    dap_chain_hash_fast_t l_hash = {};
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+            dap_chain_hash_fast_to_str_static(a_tx_hash), a_net_str);
+    
+    json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
+    if (!response) {
+        printf("Error: Failed to get response from remote node\n");
+        return false;
+    }
+    
+    json_object *l_response_array = json_object_array_get_idx(response, 0);
+    if (!l_response_array) {
+        printf("Error: Can't get the first element from the response array\n");
+        json_object_put(response);
+        return false;
+    }
+
+    json_object *items = json_object_object_get(l_response_array, "ITEMS");
+    if (!items) {
+        printf("Error: No items found in response\n");
+        return false;
+    }
+    bool l_found = false;
+    int items_count = json_object_array_length(items);
+    for (int i = 0; i < items_count; i++) {
+        json_object *item = json_object_array_get_idx(items, i);
+        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+        if (dap_strcmp(item_type, "OUT COND") == 0) {
+            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+            if (!dap_strcmp(subtype, dap_chain_tx_out_cond_subtype_to_str(a_cond_type))) {
+                dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(item, "hash")), &l_hash);
+                l_prev_tx_count++;
+                l_found = true;
+                break;
+            }
+        } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) {
+            l_prev_tx_count++;
+        }
+    }
+    if (!l_found) {
+        return false;
+    }
+    bool l_another_tx = false;
+    json_object *spent_outs = json_object_object_get(l_response_array, "Spent OUTs");
+    if (spent_outs) {
+        int spent_outs_count = json_object_array_length(spent_outs);
+        for (int i = 0; i < spent_outs_count; i++) {
+            json_object *spent_out = json_object_array_get_idx(spent_outs, i);
+            int out_index = json_object_get_int(json_object_object_get(spent_out, "OUT - "));
+            if (out_index == l_prev_tx_count) {
+                dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(spent_out, "is spent by tx")), &l_hash);
+                l_another_tx = true;
+                break;
+            }
+        }
+    }
+    if (l_another_tx) {
+        *a_out_hash = l_hash;
+        return true;
+    }
+    return false;
+}
+
+dap_chain_hash_fast_t dap_ledger_get_final_chain_tx_hash_compose(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash, bool a_unspent_only, const char *a_url_str, int a_port)
+{
+    dap_chain_hash_fast_t l_hash = { };
+    if(!a_net_str || !a_tx_hash || dap_hash_fast_is_blank(a_tx_hash))
+        return l_hash;
+    l_hash = *a_tx_hash;
+
+    while(process_ledger_response(a_net_str, a_cond_type, a_tx_hash, a_url_str, a_port, &l_hash));
+
+    return l_hash;
+}
+
+dap_chain_net_srv_xchange_price_t *dap_chain_net_srv_xchange_price_from_order_compose(const char *a_net_str, dap_chain_tx_out_cond_t *a_cond_tx, 
+                                                                                    dap_time_t a_ts_created, const char *a_token_ticker, dap_hash_fast_t *a_order_hash, 
+                                                                                    uint256_t *a_fee, bool a_ret_is_invalid, const char *a_url_str, int a_port)
+{
+    if (!a_net_str || !*a_net_str || !a_cond_tx || !a_token_ticker || !a_order_hash || !a_url_str || !*a_url_str || a_port == 0)
+        return NULL;
+    dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
+    if (!l_price)
+        return NULL;
+    l_price->creation_date = a_ts_created;
+    dap_strncpy(l_price->token_buy, a_cond_tx->subtype.srv_xchange.buy_token, sizeof(l_price->token_buy) - 1);
+
+    l_price->order_hash = *a_order_hash;
+    strncpy(l_price->token_sell, a_token_ticker, sizeof(l_price->token_sell) - 1);
+
+    if (a_fee)
+        l_price->fee = *a_fee;
+
+    l_price->datoshi_sell = a_cond_tx->header.value;
+    l_price->creator_addr = a_cond_tx->subtype.srv_xchange.seller_addr;
+    l_price->rate = a_cond_tx->subtype.srv_xchange.rate;
+    dap_chain_hash_fast_t l_final_hash = dap_ledger_get_final_chain_tx_hash_compose(a_net_str,
+                                        DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->order_hash, false, a_url_str, a_port);
+    if ( !dap_hash_fast_is_blank(&l_final_hash) ) {
+        l_price->tx_hash = l_final_hash;
+        return l_price;
+    } else {
+        printf( "This order have no active conditional transaction");
+        if (a_ret_is_invalid) {
+            dap_hash_fast_t l_tx_hash_zero = {0};
+            l_price->tx_hash = l_tx_hash_zero;
+            return l_price;
+        }
+    }
+
+    return NULL;
+}
+
+
+dap_chain_datum_tx_t* dap_xchange_tx_invalidate_compose(const char *a_net_str, dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port)
+{
+    char * l_ret = NULL;
+
+    if (!a_price) {
+        printf("An a_price NULL argument was passed to the s_xchange_tx_invalidate() function.");
+        return NULL;
+    }
+    if (!a_wallet) {
+        printf("An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function.");
+        return NULL;
+    }
+    const char *l_native_ticker = s_get_native_ticker(a_net_str);
+
+    dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str));
+    dap_chain_addr_t l_seller_addr = *l_wallet_addr;
+    DAP_DELETE(l_wallet_addr);
+
+
+    dap_chain_tx_out_cond_t *l_cond_tx = NULL;
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+        dap_chain_hash_fast_to_str_static(&a_price->tx_hash), a_net_str);
+    
+    json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+    if (!response) {
+        printf("Error: Failed to get response from remote node\n");
+        return NULL;
+    }
+    
+    json_object *l_response_array = json_object_array_get_idx(response, 0);
+    if (!l_response_array) {
+        printf("Error: Can't get the first element from the response array\n");
+        json_object_put(response);
+        return NULL;
+    }
+
+    json_object *items = json_object_object_get(l_response_array, "ITEMS");
+    if (!items) {
+        printf("Error: No items found in response\n");
+        return NULL;
+    }
+    int l_prev_cond_idx = 0;
+    int items_count = json_object_array_length(items);
+    for (int i = 0; i < items_count; i++) {
+        json_object *item = json_object_array_get_idx(items, i);
+        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+        if (dap_strcmp(item_type, "OUT COND") == 0) {
+            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+            if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
+                l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+                l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+                l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+                l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
+                l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+                l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
+                strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
+                l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
+                l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
+                l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
+                break;
+            } else if (dap_strcmp(subtype, "OUT") == 0 || dap_strcmp(subtype, "OUT COND") == 0 || dap_strcmp(subtype, "OUT OLD") == 0) {
+                l_prev_cond_idx++;
+            }
+        }
+    }
+    if (!l_cond_tx) {
+        printf("Error: No transaction output condition found\n");
+        return NULL;
+    }
+
+    const char *l_tx_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
+    if (!l_tx_ticker) {
+        printf("Error: Token_ticker not found in response\n");
+        return NULL;
+    }
+
+    bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker);
+
+    json_object *spent_outs = json_object_object_get(l_response_array, "all OUTs yet unspent");
+    const char *spent_outs_value = json_object_get_string(spent_outs);
+    if (spent_outs_value && !dap_strcmp(spent_outs_value, "yes")) {
+        printf("Error: Transaction output item already used\n");
+        return NULL;
+    }
+
+    if (!dap_chain_addr_compare(&l_seller_addr, &l_cond_tx->subtype.srv_xchange.seller_addr)) {
+        printf("Only owner can invalidate exchange transaction");
+        return NULL;
+    }
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    // add 'in' item to buy from conditional transaction
+    dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0);
+    uint256_t l_net_fee = {};
+    dap_chain_addr_t* l_addr_fee = NULL;
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port);
+    uint256_t l_total_fee = a_price->fee;
+    if (l_net_fee_used)
+        SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
+
+    if (!l_single_channel) {
+        json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_seller_addr, l_url_str, l_port);
+        if (!l_outs_native) {
+            return NULL;
+        }
+        int l_out_native_count = json_object_array_length(l_outs_native);
+        uint256_t l_transfer_fee = {}, l_fee_back = {};
+        // list of transaction with 'out' items to get net fee
+        dap_list_t *l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+                                                               l_total_fee, 
+                                                               &l_transfer_fee);
+        if (!l_list_fee_out) {
+            printf("Not enough funds to pay fee");
+            json_object_put(l_outs_native);
+            return NULL;
+        }
+
+
+        // add 'in' items to net fee
+        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+        dap_list_free_full(l_list_fee_out, NULL);
+        if (!EQUAL_256(l_value_to_items, l_transfer_fee)) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Can't compose the transaction input");
+            return NULL;
+        }
+        // return coins to owner
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_cond_tx->header.value, l_tx_ticker) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Cant add returning coins output");
+            return NULL;
+        }
+        // Network fee
+        if (l_net_fee_used &&
+                dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Cant add network fee output");
+            return NULL;
+        }
+        // put fee coinback
+        SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back);
+        if (!IS_ZERO_256(l_fee_back) &&
+                dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Cant add fee cachback output");
+            return NULL;
+        }
+    } else {
+        uint256_t l_coin_back = {};
+        if (compare256(l_total_fee, l_cond_tx->header.value) >= 0) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Total fee is greater or equal than order liquidity");
+            return NULL;
+        }
+        SUBTRACT_256_256(l_cond_tx->header.value, l_total_fee, &l_coin_back);
+        // return coins to owner
+        if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Cant add returning coins output");
+            return NULL;
+        }
+        // Network fee
+        if (l_net_fee_used &&
+                dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Cant add network fee output");
+            return NULL;
+        }
+    }
+    // Validator's fee
+    if (!IS_ZERO_256(a_price->fee)) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            printf("Cant add validator's fee output");
+            return NULL;
+        }
+    }
+    // // add 'sign' items
+    // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
+    // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
+    //     dap_chain_datum_tx_delete(l_tx);
+    //     dap_enc_key_delete(l_seller_key);
+    //     log_it( L_ERROR, "Can't add sign output");
+    //     return false;
     // }
-    // json_object * l_json_obj_create_val = json_object_new_object();
-    // json_object_object_add(l_json_obj_create_val, "status", json_object_new_string("success"));
-    // if (dap_strcmp(l_sign_str, ""))
-    //     json_object_object_add(l_json_obj_create_val, "sign", json_object_new_string(l_sign_str));
-    // json_object_object_add(l_json_obj_create_val, "order_hash", json_object_new_string(l_order_hash_str));
-    // json_object_object_add(l_json_obj_create_val, "tx_hash", json_object_new_string(l_tx_hash_str));
-    // json_object_array_add(*a_json_arr_reply, l_json_obj_create_val);
-    // DAP_DELETE(l_order_hash_str);
-    // DAP_DELETE(l_tx_hash_str);
+    // dap_enc_key_delete(l_seller_key);
+    // l_ret = s_xchange_tx_put(l_tx, a_price->net);
+
+    return l_tx;
 }
 
+
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
+                                     dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) {
+    if (!a_net_str || !a_hash_tx || !a_wallet) {
+        return NULL;
+    }
+    if(IS_ZERO_256(a_fee)){
+        return NULL;
+    }
+
+    dap_time_t ts_created = 0;
+
+    dap_chain_tx_out_cond_t *l_cond_tx = NULL;
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+        dap_chain_hash_fast_to_str_static(a_hash_tx), a_net_str);
+    
+    json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+    if (!response) {
+        printf("Error: Failed to get response from remote node\n");
+        return NULL;
+    }
+    
+    const char *items_str = json_object_get_string(response);
+    json_object *l_response_array = json_object_array_get_idx(response, 0);
+    if (!l_response_array) {
+        printf("Error: Can't get the first element from the response array\n");
+        json_object_put(response);
+        return NULL;
+    }
+    json_object *items = json_object_object_get(l_response_array, "ITEMS");
+    if (!items) {
+        printf("Error: No items found in response\n");
+        return NULL;
+    }
+    int items_count = json_object_array_length(items);
+    for (int i = 0; i < items_count; i++) {
+        json_object *item = json_object_array_get_idx(items, i);
+        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+        if (dap_strcmp(item_type, "OUT COND") == 0) {
+            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+            if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
+                l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+                l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+                l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+                l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
+                l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+                l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
+                strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
+                l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
+                l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
+                l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
+                break;
+            }
+        }
+    }
+    if (!l_cond_tx) {
+        printf("Error: No transaction output condition found\n");
+        return NULL;
+    }
+
+    const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
+    if (!token_ticker) {
+        printf("Error: Token_ticker not found in response\n");
+        return NULL;
+    }
+    const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created"));
+    if (ts_created_str) {
+        ts_created = dap_time_from_str_rfc822(ts_created_str);
+    } else {
+        printf("Error: TS_Created not found in response\n");
+        return NULL;
+    }
+
+    dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(a_net_str, l_cond_tx, ts_created, token_ticker, a_hash_tx, &a_fee, false, l_url_str, l_port);
+    if (!l_price) {
+        return NULL;
+    }
+    dap_chain_datum_tx_t *l_tx = dap_xchange_tx_invalidate_compose(a_net_str, l_price, a_wallet, l_url_str, l_port);
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
+
+    DAP_DELETE(l_price);
+    return l_tx;
+}
+
+
 // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value>
 // int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) {
 //     int arg_index = 1;
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index b01ad80d24..78c4cee86e 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -65,6 +65,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv);
+int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv);
 
 json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port);
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
@@ -110,6 +111,9 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
                                                dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port);
 
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
+                                     dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port);
+
 
 #ifdef __cplusplus
 }
-- 
GitLab


From b8f266943f69e9dad2a3c32ed774274f12517254 Mon Sep 17 00:00:00 2001
From: "Constantin P." <papizh.konstantin@demlabs.net>
Date: Mon, 7 Apr 2025 16:56:03 +0700
Subject: [PATCH 39/53] Subs up

---
 dap-sdk                                | 2 +-
 modules/compose/dap_chain_tx_compose.c | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index b3dfc55196..e46c5449c2 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit b3dfc55196d4ce1815c2805a7211f3eb3d08940e
+Subproject commit e46c5449c2c2021f51db1b194654b44b177d0449
diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 2479a6d1c3..e8c3bfb586 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -39,7 +39,6 @@
 #include "dap_chain_net_srv_order.h"
 #include "dap_chain_net_srv_stake_pos_delegate.h"
 
-#include <netdb.h>
 #include <json-c/json.h>
 
 
-- 
GitLab


From 02dac63aa351fc227d68d9db58acd8cfbc901282 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Wed, 9 Apr 2025 14:40:56 +0700
Subject: [PATCH 40/53] [*] invalidate refactor

---
 dap-sdk                                       |   2 +-
 modules/compose/dap_chain_tx_compose.c        | 220 ++++++++++++------
 .../compose/include/dap_chain_tx_compose.h    |  39 +++-
 3 files changed, 193 insertions(+), 68 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index e46c5449c2..6cfac2c1c6 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit e46c5449c2c2021f51db1b194654b44b177d0449
+Subproject commit 6cfac2c1c65127d8f9cf9cf4c65afb054af8ce1f
diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 97f76ecd59..99751e1b64 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -257,7 +257,7 @@ static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_ob
 
 static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) {
     json_object * l_response = NULL;
-    size_t l_response_size = 0; // Initialize to avoid potential undefined behavior
+    size_t l_response_size = 0;
     struct cmd_request* l_cmd_request = s_cmd_request_init();
 
     if (!l_cmd_request) {
@@ -3010,7 +3010,7 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
 */
 
 
-int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
+int dap_compose_srv_stake_invalidate(int a_argc, char **a_argv)
 {
     const char *l_net_str = NULL,
                *l_wallet_str = NULL,
@@ -3076,36 +3076,129 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
             return -1;
         }
     }
+    json_object *l_json_obj_ret = json_object_new_object();
+    int ret = dap_cli_srv_stake_invalidate_compose(l_json_obj_ret, l_net_str, l_tx_hash_str, l_wallet_str, l_wallet_path, l_cert_str, l_fee, l_url_str, l_port);
+    switch (ret) {
+        case DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND:
+            printf("Error: Specified certificate not found\n");
+            break;
+        case DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING:
+            printf("Error: It is not possible to invalidate a stake using a public key.\n");
+            break;
+        case DAP_CLI_STAKE_INVALIDATE_WRONG_CERT:
+            printf("Error: Specified certificate is wrong\n");
+            break;
+        case DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR:
+            printf("Error: Failed to retrieve coins from ledger\n");
+            break;
+        case DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH:
+            printf("Error: Invalid transaction hash format\n");
+            break;
+        case DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED:
+            printf("Error: Specified address is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n");
+            break;
+        case DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT:
+            printf("Error: Transaction does not have a delegate out\n");
+            break;
+        case DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND:
+            printf("Error: Previous transaction is not found\n");
+            break;
+        case DAP_CLI_STAKE_INVALIDATE_TX_EXISTS:
+            printf("Error: Transaction already exists in the ledger\n");
+            break;
+        case DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND:
+            printf("Error: Specified wallet not found\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR:
+            printf("Error: Failed to get response from remote node\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND:
+            printf("Error: ITEMS array not found in JSON response\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT:
+            printf("Error: All outputs are spent\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND:
+            printf("Error: Tx_prev_hash not found in ITEMS array\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR:
+            printf("Error: Request conditional transaction failed\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND:
+            printf("Error: Required conditional transaction structures not found\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND:
+            printf("Error: SIG item not found in ITEMS array\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR:
+            printf("Error: Can't get base64-encoded sign from SIG item\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER:
+            printf("Trying to invalidate delegating tx with not a owner wallet\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND:
+            printf("Error: Token ticker not found in response\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND:
+            printf("Error: Failed to get transaction outputs\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS:
+            printf("Error: Not enough funds to pay fee\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR:
+            printf("Error: Can't compose the transaction input\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR:
+            printf("Error:Cant add returning coins output\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR:
+            printf("Error: Can't add network fee output\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR:
+            printf("Error: Can't add fee output\n");
+            break;
+        case DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR:
+            printf("Error: Can't add fee back output\n");
+            break;
+        case DAP_CLI_STAKE_INVALIDATE_OK:
+            printf("%s", json_object_to_json_string(l_json_obj_ret));
+            break;
+        default:
+            printf("Error: Unknown error code: %d\n", ret);
+    }
+    
+    json_object_put(l_json_obj_ret);
+    return ret;
+}
 
+int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
+                        const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port)
+{
     dap_hash_fast_t l_tx_hash = {};
-    if (l_tx_hash_str) {
-        dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash);
+    if (a_tx_hash_str) {
+        dap_chain_hash_fast_from_str(a_tx_hash_str, &l_tx_hash);
     } else {
         dap_chain_addr_t l_signing_addr;
-        if (l_cert_str) {
-            dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str);
+        if (a_cert_str) {
+            dap_cert_t *l_cert = dap_cert_find_by_name(a_cert_str);
             if (!l_cert) {
-                printf("Specified certificate not found\n");
-                return -4;
+                return DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND;
             }
             if (!l_cert->enc_key->priv_key_data || l_cert->enc_key->priv_key_data_size == 0) {
-                printf("It is not possible to invalidate a stake using a public key.\n");
-                return -5;
+                return DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING;
             }
-            if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, s_get_net_id(l_net_str))) {
-                printf("Specified certificate is wrong\n");
-                return -6;
+            if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, s_get_net_id(a_net_str))) {
+                return DAP_CLI_STAKE_INVALIDATE_WRONG_CERT;
             }
         }
         const char *l_addr_str = dap_chain_addr_to_str_static(&l_signing_addr);
 
         char data[512];
         snprintf(data, sizeof(data), 
-                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", l_net_str);
-        json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str);
+        json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
         if (!l_json_coins) {
-            printf("Error: Failed to retrieve coins from ledger\n");
-            return -4;
+            return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR;
         }
         
         int items_count = json_object_array_length(l_json_coins);
@@ -3116,9 +3209,8 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
             if (node_addr_str && !dap_strcmp(l_addr_str, node_addr_str)) {
                 const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash"));
                 if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) {
-                    printf("Invalid transaction hash format\n");
                     json_object_put(l_json_coins);
-                    return -8;
+                    return DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH;
                 }
                 found = true;
                 break;
@@ -3126,20 +3218,18 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
         }
         json_object_put(l_json_coins);
         if (!found) {
-            printf("Specified address is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n");
-            return -9;
+            return DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED;
         }
     }
 
-    const char *l_tx_hash_str_tmp = l_tx_hash_str ? l_tx_hash_str : dap_hash_fast_to_str_static(&l_tx_hash);
+    const char *l_tx_hash_str_tmp = a_tx_hash_str ? a_tx_hash_str : dap_hash_fast_to_str_static(&l_tx_hash);
 
     char data[512];
     snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str);
-    json_object *l_json_response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, a_net_str);
+        json_object *l_json_response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
     if (!l_json_response) {
-        printf("Error: Failed to retrieve transaction info from ledger\n");
-        return -4;
+        return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR;
     }
 
     json_object *l_json_items = json_object_array_get_idx(l_json_response, 0);
@@ -3161,9 +3251,8 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
     }
 
     if (!has_delegate_out) {
-        printf("Transaction %s does not have a delegate out\n", l_tx_hash_str_tmp);
         json_object_put(l_json_response);
-        return -11;
+        return DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT;
     }
 
     json_object *l_json_spents = json_object_object_get(l_json_response, "Spent OUTs");
@@ -3174,18 +3263,16 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
             const char *spent_by_tx = json_object_get_string(json_object_object_get(spent_item, "is spent by tx"));
             if (spent_by_tx) {
                 if (dap_chain_hash_fast_from_str(spent_by_tx, &l_tx_hash)) {
-                    printf("Invalid transaction hash format in response\n");
                     json_object_put(l_json_response);
-                    return -8;
+                    return DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH;
                 }
                 l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash);
                 snprintf(data, sizeof(data), 
-                        "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str);
-                json_object *l_json_prev_tx = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+                        "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, a_net_str);
+                json_object *l_json_prev_tx = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
                 if (!l_json_prev_tx) {
-                    printf("Previous transaction %s is not found\n", l_tx_hash_str_tmp);
                     json_object_put(l_json_response);
-                    return -12;
+                    return DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND;
                 }
                 json_object_put(l_json_prev_tx);
                 break; 
@@ -3193,15 +3280,14 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
         }
     }
 
-    if (l_tx_hash_str) {
+    if (a_tx_hash_str) {
         char data[512];
         snprintf(data, sizeof(data), 
-                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", l_net_str);
-        json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", a_net_str);
+        json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
         if (!l_json_coins) {
-            printf("Error: Failed to retrieve coins from ledger\n");
             json_object_put(l_json_response);
-            return -4;
+            return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR;
         }
 
         bool tx_exists = false;
@@ -3210,36 +3296,36 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv)
             json_object *tx_item = json_object_array_get_idx(l_json_coins, i);
             const char *tx_hash = json_object_get_string(json_object_object_get(tx_item, "tx_hash"));
             if (tx_hash && strcmp(tx_hash, l_tx_hash_str_tmp) == 0) {
-                printf("Error: Transaction %s already exists in the ledger\n", l_tx_hash_str_tmp);
                 json_object_put(l_json_coins);
                 json_object_put(l_json_response);
-                return -13;
+                return DAP_CLI_STAKE_INVALIDATE_TX_EXISTS;
             }
         }
         json_object_put(l_json_coins);
     }
     dap_chain_datum_tx_t *l_tx = NULL;
 
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path,NULL);
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path,NULL);
     if (!l_wallet) {
-        printf("Specified wallet not found\n");
         json_object_put(l_json_response);
-        return -14;
+        return DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND;
     }
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
-    l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key, l_url_str, l_port);
-    json_object * l_json_obj_ret = json_object_new_object();
-    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-    printf("%s", json_object_to_json_string(l_json_obj_ret));
-    json_object_put(l_json_obj_ret);
+    int l_ret = 0;
+    l_tx = dap_stake_tx_invalidate_compose(a_net_str, &l_tx_hash, a_fee, l_enc_key, a_url_str, a_port, &l_ret);
+    if (!l_tx) {
+        json_object_put(l_json_response);
+        return l_ret;
+    }
+    dap_chain_net_tx_to_json(l_tx, a_json_obj_ret);
+
     dap_chain_wallet_close(l_wallet);
     dap_enc_key_delete(l_enc_key);
     json_object_put(l_json_response);
-    return 0;
+    return DAP_CLI_STAKE_INVALIDATE_OK;
 }
 
-
-dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port)
+dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, int *l_ret)
 {
     if(!a_net_str || !*a_net_str || !a_tx_hash || !a_key || !l_url_str || !*l_url_str || l_port == 0)
         return NULL;
@@ -3250,14 +3336,14 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     
     json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
     if (!response) {
-        printf("Error: Failed to get response from remote node\n"); 
+        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR;
         return NULL;
     }
     json_object *l_items_array = json_object_array_get_idx(response, 0);
     l_items_array = json_object_object_get(l_items_array, "ITEMS");
     if (!l_items_array) {
-        printf("Error: ITEMS array not found in JSON response\n");
         json_object_put(response);
+        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND;
         return NULL;
     }
 
@@ -3265,8 +3351,8 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (l_unspent_outs) {
         const char *all_unspent = json_object_get_string(l_unspent_outs);
         if (all_unspent && strcmp(all_unspent, "yes") == 0) {
-            printf("Error: All outputs are spent\n");
             json_object_put(response);
+            if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT;
             return NULL;
         }
     }
@@ -3287,9 +3373,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         } else if (item_type && strcmp(item_type, "IN COND") == 0) {
             l_tx_prev_hash = json_object_get_string(json_object_object_get(l_item, "Tx_prev_hash"));
             if (!l_tx_prev_hash) {
-                printf("Error: Tx_prev_hash not found in ITEMS array\n");
                 json_object_put(response);
                 DAP_DELETE(l_tx_out_cond);
+                if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND;
                 return NULL;
             }
             l_prev_cond_idx = json_object_get_int(json_object_object_get(l_item, "Tx_out_prev_idx"));
@@ -3299,9 +3385,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             
             json_object *response_cond = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
             if (!response_cond) {
-                printf("Error: Request conditional transaction failed\n"); 
                 json_object_put(response);
                 DAP_DELETE(l_tx_out_cond);
+                if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR;
                 return NULL;
             }
             json_object_put(response_cond);
@@ -3309,9 +3395,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     }
 
     if (!l_tx_out_cond || !l_tx_prev_hash) {
-        printf("Error: Required conditional transaction structures not found\n");
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
+        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND;
         return NULL;
     }
 
@@ -3326,17 +3412,17 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     }
 
     if (!l_sig_item) {
-        printf("Error: SIG item not found in ITEMS array\n");
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
+        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND;
         return NULL;
     }
 
     const char *l_sign_b64_str = json_object_get_string(json_object_object_get(l_sig_item, "sig_b64"));
     if (!l_sign_b64_str) {
-        printf("Error: Can't get base64-encoded sign from SIG item\n");
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
+        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR;
         return NULL;
     }
 
@@ -3356,10 +3442,10 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     dap_chain_addr_t l_wallet_addr;
     dap_chain_addr_fill_from_key(&l_wallet_addr, a_key, s_get_net_id(a_net_str));
     if (!dap_chain_addr_compare(&l_owner_addr, &l_wallet_addr)) {
-        printf("Trying to invalidate delegating tx with not a owner wallet\n");
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
+        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER;
         return NULL;
     }
     
@@ -3370,10 +3456,10 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (!token_ticker_obj) {
         token_ticker_obj = json_object_object_get(l_json_tiker, "token ticker");
         if (!token_ticker_obj) {
-            printf("Error: Token ticker not found in response\n");
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
+            if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND;
             return NULL;
         }
     }
@@ -3384,6 +3470,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
+        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND;
         return NULL;
     }
 
@@ -3400,11 +3487,11 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
                                                                 l_fee_total, 
                                                                 &l_fee_transfer);
     if (!l_list_fee_out) {
-        printf("Not enough funds to pay fee");
         json_object_put(l_outs_native);
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
+        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS;
         return NULL;
     }
 
@@ -3418,23 +3505,23 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
     dap_list_free_full(l_list_fee_out, NULL);
     if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
-        printf("Can't compose the transaction input\n");
         dap_chain_datum_tx_delete(l_tx);
         json_object_put(l_outs_native);
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
+        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR;
         return NULL;
     }
 
     // add 'out_ext' item
     if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_tx_out_cond->header.value, l_delegated_ticker) == -1) {
         dap_chain_datum_tx_delete(l_tx);
-        printf("Cant add returning coins output\n");
         json_object_put(l_outs_native);
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
+        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR;
         return NULL;
     }
     // add fee items
@@ -3445,6 +3532,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
+            if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR;
             return NULL;
         }
     }
@@ -3455,6 +3543,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
+            if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR;
             return NULL;
         }
     }
@@ -3468,6 +3557,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
+            if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR;
             return NULL;
         }
     }
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 78c4cee86e..eed34cd883 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -62,11 +62,47 @@ int dap_tx_cond_create_compose(int argc, char ** argv);
 int dap_cli_hold_compose(int a_argc, char **a_argv);
 int dap_cli_take_compose(int a_argc, char **a_argv);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
-int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv);
+int dap_compose_srv_stake_invalidate(int a_argc, char **a_argv);
 int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv);
 
+
+typedef enum {
+    DAP_CLI_STAKE_INVALIDATE_OK = 0,
+    DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND = -1,
+    DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING = -2,
+    DAP_CLI_STAKE_INVALIDATE_WRONG_CERT = -3,
+    DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR = -4,
+    DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH = -5,
+    DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED = -6,
+    DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT = -7,
+    DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND = -8,
+    DAP_CLI_STAKE_INVALIDATE_TX_EXISTS = -9,
+    DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND = -10,
+    DAP_CLI_STAKE_INVALIDATE_COMPOSE_ERROR = -11,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR = -12,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND = -13,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT = -14,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND = -15,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR = -16,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND = -17,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND = -18,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR = -19,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER = -20,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND = -21,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND = -22,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS = -23,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR = -24,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR = -25,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR = -26,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28
+} dap_cli_stake_invalidate_error_t;
+int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
+                        const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port);
+dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, int *l_ret);
+
 json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port);
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
 
@@ -104,7 +140,6 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
                               const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port);
-dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port);
 dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
-- 
GitLab


From ca166c2f5dcd3ba755ecb8bf5373c799df51a5d0 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Wed, 9 Apr 2025 16:15:17 +0700
Subject: [PATCH 41/53] [*] delegate

---
 modules/compose/dap_chain_tx_compose.c        | 438 ++++--------------
 .../compose/include/dap_chain_tx_compose.h    |  45 +-
 2 files changed, 138 insertions(+), 345 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 99751e1b64..9306e634de 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -3010,166 +3010,6 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
 */
 
 
-int dap_compose_srv_stake_invalidate(int a_argc, char **a_argv)
-{
-    const char *l_net_str = NULL,
-               *l_wallet_str = NULL,
-               *l_cert_str = NULL,
-               *l_fee_str = NULL,
-               *l_tx_hash_str = NULL,
-               *l_url_str = NULL,
-               *l_port_str = NULL;
-    uint16_t l_port = 0;
-               
-    int l_arg_index = 1;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
-    if (!l_net_str) {
-        printf("Command 'invalidate' requires parameter -net\n");
-        return -1;
-    }
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
-        l_url_str = s_get_net_url(l_net_str);
-    }
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
-        l_port = s_get_net_port(l_net_str);
-    } else {
-        l_port = atoi(l_port_str);
-    }
-
-    const char *l_wallet_path = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
-    if (!l_wallet_path) {
-        arg_wallets_path =
-        #ifdef DAP_OS_WINDOWS
-                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-        #elif defined DAP_OS_MAC
-                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-        #elif defined DAP_OS_UNIX
-                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-        #endif
-    } else {
-        arg_wallets_path = dap_strdup(l_wallet_path);
-    }
-
-    uint256_t l_fee = {};
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
-    if (!l_wallet_str) {
-        printf("Command 'invalidate' requires parameter -w\n");
-        return -1;
-    }
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
-    if (!l_fee_str) {
-        printf("Command 'delegate' requires parameter -fee\n");
-        return -1;
-    }
-    l_fee = dap_chain_balance_scan(l_fee_str);
-    if (IS_ZERO_256(l_fee)) {
-        printf("Unrecognized number in '-fee' param\n");
-        return -1;
-    }
-
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tx", &l_tx_hash_str);
-    if (!l_tx_hash_str) {
-        dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str);
-        if (!l_cert_str) {
-            printf("Command 'invalidate' requires parameter -tx or -cert\n");
-            return -1;
-        }
-    }
-    json_object *l_json_obj_ret = json_object_new_object();
-    int ret = dap_cli_srv_stake_invalidate_compose(l_json_obj_ret, l_net_str, l_tx_hash_str, l_wallet_str, l_wallet_path, l_cert_str, l_fee, l_url_str, l_port);
-    switch (ret) {
-        case DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND:
-            printf("Error: Specified certificate not found\n");
-            break;
-        case DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING:
-            printf("Error: It is not possible to invalidate a stake using a public key.\n");
-            break;
-        case DAP_CLI_STAKE_INVALIDATE_WRONG_CERT:
-            printf("Error: Specified certificate is wrong\n");
-            break;
-        case DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR:
-            printf("Error: Failed to retrieve coins from ledger\n");
-            break;
-        case DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH:
-            printf("Error: Invalid transaction hash format\n");
-            break;
-        case DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED:
-            printf("Error: Specified address is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n");
-            break;
-        case DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT:
-            printf("Error: Transaction does not have a delegate out\n");
-            break;
-        case DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND:
-            printf("Error: Previous transaction is not found\n");
-            break;
-        case DAP_CLI_STAKE_INVALIDATE_TX_EXISTS:
-            printf("Error: Transaction already exists in the ledger\n");
-            break;
-        case DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND:
-            printf("Error: Specified wallet not found\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR:
-            printf("Error: Failed to get response from remote node\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND:
-            printf("Error: ITEMS array not found in JSON response\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT:
-            printf("Error: All outputs are spent\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND:
-            printf("Error: Tx_prev_hash not found in ITEMS array\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR:
-            printf("Error: Request conditional transaction failed\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND:
-            printf("Error: Required conditional transaction structures not found\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND:
-            printf("Error: SIG item not found in ITEMS array\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR:
-            printf("Error: Can't get base64-encoded sign from SIG item\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER:
-            printf("Trying to invalidate delegating tx with not a owner wallet\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND:
-            printf("Error: Token ticker not found in response\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND:
-            printf("Error: Failed to get transaction outputs\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS:
-            printf("Error: Not enough funds to pay fee\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR:
-            printf("Error: Can't compose the transaction input\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR:
-            printf("Error:Cant add returning coins output\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR:
-            printf("Error: Can't add network fee output\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR:
-            printf("Error: Can't add fee output\n");
-            break;
-        case DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR:
-            printf("Error: Can't add fee back output\n");
-            break;
-        case DAP_CLI_STAKE_INVALIDATE_OK:
-            printf("%s", json_object_to_json_string(l_json_obj_ret));
-            break;
-        default:
-            printf("Error: Unknown error code: %d\n", ret);
-    }
-    
-    json_object_put(l_json_obj_ret);
-    return ret;
-}
 
 int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
                         const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port)
@@ -3703,195 +3543,118 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o
 
 
 
-int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
-{
-    int l_arg_index = 0;
-    const char *l_net_str = NULL,
-               *l_wallet_str = NULL,
-               *l_cert_str = NULL,
-               *l_pkey_str = NULL,
-               *l_pkey_full_str = NULL,
-               *l_sign_type_str = NULL,
-               *l_value_str = NULL,
-               *l_fee_str = NULL,
-               *l_node_addr_str = NULL,
-               *l_order_hash_str = NULL,
-               *l_url_str = NULL,
-               *l_port_str = NULL;
-    int l_port = 0;
-    
-    dap_pkey_t *l_pkey = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
-    if (!l_net_str) {
-        printf("Command 'delegate' requires parameter -net\n");
-        return -1;
-    }
-
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
-        l_url_str = s_get_net_url(l_net_str);
-    }
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
-        l_port = s_get_net_port(l_net_str);
-    } else {
-        l_port = atoi(l_port_str);
-    }
-
-    const char *l_wallet_path = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
-    if (!l_wallet_path) {
-        arg_wallets_path =
-        #ifdef DAP_OS_WINDOWS
-                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-        #elif defined DAP_OS_MAC
-                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-        #elif defined DAP_OS_UNIX
-                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-        #endif
-    } else {
-        arg_wallets_path = dap_strdup(l_wallet_path);
-    }
-
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
-    if (!l_wallet_str) {
-        printf("Command 'delegate' requires parameter -w\n");
-        return -1;
-    }
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL);
+int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
+                                        const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, 
+                                        const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str) {
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, arg_wallets_path, NULL);
     if (!l_wallet) {
         printf("Specified wallet not found\n");
-        return -2;
+        return STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND;
     }
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
     dap_chain_wallet_close(l_wallet);
     dap_chain_addr_t l_signing_addr, l_sovereign_addr = {};
     uint256_t l_sovereign_tax = uint256_0;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str);
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str);
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-sign_type", &l_sign_type_str);
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str);
-    if (!l_cert_str && !l_order_hash_str && !l_pkey_full_str) {
-        printf("Command 'delegate' requires parameter -cert and/or -order and/or -pkey\n");
-        dap_enc_key_delete(l_enc_key);
-        return -1;
-    }
-    if (l_pkey_full_str) {
-        printf("Command 'delegate' requires only one, -pkey or -pkey_full\n");
-        dap_enc_key_delete(l_enc_key);
-        return -1;
-    }
-    if (( l_pkey_full_str) && !l_sign_type_str) {
-        printf("Command 'delegate' requires parameter -sign_type for pkey\n");
-        dap_enc_key_delete(l_enc_key);
-        return -1;
-    }
     uint256_t l_value = uint256_0;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str);
-    if (!l_value_str) {
-        if (!l_order_hash_str) {
-            printf("Command 'delegate' requires parameter -value\n");
-            dap_enc_key_delete(l_enc_key);
-            return -1;
-        }
-    } else {
-        l_value = dap_chain_balance_scan(l_value_str);
+    if (a_value_str) {
+        l_value = dap_chain_balance_scan(a_value_str);
         if (IS_ZERO_256(l_value)) {
             printf("Unrecognized number in '-value' param\n");
             dap_enc_key_delete(l_enc_key);
-            return -1;
+            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE;
         }
     }
+    dap_pkey_t *l_pkey = NULL;
     dap_chain_datum_tx_t *l_prev_tx = NULL;
-    if (l_cert_str) {
-        dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str);
+    if (a_cert_str) {
+        dap_cert_t *l_signing_cert = dap_cert_find_by_name(a_cert_str);
         if (!l_signing_cert) {
             printf("Specified certificate not found\n");
             dap_enc_key_delete(l_enc_key);
-            return -3;
+            return STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND;
         }
-        if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(l_net_str))) {
+        if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(a_net_str))) {
             printf("Specified certificate is wrong\n");
             dap_enc_key_delete(l_enc_key);
-            return -4;
+            return STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG;
         }
         l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key);
-        dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
-    }  else if (l_pkey_full_str) {
-        dap_sign_type_t l_type = dap_sign_type_from_str(l_sign_type_str);
+    }  else if (a_pkey_full_str) {
+        dap_sign_type_t l_type = dap_sign_type_from_str(a_sign_type_str);
         if (l_type.type == SIG_TYPE_NULL) {
             printf("Wrong sign type\n");
             dap_enc_key_delete(l_enc_key);
-            return -5;
+            return STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE;
         }
-        l_pkey = dap_pkey_get_from_str(l_pkey_full_str);
+        l_pkey = dap_pkey_get_from_str(a_pkey_full_str);
         if (!l_pkey) {
             printf("Invalid pkey string format, can't get pkey_full\n");
             dap_enc_key_delete(l_enc_key);
-            return -6;
+            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY;
         }
         if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) {
             printf("pkey and sign types is different\n");
             dap_enc_key_delete(l_enc_key);
-            return -6;
+            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY;
         }
         dap_chain_hash_fast_t l_hash_public_key = {0};
         if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) {
             printf("Invalid pkey hash format\n");
             dap_enc_key_delete(l_enc_key);
-            return -6;
+            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY;
         }
-        dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(l_net_str));
-        dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
+        dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(a_net_str));
     }
 
     dap_chain_node_addr_t l_node_addr = g_node_addr;
-    if (l_node_addr_str) {
-        if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) {
-            printf("Unrecognized node addr %s\n", l_node_addr_str);
+    if (a_node_addr_str) {
+        if (dap_chain_node_addr_from_str(&l_node_addr, a_node_addr_str)) {
+            printf("Unrecognized node addr %s\n", a_node_addr_str);
             dap_enc_key_delete(l_enc_key);
-            return -7;
+            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR;
         }
     }
-    if (l_order_hash_str) {
+    if (a_order_hash_str) {
         uint256_t l_tax;
         uint256_t l_value_max;
         int l_prev_tx_count = 0;
-        dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, l_url_str, l_port);
+        dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(a_net_str, a_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, a_url_str, a_port);
         if (!l_order) {
             printf("Error: Failed to get order from remote node\n");
             dap_enc_key_delete(l_enc_key);
-            return -8;
+            return STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND;
         }
         l_sovereign_tax = l_tax;
 
         if (l_order->direction == SERV_DIR_BUY) { // Staker order
-            if (!l_cert_str) {
+            if (!a_cert_str) {
                 printf("Command 'delegate' requires parameter -cert with this order type\n");
                 dap_enc_key_delete(l_enc_key);
-                return -1;
+                return STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED;
             }
             if (l_order->ext_size != 0) {
                 printf("Specified order has invalid size\n");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return -9;
+                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE;
             }
 
             dap_chain_tx_out_cond_t *l_cond_tx = NULL;
             char data[512];
             snprintf(data, sizeof(data), 
                     "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-                    dap_chain_hash_fast_to_str_static(&l_order->tx_cond_hash), l_net_str);
+                    dap_chain_hash_fast_to_str_static(&l_order->tx_cond_hash), a_net_str);
             
-            json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+            json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
             if (!response) {
                 printf("Error: Failed to get response from remote node\n");
-                return -15;
+                return STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE;
             }
             
             json_object *items = json_object_object_get(response, "ITEMS");
             if (!items) {
                 printf("Error: No items found in response\n");
-                return -16;
+                return STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS;
             }
             int items_count = json_object_array_length(items);
             for (int i = 0; i < items_count; i++) {
@@ -3909,7 +3672,7 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                         l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr")));
                         if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) {
                             printf("Error: Failed to parse signer node address\n");
-                            return -17;
+                            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR;
                         }
                         l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
                         l_prev_tx_count++;
@@ -3921,100 +3684,98 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
             }
             if (!l_cond_tx) {
                 printf("Error: No transaction output condition found\n");
-                return -7;
+                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR;
             }
 
             json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
             const char *spent_outs_value = json_object_get_string(spent_outs);
             if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
                 printf("Error: Transaction output item already used\n");
-                return -9;
+                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE;
             }
 
             char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
-            dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(l_net_str));
+            dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(a_net_str));
             const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker"));
             if (!l_token_ticker) {
                 printf("Error: Token ticker not found in response\n");
-                return -18;
+                return STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER;
             }
             json_object_put(response);
             if (dap_strcmp(l_token_ticker, l_delegated_ticker)) {
                 printf("Requested conditional transaction have another ticker (not %s)\n", l_delegated_ticker);
-                return -13;
+                return STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER;
             }
             if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) {
                 printf("The order's conditional transaction has invalid format\n");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return -14;
+                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT;
             }
             if (compare256(l_cond_tx->header.value, l_order->price)) {
                 printf("The order's conditional transaction has different value\n");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return -15;
+                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE;
             }
             if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) ||
                     l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) {
                 printf("The order's conditional transaction gas not blank address or key\n");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return -16;
+                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR;
             }
             l_value = l_order->price;
         } else {
-            if (!l_value_str) {
+            if (!a_value_str) {
                 printf("Command 'delegate' requires parameter -value with this order type\n");
                 dap_enc_key_delete(l_enc_key);
-                return -1;
+                return STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED;
             }
-            const char *l_sovereign_addr_str = NULL;
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str);
-            if (l_sovereign_addr_str) {
-                dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str);
+            if (a_sovereign_addr_str) {
+                dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(a_sovereign_addr_str);
                 if (!l_spec_addr) {
                     printf("Specified address is ivalid\n");
-                    return -17;
+                    return STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR;
                 }
                 l_sovereign_addr = *l_spec_addr;
                 DAP_DELETE(l_spec_addr);
             } else
-                dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, s_get_net_id(l_net_str));
+                dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, s_get_net_id(a_net_str));
 
-            if (l_order_hash_str && compare256(l_value, l_order->price) == -1) {
+            if (a_order_hash_str && compare256(l_value, l_order->price) == -1) {
                 const char *l_coin_min_str, *l_value_min_str =
                     dap_uint256_to_char(l_order->price, &l_coin_min_str);
                 printf("Number in '-value' param %s is lower than order minimum allowed value %s(%s)\n",
-                                                  l_value_str, l_coin_min_str, l_value_min_str);
+                                                  a_value_str, l_coin_min_str, l_value_min_str);
                 dap_enc_key_delete(l_enc_key);
-                return -18;
+                return STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW;
             }
-            if (l_order_hash_str && compare256(l_value, l_value_max) == 1) {
+            if (a_order_hash_str && compare256(l_value, l_value_max) == 1) {
                 const char *l_coin_max_str, *l_value_max_str =
                     dap_uint256_to_char(l_value_max, &l_coin_max_str);
                 printf("Number in '-value' param %s is higher than order minimum allowed value %s(%s)\n",
-                                                  l_value_str, l_coin_max_str, l_value_max_str);
+                                                  a_value_str, l_coin_max_str, l_value_max_str);
                 dap_enc_key_delete(l_enc_key);
-                return -19;
+                return STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH;
             }
             size_t l_sign_size = 0;
-            dap_sign_t *l_sign = dap_get_remote_srv_order_sign(l_net_str, l_order_hash_str, l_url_str, l_port);
+            dap_sign_t *l_sign = dap_get_remote_srv_order_sign(a_net_str, a_order_hash_str, a_url_str, a_port);
             if (!l_sign) {
                 printf("Specified order is unsigned\n");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return -20;
+                return STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER;
             }
-            dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, s_get_net_id(l_net_str));
+            dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, s_get_net_id(a_net_str));
             l_pkey = dap_pkey_get_from_sign(l_sign);
             char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX];
-            dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, s_get_native_ticker(l_net_str));
+            dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, s_get_native_ticker(a_net_str));
             if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) {
                 printf("Specified order is invalid\n");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return -21;
+                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER;
             }
             l_node_addr = l_order->node_addr;
         }
@@ -4023,14 +3784,14 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
                 compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) {
             printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n");
             dap_enc_key_delete(l_enc_key);
-            return -22;
+            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX;
         }
         DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
     }
     if (!l_pkey) {
         printf("pkey not defined\n");
         dap_enc_key_delete(l_enc_key);
-        return -6;
+        return STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED;
     }
 
     // TODO: need to make sure that the key and node are required verification 
@@ -4042,52 +3803,49 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv)
     // }
  
 
-    uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str, l_url_str, l_port);
+    uint256_t l_allowed_min = s_get_key_delegating_min_value(a_net_str, a_url_str, a_port);
     if (compare256(l_value, l_allowed_min) == -1) {
         const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str);
         printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n",
-                                          l_value_str, l_coin_min_str, l_value_min_str);
+                                          a_value_str, l_coin_min_str, l_value_min_str);
         dap_enc_key_delete(l_enc_key);
-        return -23;
-    }
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
-    if (!l_fee_str) {
-        printf("Command 'delegate' requires parameter -fee\n");
-        dap_enc_key_delete(l_enc_key);
-        return -1;
+        return STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN;
     }
-    uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+
+    uint256_t l_fee = dap_chain_balance_scan(a_fee_str);
     if (IS_ZERO_256(l_fee)) {
         printf("Unrecognized number in '-fee' param\n");
         dap_enc_key_delete(l_enc_key);
-        return -1;
+        return STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE;
     }
-
-    // Create conditional transaction
-    dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr,
-                                                   l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, l_url_str, l_port);
+    int l_ret = 0;
+    dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(a_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr,
+                                                   a_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, a_url_str, a_port, &l_ret);
+    
     dap_enc_key_delete(l_enc_key);
     DAP_DELETE(l_pkey);
 
-    json_object * l_json_obj_ret = json_object_new_object();
-    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-    printf("%s", json_object_to_json_string(l_json_obj_ret));
-    json_object_put(l_json_obj_ret);
+    if (l_ret) {
+        return l_ret;
+    }
+    dap_chain_net_tx_to_json(l_tx, a_json_obj_ret);
     DAP_DELETE(l_tx);
 
-    return 0;
+    return STAKE_DELEGATE_COMPOSE_OK;
 
 }
 
-// Freeze staker's funds when delegating a key
+
 dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
-                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port)
+                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, int *l_ret)
 {
-    if  (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr)
+    if  (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) {
+        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS;
         return NULL;
+    }
     const char *l_native_ticker = s_get_native_ticker(a_net_str);
     char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker);
@@ -4106,11 +3864,13 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
 
     json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
     if (!l_outs_native) {
+        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE;
         return NULL;
     }
 
     json_object *l_outs_delegated = dap_get_remote_tx_outs(l_delegated_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
     if (!l_outs_delegated) {
+        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE;
         return NULL;
     }
 
@@ -4121,9 +3881,9 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
                                                     l_fee_total, 
                                                     &l_fee_transfer);
     if (!l_list_fee_out) {
-        printf("Not enough funds to pay fee");
         json_object_put(l_outs_native);
         json_object_put(l_outs_delegated);
+        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE;
         return NULL;
     }
 
@@ -4135,16 +3895,16 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
                                                                a_value, 
                                                                &l_value_transfer);
         if (!l_list_used_out) {
-            printf("Not enough funds to pay fee");
             json_object_put(l_outs_native);
             json_object_put(l_outs_delegated);
+            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE;
             return NULL;
         }
         // add 'in' items to pay for delegate
         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
         dap_list_free_full(l_list_used_out, NULL);
         if (!EQUAL_256(l_value_to_items, l_value_transfer)) {
-            printf("Can't compose the transaction input\n");
+            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR;
             goto tx_fail;
         }
     } else {
@@ -4154,7 +3914,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
         dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
         // add 'in' item to buy from conditional transaction
         if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_out_num, -1)) {
-            printf("Can't compose the transaction conditional input\n");
+            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR;
             goto tx_fail;
         }
     }
@@ -4162,7 +3922,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
     dap_list_free_full(l_list_fee_out, NULL);
     if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
-        printf("Can't compose the fee transaction input\n");
+        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR;
         goto tx_fail;
     }
 
@@ -4172,7 +3932,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
                                                                                           a_sovereign_addr, a_sovereign_tax, a_pkey);
 
     if (!l_tx_out) {
-        printf("Can't compose the transaction conditional output\n");
+        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR;
         goto tx_fail;
     }
     dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
@@ -4183,7 +3943,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
         SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back);
         if (!IS_ZERO_256(l_value_back)) {
             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) {
-                printf("Cant add coin back output\n");
+                if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR;
                 goto tx_fail;
             }
         }
@@ -4192,13 +3952,13 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     // add fee items
     if (l_net_fee_used) {
         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
-            printf("Cant add net fee output\n");
+            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR;
             goto tx_fail;
         }
     }
     if (!IS_ZERO_256(a_fee)) {
         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
-            printf("Cant add validator fee output\n");
+            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR;
             goto tx_fail;
         }
     }
@@ -4207,17 +3967,11 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back);
     if (!IS_ZERO_256(l_fee_back)) {
         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) {
-            printf("Cant add fee back output\n");
+            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR;
             goto tx_fail;
         }
     }
 
-    // // add 'sign' item
-    // if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) {
-    //     printf("Can't add sign output\n");
-    //     goto tx_fail;
-    // }
-
     return l_tx;
 
 tx_fail:
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index eed34cd883..221b35b954 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -62,12 +62,51 @@ int dap_tx_cond_create_compose(int argc, char ** argv);
 int dap_cli_hold_compose(int a_argc, char **a_argv);
 int dap_cli_take_compose(int a_argc, char **a_argv);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
-int dap_compose_srv_stake_invalidate(int a_argc, char **a_argv);
-int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv);
 int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv);
 
-
+typedef enum {
+    STAKE_DELEGATE_COMPOSE_OK = 0,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE = -1,
+    STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND = -2, 
+    STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND = -3,
+    STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG = -4,
+    STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE = -5,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY = -6,
+    STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED = -6,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR = -7,
+    STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND = -8,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE = -9,
+    STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED = -10,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED = -11,
+    STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER = -13,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT = -14,
+    STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE = -15,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE = -15,
+    STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS = -16,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR = -16,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR = -17,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR = -17,
+    STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER = -18,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW = -18,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH = -19,
+    STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER = -20,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER = -21,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX = -22,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN = -23,
+    DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS = -24,
+    DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE = -25,
+    DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE = -26,
+    DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR = -27,
+    DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR = -28,
+    DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR = -29,
+    DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR = -30,
+    DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -31,
+    DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -32
+} stake_delegate_error_t;
+int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
+                                        const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, 
+                                        const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str);
 typedef enum {
     DAP_CLI_STAKE_INVALIDATE_OK = 0,
     DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND = -1,
-- 
GitLab


From 5d5bd7ce870cb1d9a2bed594dbef1d390052fcdd Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Wed, 9 Apr 2025 16:34:41 +0700
Subject: [PATCH 42/53] [*] fix build

---
 modules/compose/dap_chain_tx_compose.c        | 134 ++++++++----------
 .../compose/include/dap_chain_tx_compose.h    |  65 +++++----
 2 files changed, 92 insertions(+), 107 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 9306e634de..f0b96bcc50 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -41,45 +41,41 @@
 
 #include <json-c/json.h>
 
-
-
-const char *arg_wallets_path = NULL;
-
-static const char* s_get_native_ticker(const char* name) {
+const char* dap_compose_get_net_url(const char* name) {
     for (int i = 0; i < NET_COUNT; i++) {
         if (strcmp(netinfo[i].name, name) == 0) {
-            return netinfo[i].native_ticker;
+            return netinfo[i].url;
         }
     }
     return NULL;
 }
 
-static dap_chain_net_id_t s_get_net_id(const char* name) {
+uint16_t dap_compose_get_net_port(const char* name) {
     for (int i = 0; i < NET_COUNT; i++) {
         if (strcmp(netinfo[i].name, name) == 0) {
-            return netinfo[i].net_id;
+            return netinfo[i].port;
         }
     }
-    dap_chain_net_id_t empty_id = {.uint64 = 0};
-    return empty_id;
+    return 0;
 }
 
-static const char* s_get_net_url(const char* name) {
+static const char* s_get_native_ticker(const char* name) {
     for (int i = 0; i < NET_COUNT; i++) {
         if (strcmp(netinfo[i].name, name) == 0) {
-            return netinfo[i].url;
+            return netinfo[i].native_ticker;
         }
     }
     return NULL;
 }
 
-static uint16_t s_get_net_port(const char* name) {
+static dap_chain_net_id_t s_get_net_id(const char* name) {
     for (int i = 0; i < NET_COUNT; i++) {
         if (strcmp(netinfo[i].name, name) == 0) {
-            return netinfo[i].port;
+            return netinfo[i].net_id;
         }
     }
-    return 0;
+    dap_chain_net_id_t empty_id = {.uint64 = 0};
+    return empty_id;
 }
 
 
@@ -266,8 +262,8 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a
     }
 
     dap_client_http_request(dap_worker_get_auto(),
-                                a_url_str ? a_url_str : s_get_net_url(a_net_name),
-                                a_port ? a_port : s_get_net_port(a_net_name),
+                                a_url_str ? a_url_str : dap_compose_get_net_url(a_net_name),
+                                a_port ? a_port : dap_compose_get_net_port(a_net_name),
                                 "POST", "application/json",
                                 NULL, request, strlen(request), NULL,
                                 s_cmd_response_handler, s_cmd_error_handler,
@@ -442,7 +438,7 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) {
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
     if (!l_wallet_path) {
-        arg_wallets_path =
+        l_wallet_path =
         #ifdef DAP_OS_WINDOWS
                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
         #elif defined DAP_OS_MAC
@@ -450,8 +446,6 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) {
         #elif defined DAP_OS_UNIX
                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
         #endif
-    } else {
-        arg_wallets_path = dap_strdup(l_wallet_path);
     }
 
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
@@ -470,11 +464,11 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) {
     }
 
     if (!l_url_str) {
-        l_url_str = s_get_net_url(l_net_name);
+        l_url_str = dap_compose_get_net_url(l_net_name);
     }
 
     if (!l_port_str) {
-        l_port = s_get_net_port(l_net_name);
+        l_port = dap_compose_get_net_port(l_net_name);
     } else {
         l_port = atoi(l_port_str);
     }
@@ -509,7 +503,7 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) {
         return -1;
     }
 
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, arg_wallets_path, NULL);
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL);
     if(!l_wallet) {
         printf("wallet %s does not exist", l_wallet_name);
         return -1;
@@ -560,7 +554,7 @@ int dap_tx_create_compose(int argc, char ** argv) {
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
     if (!l_wallet_path) {
-        arg_wallets_path =
+        l_wallet_path =
         #ifdef DAP_OS_WINDOWS
                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
         #elif defined DAP_OS_MAC
@@ -568,9 +562,7 @@ int dap_tx_create_compose(int argc, char ** argv) {
         #elif defined DAP_OS_UNIX
                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
         #endif
-    } else {
-        arg_wallets_path = dap_strdup(l_wallet_path);
-    }
+    }  
 
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
     if (!l_net_name) {
@@ -579,11 +571,11 @@ int dap_tx_create_compose(int argc, char ** argv) {
     }
 
     if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str)) {
-        l_url_str = s_get_net_url(l_net_name);
+        l_url_str = dap_compose_get_net_url(l_net_name);
     }
     const char *l_port_str = NULL;
     if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str)) {
-        l_port = s_get_net_port(l_net_name);
+        l_port = dap_compose_get_net_port(l_net_name);
     } else {
         l_port = atoi(l_port_str);
     }
@@ -688,7 +680,7 @@ int dap_tx_create_compose(int argc, char ** argv) {
         DAP_DELETE(l_addr_base58_to_array);
     }
     
-    dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, arg_wallets_path, NULL);
+    dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, l_wallet_path, NULL);
     if(!l_wallet) {
         printf("Can't open wallet %s", l_from_wallet_name);
         return -12;
@@ -1331,7 +1323,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
     if (!l_wallet_path) {
-        arg_wallets_path =
+        l_wallet_path =
         #ifdef DAP_OS_WINDOWS
                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
         #elif defined DAP_OS_MAC
@@ -1339,9 +1331,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
         #elif defined DAP_OS_UNIX
                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
         #endif
-    } else {
-        arg_wallets_path = dap_strdup(l_wallet_path);
-    }
+    }  
 
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_str);
@@ -1379,10 +1369,10 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
         return -7;
     }
     if(!l_url_str) {
-        l_url_str = s_get_net_url(l_net_name);
+        l_url_str = dap_compose_get_net_url(l_net_name);
     }
     if(!l_port_str) {
-        l_port = s_get_net_port(l_net_name);
+        l_port = dap_compose_get_net_port(l_net_name);
     } else {
         l_port = atoi(l_port_str);
     }
@@ -1421,7 +1411,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv)
         return -13;
     }
 
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL);
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
     if(!l_wallet) {
         printf("Can't open wallet '%s'\n", l_wallet_str);
         return -15;
@@ -1566,7 +1556,6 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
             *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL,
             *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL;
 
-    const char *l_wallets_path								=	arg_wallets_path;
     char 	l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
     dap_time_t              			l_time_staking		=	0;
     uint256_t						    l_reinvest_percent	=	{};
@@ -1582,7 +1571,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
     if (!l_wallet_path) {
-        arg_wallets_path =
+        l_wallet_path =
         #ifdef DAP_OS_WINDOWS
                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
         #elif defined DAP_OS_MAC
@@ -1590,9 +1579,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
         #elif defined DAP_OS_UNIX
                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
         #endif
-    } else {
-        arg_wallets_path = dap_strdup(l_wallet_path);
-    }
+    }  
 
 
     const char *l_hash_out_type = NULL;
@@ -1615,12 +1602,12 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
     }
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) {
-        l_url_str = s_get_net_url(l_net_name);
+        l_url_str = dap_compose_get_net_url(l_net_name);
     }
 
     const char *l_port_str = NULL;
     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) {
-        l_port = s_get_net_port(l_net_name);
+        l_port = dap_compose_get_net_port(l_net_name);
     } else {
         l_port = atoi(l_port_str);
     }
@@ -1743,7 +1730,7 @@ int  dap_cli_hold_compose(int a_argc, char **a_argv)
         }
     }
 
-    if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallets_path, NULL))) {
+    if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) {
         printf("Error: Unable to open wallet '%s'\n", l_wallet_str);
         return -22;
     }
@@ -1971,7 +1958,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
     if (!l_wallet_path) {
-        arg_wallets_path =
+        l_wallet_path =
         #ifdef DAP_OS_WINDOWS
                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
         #elif defined DAP_OS_MAC
@@ -1979,9 +1966,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
         #elif defined DAP_OS_UNIX
                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
         #endif
-    } else {
-        arg_wallets_path = dap_strdup(l_wallet_path);
-    }
+    }  
 
 
     const char *l_hash_out_type = NULL;
@@ -1999,12 +1984,12 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
     }
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) {
-        l_url_str = s_get_net_url(l_net_str);
+        l_url_str = dap_compose_get_net_url(l_net_str);
     }
 
     const char *l_port_str = NULL;
     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) {
-        l_port = s_get_net_port(l_net_str);
+        l_port = dap_compose_get_net_port(l_net_str);
     } else {
         l_port = atoi(l_port_str);
     }
@@ -2117,7 +2102,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv)
         return -15;
     }
 
-    if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL))) {
+    if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) {
         printf("Error: Unable to open wallet\n");
         return -16;
     }
@@ -2379,7 +2364,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
     if (!l_wallet_path) {
-        arg_wallets_path =
+        l_wallet_path =
         #ifdef DAP_OS_WINDOWS
                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
         #elif defined DAP_OS_MAC
@@ -2387,9 +2372,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
         #elif defined DAP_OS_UNIX
                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
         #endif
-    } else {
-        arg_wallets_path = dap_strdup(l_wallet_path);
-    }
+    }  
     
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
     // Select chain network
@@ -2399,12 +2382,12 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
     }
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-url", &l_url_str)) {
-        l_url_str = s_get_net_url(l_net_str);
+        l_url_str = dap_compose_get_net_url(l_net_str);
     }
 
     const char *l_port_str = NULL;
     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str)) {
-        l_port = s_get_net_port(l_net_str);
+        l_port = dap_compose_get_net_port(l_net_str);
     } else {
         l_port = atoi(l_port_str);
     }
@@ -2466,7 +2449,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv)
 
     bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false;
     bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false;
-    dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL);
+    dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
     if (!l_wallet_fee) {
         printf("Wallet %s does not exist\n", l_wallet_str);
         return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
@@ -2740,8 +2723,8 @@ int dap_cli_vote_compose(int a_argc, char **a_argv){
         return -DAP_CHAIN_NET_VOTE_VOTING_OPTION_IDX_PARAM_NOT_VALID;
     }
 
-    const char *arg_wallets_path = dap_chain_wallet_get_path(g_config);
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path,NULL);
+    const char *l_wallet_path = dap_chain_wallet_get_path(g_config);
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path,NULL);
     if (!l_wallet) {
         printf("Wallet %s does not exist\n", l_wallet_str);
         return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST;
@@ -3545,8 +3528,8 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o
 
 int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
                                         const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, 
-                                        const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str) {
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, arg_wallets_path, NULL);
+                                        const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path) {
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallets_path, NULL);
     if (!l_wallet) {
         printf("Specified wallet not found\n");
         return STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND;
@@ -3985,9 +3968,10 @@ static dap_chain_datum_tx_t *dap_order_tx_create_compose(const char * a_net_str,
                                                 const char *l_url_str, int l_port)
 {
     dap_chain_node_addr_t l_node_addr = {};
+    int l_ret = 0;
     return dap_stake_tx_create_compose(a_net_str, a_key, a_value, a_fee,
                              (dap_chain_addr_t *)&c_dap_chain_addr_blank, &l_node_addr,
-                             a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port);
+                             a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, &l_ret);
 }
 
 //srv_stake order create staker -net <net_name> -w <wallet_with_m_tokens> -value <stake_value> -fee <value> -tax <percent> [-addr <for_tax_collecting>]  [-cert <for_order_signing>] [-H {hex(default) | base58}]
@@ -4009,10 +3993,10 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
     }
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
-        l_url_str = s_get_net_url(l_net_str);
+        l_url_str = dap_compose_get_net_url(l_net_str);
     }
     if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
-        l_port = s_get_net_port(l_net_str);
+        l_port = dap_compose_get_net_port(l_net_str);
     } else {
         l_port = atoi(l_port_str);
     }
@@ -4020,7 +4004,7 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
     if (!l_wallet_path) {
-        arg_wallets_path =
+        l_wallet_path =
         #ifdef DAP_OS_WINDOWS
                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
         #elif defined DAP_OS_MAC
@@ -4028,9 +4012,7 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
         #elif defined DAP_OS_UNIX
                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
         #endif
-    } else {
-        arg_wallets_path = dap_strdup(l_wallet_path);
-    }
+    }  
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str) || !l_value_str) {
         printf("Staker order creation requires parameter -value\n");
@@ -4133,10 +4115,10 @@ int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) {
     }
 
         if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
-        l_url_str = s_get_net_url(l_net_str);
+        l_url_str = dap_compose_get_net_url(l_net_str);
     }
     if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
-        l_port = s_get_net_port(l_net_str);
+        l_port = dap_compose_get_net_port(l_net_str);
     } else {
         l_port = atoi(l_port_str);
     }
@@ -4144,7 +4126,7 @@ int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) {
     const char *l_wallet_path = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
     if (!l_wallet_path) {
-        arg_wallets_path =
+        l_wallet_path =
         #ifdef DAP_OS_WINDOWS
                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
         #elif defined DAP_OS_MAC
@@ -4152,9 +4134,7 @@ int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) {
         #elif defined DAP_OS_UNIX
                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
         #endif
-    } else {
-        arg_wallets_path = dap_strdup(l_wallet_path);
-    }
+    }  
 
     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
     if (!l_wallet_str) {
@@ -4611,7 +4591,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net
 //         printf("Error: Command 'purchase' requires parameter -w\n");
 //         return -1;
 //     }
-//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, arg_wallets_path, NULL);
+//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL);
 //     if (!l_wallet) {
 //         printf("Error: Specified wallet not found\n");
 //         return -2;
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 221b35b954..24cd70ee3e 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -52,6 +52,11 @@ static NetInfo netinfo[NET_COUNT] = {
     {"subzero",  "tCELL", {.uint64 = 0x000000000000acca}, "http://rpc.cellframe.net", 8081}
 };
 
+
+const char* dap_compose_get_net_url(const char* name);
+uint16_t dap_compose_get_net_port(const char* name);
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -68,45 +73,45 @@ int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv);
 typedef enum {
     STAKE_DELEGATE_COMPOSE_OK = 0,
     STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE = -1,
-    STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND = -2, 
+    STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND = -2,
     STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND = -3,
     STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG = -4,
     STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE = -5,
     STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY = -6,
-    STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED = -6,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR = -7,
-    STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND = -8,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE = -9,
-    STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED = -10,
-    STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED = -11,
+    STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED = -7,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR = -8,
+    STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND = -9,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE = -10,
+    STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED = -11,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED = -12,
     STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER = -13,
     STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT = -14,
     STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE = -15,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE = -15,
-    STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS = -16,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR = -16,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR = -17,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR = -17,
-    STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER = -18,
-    STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW = -18,
-    STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH = -19,
-    STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER = -20,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER = -21,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX = -22,
-    STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN = -23,
-    DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS = -24,
-    DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE = -25,
-    DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE = -26,
-    DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR = -27,
-    DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR = -28,
-    DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR = -29,
-    DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR = -30,
-    DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -31,
-    DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -32
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE = -16,
+    STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS = -17,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR = -18,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR = -19,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR = -20,
+    STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER = -21,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW = -22,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH = -23,
+    STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER = -24,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER = -25,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX = -26,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN = -27,
+    DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS = -28,
+    DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE = -29,
+    DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE = -30,
+    DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR = -31,
+    DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR = -32,
+    DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR = -33,
+    DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR = -34,
+    DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -35,
+    DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -36
 } stake_delegate_error_t;
 int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
                                         const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, 
-                                        const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str);
+                                        const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path);
 typedef enum {
     DAP_CLI_STAKE_INVALIDATE_OK = 0,
     DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND = -1,
@@ -183,7 +188,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
-                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port);
+                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, int *l_ret);
 
 dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
                                      dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port);
-- 
GitLab


From 922f20d6e668e297f3c73a994be609b9a094ab88 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Wed, 9 Apr 2025 16:56:46 +0700
Subject: [PATCH 43/53] [*] create staker

---
 modules/compose/dap_chain_tx_compose.c        | 98 ++++---------------
 .../compose/include/dap_chain_tx_compose.h    | 14 ++-
 2 files changed, 30 insertions(+), 82 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index f0b96bcc50..ed84d7b71b 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -3832,7 +3832,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     const char *l_native_ticker = s_get_native_ticker(a_net_str);
     char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker);
-    uint256_t l_value_transfer = {}, l_fee_transfer = {}; // how many coins to transfer
+    uint256_t l_value_transfer = {}, l_fee_transfer = {}; 
     // list of transaction with 'out' items to sell
     dap_chain_addr_t l_owner_addr;
     dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str));
@@ -3965,94 +3965,38 @@ tx_fail:
 static dap_chain_datum_tx_t *dap_order_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                 uint256_t a_sovereign_tax, dap_chain_addr_t *a_sovereign_addr,
-                                                const char *l_url_str, int l_port)
+                                                const char *l_url_str, int l_port, int *l_ret)
 {
     dap_chain_node_addr_t l_node_addr = {};
-    int l_ret = 0;
     return dap_stake_tx_create_compose(a_net_str, a_key, a_value, a_fee,
                              (dap_chain_addr_t *)&c_dap_chain_addr_blank, &l_node_addr,
-                             a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, &l_ret);
+                             a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, l_ret);
 }
 
-//srv_stake order create staker -net <net_name> -w <wallet_with_m_tokens> -value <stake_value> -fee <value> -tax <percent> [-addr <for_tax_collecting>]  [-cert <for_order_signing>] [-H {hex(default) | base58}]
-int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
-    int l_arg_index = 1;
-    const char *l_value_str = NULL,
-               *l_wallet_str = NULL,
-               *l_tax_str = NULL,
-               *l_addr_str = NULL,
-               *l_fee_str = NULL,
-               *l_url_str = NULL,
-               *l_port_str = NULL,
-               *l_net_str = NULL;
-    int l_port = 0;
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str) || !l_net_str) {
-        printf("Command 'order' requires parameter -net\n");
-        return -1;
-    }
-
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
-        l_url_str = dap_compose_get_net_url(l_net_str);
-    }
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
-        l_port = dap_compose_get_net_port(l_net_str);
-    } else {
-        l_port = atoi(l_port_str);
-    }
 
-    const char *l_wallet_path = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
-    if (!l_wallet_path) {
-        l_wallet_path =
-        #ifdef DAP_OS_WINDOWS
-                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-        #elif defined DAP_OS_MAC
-                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-        #elif defined DAP_OS_UNIX
-                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-        #endif
-    }  
-
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str) || !l_value_str) {
-        printf("Staker order creation requires parameter -value\n");
-        return -1;
-    }
+int dap_cli_srv_stake_order_create_staker_compose(json_object* a_json_obj_ret, const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) {
     uint256_t l_value = dap_chain_balance_scan(l_value_str);
     if (IS_ZERO_256(l_value)) { 
         printf("Format -value <256 bit integer>\n");
-        return -2;
-    }
-
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str) || !l_fee_str) {
-        printf("Staker order creation requires parameter -fee\n");
-        return -3;
+        return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE;
     }
     uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
     if (IS_ZERO_256(l_fee)) {
         printf("Format -fee <256 bit integer>\n");
-        return -4;
-    }
-
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax", &l_tax_str) || !l_tax_str) {
-        printf("Staker order creation requires parameter -tax\n");
-        return -5;
+        return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE;
     }
     uint256_t l_tax = dap_chain_coins_to_balance(l_tax_str);
     if (compare256(l_tax, dap_chain_coins_to_balance("100.0")) == 1 ||
             compare256(l_tax, GET_256_FROM_64(100)) == -1) {
         printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n");
-        return -6;
+        return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX;
     }
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) {
-        printf("Staker order creation requires parameter -w\n");
-        return -7;
-    }
     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
     if (!l_wallet) {
         printf("Specified wallet not found\n");
-        return -8;
+        return STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND;
     }
 
     const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet);
@@ -4061,42 +4005,34 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) {
 
     if (!l_enc_key) {
         printf("Failed to retrieve encryption key\n");
-        return -9;
+        return STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND;
     }
 
     dap_chain_addr_t l_addr = {};
-    if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_addr_str) && l_addr_str) {
+    if (l_addr_str) {
         dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str);
         if (!l_spec_addr) {
             printf("Specified address is invalid\n");
             DAP_DELETE(l_enc_key);
-            return -10;
+            return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR;
         }
         l_addr = *l_spec_addr;
         DAP_DELETE(l_spec_addr);
     } else
         dap_chain_addr_fill_from_key(&l_addr, l_enc_key, s_get_net_id(l_net_str));
     DIV_256(l_tax, GET_256_FROM_64(100), &l_tax);
-    dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, &l_addr, l_url_str, l_port);
+    int l_ret = 0;
+    dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, &l_addr, l_url_str, l_port, &l_ret);
     DAP_DEL_Z(l_enc_key);
 
-    if (!l_tx) {
-        printf("Failed to create transaction\n");
-        return -11;
+    if (l_ret) {
+        return l_ret;
     }
 
-    json_object *l_json_obj_ret = json_object_new_object();
-    if (!l_json_obj_ret) {
-        printf("Failed to create JSON object\n");
-        DAP_DELETE(l_tx);
-        return -12;
-    }
+    dap_chain_net_tx_to_json(l_tx, a_json_obj_ret);
 
-    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-    printf("%s", json_object_to_json_string(l_json_obj_ret));
-    json_object_put(l_json_obj_ret);
     DAP_DELETE(l_tx);
-    return 0;
+    return STAKE_ORDER_CREATE_STAKER_OK;
 }
 
 int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) {
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 24cd70ee3e..f06ba28a1d 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -67,7 +67,19 @@ int dap_tx_cond_create_compose(int argc, char ** argv);
 int dap_cli_hold_compose(int a_argc, char **a_argv);
 int dap_cli_take_compose(int a_argc, char **a_argv);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
-int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv);
+typedef enum {
+    STAKE_ORDER_CREATE_STAKER_OK = 0,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -2,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -4,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -6,
+    STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -8,
+    STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -9,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -10,
+    STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -11,
+    STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -12
+} dap_cli_srv_stake_order_create_staker_error_t;
+int dap_cli_srv_stake_order_create_staker_compose(json_object* a_json_obj_ret, const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port);
+
 int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv);
 
 typedef enum {
-- 
GitLab


From bb94dc4d090fbfa3cadbc5978a576af90199c565 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Thu, 10 Apr 2025 18:30:20 +0700
Subject: [PATCH 44/53] [*] improve error handle

---
 modules/compose/dap_chain_tx_compose.c        | 362 ++++++++++--------
 .../compose/include/dap_chain_tx_compose.h    |  26 +-
 2 files changed, 216 insertions(+), 172 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index ed84d7b71b..7072f557ef 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -79,6 +79,33 @@ static dap_chain_net_id_t s_get_net_id(const char* name) {
 }
 
 
+int dap_json_compose_error_add(json_object* a_json_obj_reply, int a_code_error, const char *msg, ...)
+{
+    va_list args;
+    va_start(args, msg);
+    char *l_msg = dap_strdup_vprintf(msg, args);
+    va_end(args);
+
+    if (!a_json_obj_reply || !json_object_is_type(a_json_obj_reply, json_type_object)) {
+        return -1;
+    }
+
+    json_object *l_json_arr_errors = NULL;
+    if (!json_object_object_get_ex(a_json_obj_reply, "errors", &l_json_arr_errors)) {
+        l_json_arr_errors = json_object_new_array();
+        json_object_object_add(a_json_obj_reply, "errors", l_json_arr_errors);
+    }
+
+    json_object* l_obj_error = json_object_new_object();
+    json_object_object_add(l_obj_error, "code", json_object_new_int(a_code_error));
+    json_object_object_add(l_obj_error, "message", json_object_new_string(l_msg));
+    json_object_array_add(l_json_arr_errors, l_obj_error);
+
+    DAP_DEL_Z(l_msg);
+    return 0;
+}
+
+
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add) {
     json_object *items_array;
     if (!json_object_object_get_ex(json_tx, "items", &items_array)) {
@@ -2994,9 +3021,10 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
 
 
 
-int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
+json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
                         const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port)
 {
+    json_object* l_json_obj_ret = json_object_new_object();
     dap_hash_fast_t l_tx_hash = {};
     if (a_tx_hash_str) {
         dap_chain_hash_fast_from_str(a_tx_hash_str, &l_tx_hash);
@@ -3005,13 +3033,16 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char
         if (a_cert_str) {
             dap_cert_t *l_cert = dap_cert_find_by_name(a_cert_str);
             if (!l_cert) {
-                return DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND;
+                dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND, "Specified certificate not found");
+                return l_json_obj_ret;
             }
             if (!l_cert->enc_key->priv_key_data || l_cert->enc_key->priv_key_data_size == 0) {
-                return DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING;
+                dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING, "Private key missing in certificate");
+                return l_json_obj_ret;
             }
             if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, s_get_net_id(a_net_str))) {
-                return DAP_CLI_STAKE_INVALIDATE_WRONG_CERT;
+                dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_WRONG_CERT, "Wrong certificate");
+                return l_json_obj_ret;
             }
         }
         const char *l_addr_str = dap_chain_addr_to_str_static(&l_signing_addr);
@@ -3021,7 +3052,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char
                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str);
         json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
         if (!l_json_coins) {
-            return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR;
+            dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger");
+            return l_json_obj_ret;
         }
         
         int items_count = json_object_array_length(l_json_coins);
@@ -3033,7 +3065,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char
                 const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash"));
                 if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) {
                     json_object_put(l_json_coins);
-                    return DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH;
+                    dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format");
+                    return l_json_obj_ret;
                 }
                 found = true;
                 break;
@@ -3041,7 +3074,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char
         }
         json_object_put(l_json_coins);
         if (!found) {
-            return DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED;
+            dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED, "Specified certificate/pkey hash is not delegated");
+            return l_json_obj_ret;
         }
     }
 
@@ -3050,9 +3084,10 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, a_net_str);
-        json_object *l_json_response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
+    json_object *l_json_response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
     if (!l_json_response) {
-        return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR;
+        dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger");
+        return l_json_obj_ret;
     }
 
     json_object *l_json_items = json_object_array_get_idx(l_json_response, 0);
@@ -3075,7 +3110,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char
 
     if (!has_delegate_out) {
         json_object_put(l_json_response);
-        return DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT;
+        dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT, "No delegate output found in transaction");
+        return l_json_obj_ret;
     }
 
     json_object *l_json_spents = json_object_object_get(l_json_response, "Spent OUTs");
@@ -3087,7 +3123,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char
             if (spent_by_tx) {
                 if (dap_chain_hash_fast_from_str(spent_by_tx, &l_tx_hash)) {
                     json_object_put(l_json_response);
-                    return DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH;
+                    dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format");
+                    return l_json_obj_ret;
                 }
                 l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash);
                 snprintf(data, sizeof(data), 
@@ -3095,13 +3132,15 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char
                 json_object *l_json_prev_tx = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
                 if (!l_json_prev_tx) {
                     json_object_put(l_json_response);
-                    return DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND;
+                    dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND, "Previous transaction not found");
+                    return l_json_obj_ret;
                 }
                 json_object_put(l_json_prev_tx);
                 break; 
             }
         }
     }
+    json_object_put(l_json_response);
 
     if (a_tx_hash_str) {
         char data[512];
@@ -3109,8 +3148,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char
                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", a_net_str);
         json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
         if (!l_json_coins) {
-            json_object_put(l_json_response);
-            return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR;
+            dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger");
+            return l_json_obj_ret;
         }
 
         bool tx_exists = false;
@@ -3120,35 +3159,32 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char
             const char *tx_hash = json_object_get_string(json_object_object_get(tx_item, "tx_hash"));
             if (tx_hash && strcmp(tx_hash, l_tx_hash_str_tmp) == 0) {
                 json_object_put(l_json_coins);
-                json_object_put(l_json_response);
-                return DAP_CLI_STAKE_INVALIDATE_TX_EXISTS;
+                dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_TX_EXISTS, "Transaction already exists");
+                return l_json_obj_ret;
             }
         }
         json_object_put(l_json_coins);
     }
-    dap_chain_datum_tx_t *l_tx = NULL;
+
 
     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path,NULL);
     if (!l_wallet) {
-        json_object_put(l_json_response);
-        return DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND;
+        dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND, "Specified wallet not found");
+        return l_json_obj_ret;
     }
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
-    int l_ret = 0;
-    l_tx = dap_stake_tx_invalidate_compose(a_net_str, &l_tx_hash, a_fee, l_enc_key, a_url_str, a_port, &l_ret);
-    if (!l_tx) {
-        json_object_put(l_json_response);
-        return l_ret;
+    dap_chain_datum_tx_t *l_tx = dap_stake_tx_invalidate_compose(a_net_str, &l_tx_hash, a_fee, l_enc_key, a_url_str, a_port, l_json_obj_ret);
+    if (l_tx) {
+        dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+        DAP_DELETE(l_tx);
     }
-    dap_chain_net_tx_to_json(l_tx, a_json_obj_ret);
 
     dap_chain_wallet_close(l_wallet);
     dap_enc_key_delete(l_enc_key);
-    json_object_put(l_json_response);
-    return DAP_CLI_STAKE_INVALIDATE_OK;
+    return l_json_obj_ret;
 }
 
-dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, int *l_ret)
+dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, json_object *a_error_handler)
 {
     if(!a_net_str || !*a_net_str || !a_tx_hash || !a_key || !l_url_str || !*l_url_str || l_port == 0)
         return NULL;
@@ -3159,14 +3195,14 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     
     json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
     if (!response) {
-        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR;
+        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR, "Failed to get ledger info");
         return NULL;
     }
     json_object *l_items_array = json_object_array_get_idx(response, 0);
     l_items_array = json_object_object_get(l_items_array, "ITEMS");
     if (!l_items_array) {
         json_object_put(response);
-        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND;
+        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND, "Items not found in ledger response");
         return NULL;
     }
 
@@ -3175,7 +3211,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         const char *all_unspent = json_object_get_string(l_unspent_outs);
         if (all_unspent && strcmp(all_unspent, "yes") == 0) {
             json_object_put(response);
-            if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT;
+            if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT, "All outputs are already spent");
             return NULL;
         }
     }
@@ -3198,7 +3234,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             if (!l_tx_prev_hash) {
                 json_object_put(response);
                 DAP_DELETE(l_tx_out_cond);
-                if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND;
+                if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND, "Previous transaction hash not found");
                 return NULL;
             }
             l_prev_cond_idx = json_object_get_int(json_object_object_get(l_item, "Tx_out_prev_idx"));
@@ -3210,7 +3246,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             if (!response_cond) {
                 json_object_put(response);
                 DAP_DELETE(l_tx_out_cond);
-                if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR;
+                if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR, "Failed to get conditional transaction info");
                 return NULL;
             }
             json_object_put(response_cond);
@@ -3220,7 +3256,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (!l_tx_out_cond || !l_tx_prev_hash) {
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
-        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND;
+        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND, "Conditional transaction not found");
         return NULL;
     }
 
@@ -3237,7 +3273,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (!l_sig_item) {
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
-        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND;
+        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND, "Signature item not found");
         return NULL;
     }
 
@@ -3245,7 +3281,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (!l_sign_b64_str) {
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
-        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR;
+        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR, "Failed to decode signature");
         return NULL;
     }
 
@@ -3268,7 +3304,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
-        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER;
+        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER, "Wrong transaction owner");
         return NULL;
     }
     
@@ -3282,7 +3318,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
-            if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND;
+            if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND, "Token ticker not found");
             return NULL;
         }
     }
@@ -3293,7 +3329,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
-        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND;
+        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND, "Transaction outputs not found");
         return NULL;
     }
 
@@ -3314,7 +3350,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
-        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS;
+        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS, "Not enough funds to pay fees");
         return NULL;
     }
 
@@ -3333,7 +3369,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
-        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR;
+        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR, "Error adding input items");
         return NULL;
     }
 
@@ -3344,7 +3380,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
-        if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR;
+        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR, "Error adding output items");
         return NULL;
     }
     // add fee items
@@ -3355,7 +3391,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
-            if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR;
+            if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR, "Error adding network fee");
             return NULL;
         }
     }
@@ -3366,7 +3402,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
-            if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR;
+            if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR, "Error adding fee");
             return NULL;
         }
     }
@@ -3380,7 +3416,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
-            if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR;
+            if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR, "Error adding fee back");
             return NULL;
         }
     }
@@ -3526,13 +3562,14 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o
 
 
 
-int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
+json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
                                         const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, 
                                         const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path) {
+    json_object* l_json_obj_ret = json_object_new_object();
     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallets_path, NULL);
     if (!l_wallet) {
-        printf("Specified wallet not found\n");
-        return STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND;
+        dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND, "Specified wallet not found");
+        return l_json_obj_ret;
     }
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
     dap_chain_wallet_close(l_wallet);
@@ -3542,9 +3579,9 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char*
     if (a_value_str) {
         l_value = dap_chain_balance_scan(a_value_str);
         if (IS_ZERO_256(l_value)) {
-            printf("Unrecognized number in '-value' param\n");
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-value' param");
             dap_enc_key_delete(l_enc_key);
-            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE;
+            return l_json_obj_ret;
         }
     }
     dap_pkey_t *l_pkey = NULL;
@@ -3552,39 +3589,39 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char*
     if (a_cert_str) {
         dap_cert_t *l_signing_cert = dap_cert_find_by_name(a_cert_str);
         if (!l_signing_cert) {
-            printf("Specified certificate not found\n");
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND, "Specified certificate not found");
             dap_enc_key_delete(l_enc_key);
-            return STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND;
+            return l_json_obj_ret;
         }
         if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(a_net_str))) {
-            printf("Specified certificate is wrong\n");
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG, "Specified certificate is wrong");
             dap_enc_key_delete(l_enc_key);
-            return STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG;
+            return l_json_obj_ret;
         }
         l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key);
     }  else if (a_pkey_full_str) {
         dap_sign_type_t l_type = dap_sign_type_from_str(a_sign_type_str);
         if (l_type.type == SIG_TYPE_NULL) {
-            printf("Wrong sign type\n");
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE, "Wrong sign type");
             dap_enc_key_delete(l_enc_key);
-            return STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE;
+            return l_json_obj_ret;
         }
         l_pkey = dap_pkey_get_from_str(a_pkey_full_str);
         if (!l_pkey) {
-            printf("Invalid pkey string format, can't get pkey_full\n");
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey string format, can't get pkey_full");
             dap_enc_key_delete(l_enc_key);
-            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY;
+            return l_json_obj_ret;
         }
         if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) {
-            printf("pkey and sign types is different\n");
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "pkey and sign types is different");
             dap_enc_key_delete(l_enc_key);
-            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY;
+            return l_json_obj_ret;
         }
         dap_chain_hash_fast_t l_hash_public_key = {0};
         if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) {
-            printf("Invalid pkey hash format\n");
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey hash format");
             dap_enc_key_delete(l_enc_key);
-            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY;
+            return l_json_obj_ret;
         }
         dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(a_net_str));
     }
@@ -3592,9 +3629,9 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char*
     dap_chain_node_addr_t l_node_addr = g_node_addr;
     if (a_node_addr_str) {
         if (dap_chain_node_addr_from_str(&l_node_addr, a_node_addr_str)) {
-            printf("Unrecognized node addr %s\n", a_node_addr_str);
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Unrecognized node addr %s", a_node_addr_str);
             dap_enc_key_delete(l_enc_key);
-            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR;
+            return l_json_obj_ret;
         }
     }
     if (a_order_hash_str) {
@@ -3603,23 +3640,23 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char*
         int l_prev_tx_count = 0;
         dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(a_net_str, a_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, a_url_str, a_port);
         if (!l_order) {
-            printf("Error: Failed to get order from remote node\n");
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND, "Error: Failed to get order from remote node");
             dap_enc_key_delete(l_enc_key);
-            return STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND;
+            return l_json_obj_ret;
         }
         l_sovereign_tax = l_tax;
 
         if (l_order->direction == SERV_DIR_BUY) { // Staker order
             if (!a_cert_str) {
-                printf("Command 'delegate' requires parameter -cert with this order type\n");
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED, "Command 'delegate' requires parameter -cert with this order type");
                 dap_enc_key_delete(l_enc_key);
-                return STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED;
+                return l_json_obj_ret;
             }
             if (l_order->ext_size != 0) {
-                printf("Specified order has invalid size\n");
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Specified order has invalid size");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE;
+                return l_json_obj_ret;
             }
 
             dap_chain_tx_out_cond_t *l_cond_tx = NULL;
@@ -3630,14 +3667,14 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char*
             
             json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
             if (!response) {
-                printf("Error: Failed to get response from remote node\n");
-                return STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE;
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE, "Error: Failed to get response from remote node");
+                return l_json_obj_ret;
             }
             
             json_object *items = json_object_object_get(response, "ITEMS");
             if (!items) {
-                printf("Error: No items found in response\n");
-                return STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS;
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS, "Error: No items found in response");
+                return l_json_obj_ret;
             }
             int items_count = json_object_array_length(items);
             for (int i = 0; i < items_count; i++) {
@@ -3654,8 +3691,8 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char*
                         l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
                         l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr")));
                         if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) {
-                            printf("Error: Failed to parse signer node address\n");
-                            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR;
+                            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR, "Error: Failed to parse signer node address");
+                            return l_json_obj_ret;
                         }
                         l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
                         l_prev_tx_count++;
@@ -3666,60 +3703,60 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char*
                 }
             }
             if (!l_cond_tx) {
-                printf("Error: No transaction output condition found\n");
-                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR;
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Error: No transaction output condition found");
+                return l_json_obj_ret;
             }
 
             json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
             const char *spent_outs_value = json_object_get_string(spent_outs);
             if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
-                printf("Error: Transaction output item already used\n");
-                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE;
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Error: Transaction output item already used");
+                return l_json_obj_ret;
             }
 
             char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
             dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(a_net_str));
             const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker"));
             if (!l_token_ticker) {
-                printf("Error: Token ticker not found in response\n");
-                return STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER;
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER, "Error: Token ticker not found in response");
+                return l_json_obj_ret;
             }
             json_object_put(response);
             if (dap_strcmp(l_token_ticker, l_delegated_ticker)) {
-                printf("Requested conditional transaction have another ticker (not %s)\n", l_delegated_ticker);
-                return STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER;
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER, "Requested conditional transaction have another ticker (not %s)", l_delegated_ticker);
+                return l_json_obj_ret;
             }
             if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) {
-                printf("The order's conditional transaction has invalid format\n");
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT, "The order's conditional transaction has invalid format");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT;
+                return l_json_obj_ret;
             }
             if (compare256(l_cond_tx->header.value, l_order->price)) {
-                printf("The order's conditional transaction has different value\n");
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE, "The order's conditional transaction has different value");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE;
+                return l_json_obj_ret;
             }
             if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) ||
                     l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) {
-                printf("The order's conditional transaction gas not blank address or key\n");
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR, "The order's conditional transaction gas not blank address or key");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR;
+                return l_json_obj_ret;
             }
             l_value = l_order->price;
         } else {
             if (!a_value_str) {
-                printf("Command 'delegate' requires parameter -value with this order type\n");
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED, "Command 'delegate' requires parameter -value with this order type");
                 dap_enc_key_delete(l_enc_key);
-                return STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED;
+                return l_json_obj_ret;
             }
             if (a_sovereign_addr_str) {
                 dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(a_sovereign_addr_str);
                 if (!l_spec_addr) {
-                    printf("Specified address is ivalid\n");
-                    return STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR;
+                    dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR, "Specified address is invalid");
+                    return l_json_obj_ret;
                 }
                 l_sovereign_addr = *l_spec_addr;
                 DAP_DELETE(l_spec_addr);
@@ -3729,58 +3766,58 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char*
             if (a_order_hash_str && compare256(l_value, l_order->price) == -1) {
                 const char *l_coin_min_str, *l_value_min_str =
                     dap_uint256_to_char(l_order->price, &l_coin_min_str);
-                printf("Number in '-value' param %s is lower than order minimum allowed value %s(%s)\n",
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW, "Number in '-value' param %s is lower than order minimum allowed value %s(%s)",
                                                   a_value_str, l_coin_min_str, l_value_min_str);
                 dap_enc_key_delete(l_enc_key);
-                return STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW;
+                return l_json_obj_ret;
             }
             if (a_order_hash_str && compare256(l_value, l_value_max) == 1) {
                 const char *l_coin_max_str, *l_value_max_str =
                     dap_uint256_to_char(l_value_max, &l_coin_max_str);
-                printf("Number in '-value' param %s is higher than order minimum allowed value %s(%s)\n",
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH, "Number in '-value' param %s is higher than order minimum allowed value %s(%s)",
                                                   a_value_str, l_coin_max_str, l_value_max_str);
                 dap_enc_key_delete(l_enc_key);
-                return STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH;
+                return l_json_obj_ret;
             }
             size_t l_sign_size = 0;
             dap_sign_t *l_sign = dap_get_remote_srv_order_sign(a_net_str, a_order_hash_str, a_url_str, a_port);
             if (!l_sign) {
-                printf("Specified order is unsigned\n");
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER, "Specified order is unsigned");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER;
+                return l_json_obj_ret;
             }
             dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, s_get_net_id(a_net_str));
             l_pkey = dap_pkey_get_from_sign(l_sign);
             char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX];
             dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, s_get_native_ticker(a_net_str));
             if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) {
-                printf("Specified order is invalid\n");
+                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER, "Specified order is invalid");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER;
+                return l_json_obj_ret;
             }
             l_node_addr = l_order->node_addr;
         }
         DAP_DELETE(l_order);
         if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 ||
                 compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) {
-            printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n");
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%");
             dap_enc_key_delete(l_enc_key);
-            return STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX;
+            return l_json_obj_ret;
         }
         DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
     }
     if (!l_pkey) {
-        printf("pkey not defined\n");
+        dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED, "pkey not defined");
         dap_enc_key_delete(l_enc_key);
-        return STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED;
+        return l_json_obj_ret;
     }
 
     // TODO: need to make sure that the key and node are required verification 
     // int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr);
     // if (l_check_result) {
-    //     printf("Key and node verification error\n");
+    //     dap_json_compose_error_add(a_json_obj_ret, l_check_result, "Key and node verification error");
     //     dap_enc_key_delete(l_enc_key);
     //     return l_check_result;
     // }
@@ -3789,44 +3826,42 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char*
     uint256_t l_allowed_min = s_get_key_delegating_min_value(a_net_str, a_url_str, a_port);
     if (compare256(l_value, l_allowed_min) == -1) {
         const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str);
-        printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n",
+        dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN, "Number in '-value' param %s is lower than minimum allowed value %s(%s)",
                                           a_value_str, l_coin_min_str, l_value_min_str);
         dap_enc_key_delete(l_enc_key);
-        return STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN;
+        return l_json_obj_ret;
     }
 
     uint256_t l_fee = dap_chain_balance_scan(a_fee_str);
     if (IS_ZERO_256(l_fee)) {
-        printf("Unrecognized number in '-fee' param\n");
+        dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-fee' param");
         dap_enc_key_delete(l_enc_key);
-        return STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE;
+        return l_json_obj_ret;
     }
-    int l_ret = 0;
     dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(a_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr,
-                                                   a_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, a_url_str, a_port, &l_ret);
+                                                   a_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, a_url_str, a_port, l_json_obj_ret);
     
     dap_enc_key_delete(l_enc_key);
     DAP_DELETE(l_pkey);
 
-    if (l_ret) {
-        return l_ret;
+    if (l_tx) {
+        dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+        DAP_DELETE(l_tx);
     }
-    dap_chain_net_tx_to_json(l_tx, a_json_obj_ret);
-    DAP_DELETE(l_tx);
 
-    return STAKE_DELEGATE_COMPOSE_OK;
+    return l_json_obj_ret;
 
 }
 
-
 dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
-                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, int *l_ret)
+                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, json_object *l_error_handle)
 {
     if  (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) {
-        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS;
+        if (l_error_handle)
+            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS, "Invalid parameters for transaction creation");
         return NULL;
     }
     const char *l_native_ticker = s_get_native_ticker(a_net_str);
@@ -3844,16 +3879,17 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
 
     dap_list_t *l_list_fee_out = NULL;
 
-
     json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
     if (!l_outs_native) {
-        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE;
+        if (l_error_handle)
+            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee");
         return NULL;
     }
 
     json_object *l_outs_delegated = dap_get_remote_tx_outs(l_delegated_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
     if (!l_outs_delegated) {
-        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE;
+        if (l_error_handle)
+            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value");
         return NULL;
     }
 
@@ -3866,7 +3902,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     if (!l_list_fee_out) {
         json_object_put(l_outs_native);
         json_object_put(l_outs_delegated);
-        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE;
+        if (l_error_handle)
+            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee");
         return NULL;
     }
 
@@ -3880,14 +3917,16 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
         if (!l_list_used_out) {
             json_object_put(l_outs_native);
             json_object_put(l_outs_delegated);
-            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE;
+            if (l_error_handle)
+                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value");
             return NULL;
         }
         // add 'in' items to pay for delegate
         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
         dap_list_free_full(l_list_used_out, NULL);
         if (!EQUAL_256(l_value_to_items, l_value_transfer)) {
-            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR;
+            if (l_error_handle)
+                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input");
             goto tx_fail;
         }
     } else {
@@ -3897,7 +3936,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
         dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
         // add 'in' item to buy from conditional transaction
         if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_out_num, -1)) {
-            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR;
+            if (l_error_handle)
+                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input");
             goto tx_fail;
         }
     }
@@ -3905,7 +3945,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
     dap_list_free_full(l_list_fee_out, NULL);
     if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
-        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR;
+        if (l_error_handle)
+            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input");
         goto tx_fail;
     }
 
@@ -3915,7 +3956,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
                                                                                           a_sovereign_addr, a_sovereign_tax, a_pkey);
 
     if (!l_tx_out) {
-        if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR;
+        if (l_error_handle)
+            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR, "Error creating conditional transaction output");
         goto tx_fail;
     }
     dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
@@ -3926,7 +3968,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
         SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back);
         if (!IS_ZERO_256(l_value_back)) {
             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) {
-                if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR;
+                if (l_error_handle)
+                    dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR, "Error creating transaction output");
                 goto tx_fail;
             }
         }
@@ -3935,13 +3978,15 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     // add fee items
     if (l_net_fee_used) {
         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
-            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR;
+            if (l_error_handle)
+                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR, "Error with network fee");
             goto tx_fail;
         }
     }
     if (!IS_ZERO_256(a_fee)) {
         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
-            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR;
+            if (l_error_handle)
+                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR, "Error with validator fee");
             goto tx_fail;
         }
     }
@@ -3950,7 +3995,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back);
     if (!IS_ZERO_256(l_fee_back)) {
         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) {
-            if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR;
+            if (l_error_handle)
+                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR, "Error with fee back");
             goto tx_fail;
         }
     }
@@ -3965,38 +4011,38 @@ tx_fail:
 static dap_chain_datum_tx_t *dap_order_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                 uint256_t a_sovereign_tax, dap_chain_addr_t *a_sovereign_addr,
-                                                const char *l_url_str, int l_port, int *l_ret)
+                                                const char *l_url_str, int l_port, json_object *l_error_handle)
 {
     dap_chain_node_addr_t l_node_addr = {};
     return dap_stake_tx_create_compose(a_net_str, a_key, a_value, a_fee,
                              (dap_chain_addr_t *)&c_dap_chain_addr_blank, &l_node_addr,
-                             a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, l_ret);
+                             a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, l_error_handle);
 }
 
 
-
-int dap_cli_srv_stake_order_create_staker_compose(json_object* a_json_obj_ret, const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) {
+json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) {
+    json_object* l_json_obj_ret = json_object_new_object();
     uint256_t l_value = dap_chain_balance_scan(l_value_str);
-    if (IS_ZERO_256(l_value)) { 
-        printf("Format -value <256 bit integer>\n");
-        return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE;
+    if (IS_ZERO_256(l_value)) {
+        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE, "Format -value <256 bit integer>");
+        return l_json_obj_ret;
     }
     uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
     if (IS_ZERO_256(l_fee)) {
-        printf("Format -fee <256 bit integer>\n");
-        return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE;
+        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE, "Format -fee <256 bit integer>");
+        return l_json_obj_ret;
     }
     uint256_t l_tax = dap_chain_coins_to_balance(l_tax_str);
     if (compare256(l_tax, dap_chain_coins_to_balance("100.0")) == 1 ||
             compare256(l_tax, GET_256_FROM_64(100)) == -1) {
-        printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n");
-        return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX;
+        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%");
+        return l_json_obj_ret;
     }
 
     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
     if (!l_wallet) {
-        printf("Specified wallet not found\n");
-        return STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND;
+        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND, "Specified wallet not found");
+        return l_json_obj_ret;
     }
 
     const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet);
@@ -4004,35 +4050,33 @@ int dap_cli_srv_stake_order_create_staker_compose(json_object* a_json_obj_ret, c
     dap_chain_wallet_close(l_wallet);
 
     if (!l_enc_key) {
-        printf("Failed to retrieve encryption key\n");
-        return STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND;
+        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND, "Failed to retrieve encryption key");
+        return l_json_obj_ret;
     }
 
     dap_chain_addr_t l_addr = {};
     if (l_addr_str) {
         dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str);
         if (!l_spec_addr) {
-            printf("Specified address is invalid\n");
+            dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR, "Specified address is invalid");
             DAP_DELETE(l_enc_key);
-            return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR;
+            return NULL;
         }
         l_addr = *l_spec_addr;
         DAP_DELETE(l_spec_addr);
     } else
         dap_chain_addr_fill_from_key(&l_addr, l_enc_key, s_get_net_id(l_net_str));
     DIV_256(l_tax, GET_256_FROM_64(100), &l_tax);
-    int l_ret = 0;
-    dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, &l_addr, l_url_str, l_port, &l_ret);
+    dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, 
+                                                            &l_addr, l_url_str, l_port, l_json_obj_ret);
     DAP_DEL_Z(l_enc_key);
 
-    if (l_ret) {
-        return l_ret;
+    if (l_tx) {
+        dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+        DAP_DELETE(l_tx);
     }
 
-    dap_chain_net_tx_to_json(l_tx, a_json_obj_ret);
-
-    DAP_DELETE(l_tx);
-    return STAKE_ORDER_CREATE_STAKER_OK;
+    return l_json_obj_ret;
 }
 
 int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) {
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index f06ba28a1d..92d8bc19c1 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -69,16 +69,16 @@ int dap_cli_take_compose(int a_argc, char **a_argv);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
 typedef enum {
     STAKE_ORDER_CREATE_STAKER_OK = 0,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -2,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -4,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -6,
-    STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -8,
-    STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -9,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -10,
-    STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -11,
-    STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -12
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -1,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -2,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -3,
+    STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -4,
+    STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -5,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -6,
+    STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -7,
+    STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -8
 } dap_cli_srv_stake_order_create_staker_error_t;
-int dap_cli_srv_stake_order_create_staker_compose(json_object* a_json_obj_ret, const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port);
+json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port);
 
 int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv);
 
@@ -121,7 +121,7 @@ typedef enum {
     DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -35,
     DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -36
 } stake_delegate_error_t;
-int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
+json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
                                         const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, 
                                         const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path);
 typedef enum {
@@ -155,9 +155,9 @@ typedef enum {
     DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27,
     DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28
 } dap_cli_stake_invalidate_error_t;
-int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
+json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
                         const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port);
-dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, int *l_ret);
+dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, json_object *a_error_handler);
 
 json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port);
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
@@ -200,7 +200,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
-                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, int *l_ret);
+                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, json_object *l_error_handle);
 
 dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
                                      dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port);
-- 
GitLab


From 2a042795aa8e11a58d1d7bda91a99a0b6284fcec Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Fri, 11 Apr 2025 14:53:23 +0700
Subject: [PATCH 45/53] [*] refactor error

---
 modules/compose/dap_chain_tx_compose.c        | 5213 +++++++++--------
 .../compose/include/dap_chain_tx_compose.h    |   46 +-
 2 files changed, 2651 insertions(+), 2608 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 7072f557ef..125c7259b3 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -41,6 +41,37 @@
 
 #include <json-c/json.h>
 
+static compose_config_t* s_compose_config_init(const char *a_net_name, const char *a_url_str,
+                                 uint16_t a_port) {
+    if (!a_net_name || !a_url_str || a_port == 0) {
+        return NULL;
+    }
+    compose_config_t *l_config = DAP_NEW_Z(compose_config_t);
+    if (!l_config) {
+        return NULL;
+    }
+    l_config->net_name = a_net_name;
+    l_config->url_str = a_url_str ? a_url_str : dap_compose_get_net_url(a_net_name);
+    l_config->port = a_port ? a_port : dap_compose_get_net_port(a_net_name);
+    l_config->response_handler = json_object_new_object();
+    return l_config;
+}
+
+static json_object* s_compose_config_return_response_handler(compose_config_t *a_config) {
+    if (!a_config || !a_config->response_handler) {
+        return NULL;
+    }
+    json_object* l_response_handler = a_config->response_handler;
+    DAP_DEL_Z(a_config);
+    return l_response_handler;
+}
+
+static int s_compose_config_deinit(compose_config_t *a_config) {
+    json_object_put(a_config->response_handler);
+    DAP_DEL_Z(a_config);
+    return 0;
+}
+
 const char* dap_compose_get_net_url(const char* name) {
     for (int i = 0; i < NET_COUNT; i++) {
         if (strcmp(netinfo[i].name, name) == 0) {
@@ -278,19 +309,20 @@ static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_ob
     return ret;
 }
 
-static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) {
+
+static json_object* s_request_command_to_rpc(const char *request, compose_config_t *a_config) {
     json_object * l_response = NULL;
     size_t l_response_size = 0;
     struct cmd_request* l_cmd_request = s_cmd_request_init();
 
     if (!l_cmd_request) {
-        printf("Error: Failed to initialize command request\n");
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_REQUEST_INIT_FAILED, "Failed to initialize command request");
         return NULL;
     }
 
     dap_client_http_request(dap_worker_get_auto(),
-                                a_url_str ? a_url_str : dap_compose_get_net_url(a_net_name),
-                                a_port ? a_port : dap_compose_get_net_port(a_net_name),
+                                a_config->url_str,
+                                a_config->port,
                                 "POST", "application/json",
                                 NULL, request, strlen(request), NULL,
                                 s_cmd_response_handler, s_cmd_error_handler,
@@ -300,25 +332,24 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a
 
     if (!l_ret){
         if (s_cmd_request_get_response(l_cmd_request, &l_response, &l_response_size)) {
-            printf( "Response error code: %d", l_cmd_request->error_code);
+            dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_REQUEST_FAILED, "Response error code: %d", l_cmd_request->error_code);
         }
     } else {
-        printf("Error: Command list wait failed with code %d\n", l_ret);
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_REQUEST_TIMEOUT, "Request timed out");
     }
-
     s_cmd_request_free(l_cmd_request);
     return l_response;
 }
 
-static json_object* s_request_command_parse(json_object *l_response) {
+static json_object* s_request_command_parse(json_object *l_response, compose_config_t *a_config) {
     if (!l_response) {
-        printf("Error: Response is NULL\n");
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is NULL");
         return NULL;
     }
 
     json_object * l_result = NULL;
     if (!json_object_object_get_ex(l_response, "result", &l_result)) {
-        printf("Error: Failed to get 'result' from response\n");
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESULT_NOT_FOUND, "Failed to get 'result' from response");
         return NULL;
     }
 
@@ -332,7 +363,7 @@ static json_object* s_request_command_parse(json_object *l_response) {
                 json_object *error_code = NULL, *error_message = NULL;
                 if (json_object_object_get_ex(error_obj, "code", &error_code) &&
                     json_object_object_get_ex(error_obj, "message", &error_message)) {
-                    printf("Error %d: %s\n", json_object_get_int(error_code), json_object_get_string(error_message));
+                    dap_json_compose_error_add(a_config->response_handler, json_object_get_int(error_code), json_object_get_string(error_message));
                 }
             }
             l_result = NULL;
@@ -342,23 +373,26 @@ static json_object* s_request_command_parse(json_object *l_response) {
     return l_result;
 }
 
-json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) {
-    json_object * l_response = s_request_command_to_rpc(request, a_net_name, a_url_str, a_port);
+json_object* dap_request_command_to_rpc(const char *request, compose_config_t *a_config) {
+    json_object * l_response = s_request_command_to_rpc(request, a_config);
     if (!l_response) {
-        printf("Error: Failed to get response from RPC request\n");
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Failed to get response from RPC request");
         return NULL;
     }
-
-    json_object * l_result = s_request_command_parse(l_response);
+    json_object * l_result = s_request_command_parse(l_response, a_config);
     json_object_put(l_response);
+    if (!l_result) {
+        json_object_put(l_result);
+        return NULL;
+    }
     return l_result;
 }
 
 
-bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, const char * a_url_str, uint16_t a_port) {
+bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, compose_config_t *a_config) {
     char data[512];
-    snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name);
-    json_object *l_json_get_fee = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port);
+    snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", a_config->net_name);
+    json_object * l_json_get_fee = dap_request_command_to_rpc(data, a_config);
     if (!l_json_get_fee) {
         return false;
     }
@@ -403,557 +437,557 @@ bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net
     return true;
 }
 
-bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name,
-                                         json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port) {
-    char data[512];
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
-            dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name);
-    json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port);
-    if (!l_json_outs) {
-        return false;
-    }
+// bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name,
+//                                          json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port) {
+//     char data[512];
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
+//             dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name);
+//     json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port);
+//     if (!l_json_outs) {
+//         return false;
+//     }
 
-    if (!json_object_is_type(l_json_outs, json_type_array)) {
-        json_object_put(l_json_outs);
-        return false;
-    }
+//     if (!json_object_is_type(l_json_outs, json_type_array)) {
+//         json_object_put(l_json_outs);
+//         return false;
+//     }
 
-    if (json_object_array_length(l_json_outs) == 0) {
-        json_object_put(l_json_outs);
-        return false;
-    }
+//     if (json_object_array_length(l_json_outs) == 0) {
+//         json_object_put(l_json_outs);
+//         return false;
+//     }
 
-    json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0);
-    if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) {
-        json_object_put(l_json_outs);
-        return false;
-    }
+//     json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0);
+//     if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) {
+//         json_object_put(l_json_outs);
+//         return false;
+//     }
 
-    json_object *l_first_item = json_object_array_get_idx(l_first_array, 0);
-    if (!l_first_item) {
-        json_object_put(l_json_outs);
-        return false;
-    }
+//     json_object *l_first_item = json_object_array_get_idx(l_first_array, 0);
+//     if (!l_first_item) {
+//         json_object_put(l_json_outs);
+//         return false;
+//     }
 
-    if (!json_object_object_get_ex(l_first_item, "outs", l_outs) ||
-        !json_object_is_type(*l_outs, json_type_array)) {
-        json_object_put(l_json_outs);
-        return false;
-    }
+//     if (!json_object_object_get_ex(l_first_item, "outs", l_outs) ||
+//         !json_object_is_type(*l_outs, json_type_array)) {
+//         json_object_put(l_json_outs);
+//         return false;
+//     }
 
-    *l_outputs_count = json_object_array_length(*l_outs);
-    json_object_get(*l_outs);
-    json_object_put(l_json_outs);
-    return true;
-}
+//     *l_outputs_count = json_object_array_length(*l_outs);
+//     json_object_get(*l_outs);
+//     json_object_put(l_json_outs);
+//     return true;
+// }
 
 
-int dap_tx_create_xchange_compose(int argc, char ** argv) {
-    int arg_index = 1;
-    const char *l_net_name = NULL;
-    const char *l_token_sell = NULL;
-    const char *l_token_buy = NULL;
-    const char *l_wallet_name = NULL;
-    const char *l_value_str = NULL;
-    const char *l_rate_str = NULL;
-    const char *l_fee_str = NULL;
-    const char *l_url_str = NULL;
-    const char *l_port_str = NULL;
-    uint16_t l_port = 0;
-
-    const char *l_wallet_path = NULL;
-    dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
-    if (!l_wallet_path) {
-        l_wallet_path =
-        #ifdef DAP_OS_WINDOWS
-                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-        #elif defined DAP_OS_MAC
-                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-        #elif defined DAP_OS_UNIX
-                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-        #endif
-    }
+// int dap_tx_create_xchange_compose(int argc, char ** argv) {
+//     int arg_index = 1;
+//     const char *l_net_name = NULL;
+//     const char *l_token_sell = NULL;
+//     const char *l_token_buy = NULL;
+//     const char *l_wallet_name = NULL;
+//     const char *l_value_str = NULL;
+//     const char *l_rate_str = NULL;
+//     const char *l_fee_str = NULL;
+//     const char *l_url_str = NULL;
+//     const char *l_port_str = NULL;
+//     uint16_t l_port = 0;
+
+//     const char *l_wallet_path = NULL;
+//     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
+//     if (!l_wallet_path) {
+//         l_wallet_path =
+//         #ifdef DAP_OS_WINDOWS
+//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+//         #elif defined DAP_OS_MAC
+//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+//         #elif defined DAP_OS_UNIX
+//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+//         #endif
+//     }
 
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_sell", &l_token_sell);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_buy", &l_token_buy);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-rate", &l_rate_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str);
-
-    if (!l_net_name) {
-        printf("xchange_create requires parameter '-net'");
-        return -1;
-    }
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_sell", &l_token_sell);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_buy", &l_token_buy);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-rate", &l_rate_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str);
 
-    if (!l_url_str) {
-        l_url_str = dap_compose_get_net_url(l_net_name);
-    }
+//     if (!l_net_name) {
+//         printf("xchange_create requires parameter '-net'");
+//         return -1;
+//     }
 
-    if (!l_port_str) {
-        l_port = dap_compose_get_net_port(l_net_name);
-    } else {
-        l_port = atoi(l_port_str);
-    }
+//     if (!l_url_str) {
+//         l_url_str = dap_compose_get_net_url(l_net_name);
+//     }
 
-    if (!l_token_buy) {
-        printf("xchange_create requires parameter '-token_buy'");
-        return -1;
-    }
+//     if (!l_port_str) {
+//         l_port = dap_compose_get_net_port(l_net_name);
+//     } else {
+//         l_port = atoi(l_port_str);
+//     }
 
-    if (!l_token_sell) {
-        printf("xchange_create requires parameter '-token_sell'");
-        return -1;
-    }
+//     if (!l_token_buy) {
+//         printf("xchange_create requires parameter '-token_buy'");
+//         return -1;
+//     }
 
-    if (!l_wallet_name) {
-        printf("xchange_create requires parameter '-w'");
-        return -1;
-    }
+//     if (!l_token_sell) {
+//         printf("xchange_create requires parameter '-token_sell'");
+//         return -1;
+//     }
 
-    if (!l_value_str) {
-        printf("xchange_create requires parameter '-value'");
-        return -1;
-    }
+//     if (!l_wallet_name) {
+//         printf("xchange_create requires parameter '-w'");
+//         return -1;
+//     }
 
-    if (!l_rate_str) {
-        printf("xchange_create requires parameter '-rate'");
-        return -1;
-    }
+//     if (!l_value_str) {
+//         printf("xchange_create requires parameter '-value'");
+//         return -1;
+//     }
 
-    if (!l_fee_str) {
-        printf("xchange_create requires parameter '-fee'");
-        return -1;
-    }
+//     if (!l_rate_str) {
+//         printf("xchange_create requires parameter '-rate'");
+//         return -1;
+//     }
 
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL);
-    if(!l_wallet) {
-        printf("wallet %s does not exist", l_wallet_name);
-        return -1;
-    }
+//     if (!l_fee_str) {
+//         printf("xchange_create requires parameter '-fee'");
+//         return -1;
+//     }
 
+//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL);
+//     if(!l_wallet) {
+//         printf("wallet %s does not exist", l_wallet_name);
+//         return -1;
+//     }
 
-    uint256_t l_value = dap_chain_balance_scan(l_value_str);
-    uint256_t l_rate = dap_chain_balance_scan(l_rate_str);
-    uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
-    if (IS_ZERO_256(l_value) || IS_ZERO_256(l_rate) || IS_ZERO_256(l_fee)) {
-        printf("Invalid parameter value, rate or fee is 0, use required format 1.0e+18 ot in datoshi");
-        return -1;
-    }
 
-    dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_net_name, l_token_buy,
-                                     l_token_sell, l_value, l_rate, l_fee, l_wallet, l_url_str, l_port);
-    json_object *l_ret = json_object_new_object();
-    dap_chain_net_tx_to_json(l_tx, l_ret);
-    printf("%s", json_object_to_json_string(l_ret));
-    json_object_put(l_ret);
-    dap_chain_datum_tx_delete(l_tx);
-    return 0;
-}
+//     uint256_t l_value = dap_chain_balance_scan(l_value_str);
+//     uint256_t l_rate = dap_chain_balance_scan(l_rate_str);
+//     uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+//     if (IS_ZERO_256(l_value) || IS_ZERO_256(l_rate) || IS_ZERO_256(l_fee)) {
+//         printf("Invalid parameter value, rate or fee is 0, use required format 1.0e+18 ot in datoshi");
+//         return -1;
+//     }
+
+//     dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_net_name, l_token_buy,
+//                                      l_token_sell, l_value, l_rate, l_fee, l_wallet, l_url_str, l_port);
+//     json_object *l_ret = json_object_new_object();
+//     dap_chain_net_tx_to_json(l_tx, l_ret);
+//     printf("%s", json_object_to_json_string(l_ret));
+//     json_object_put(l_ret);
+//     dap_chain_datum_tx_delete(l_tx);
+//     return 0;
+// }
 
 
 
-int dap_tx_create_compose(int argc, char ** argv) {
-    int arg_index = 1;
-    const char *addr_base58_to = NULL;
-    const char *str_tmp = NULL;
-    const char * l_from_wallet_name = NULL;
-    const char * l_wallet_fee_name = NULL;
-    const char * l_token_ticker = NULL;
-    const char * l_net_name = NULL;
-    const char * l_chain_name = NULL;
-    const char * l_url_str = NULL;
-    uint16_t l_port = 0;
-
-    const char * l_hash_out_type = NULL;
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type);
-    if(!l_hash_out_type)
-        l_hash_out_type = "hex";
-    if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) {
-        printf("Invalid parameter -H, valid values: -H <hex | base58>");
-        return -1;
-    }
+// int dap_tx_create_compose(int argc, char ** argv) {
+//     int arg_index = 1;
+//     const char *addr_base58_to = NULL;
+//     const char *str_tmp = NULL;
+//     const char * l_from_wallet_name = NULL;
+//     const char * l_wallet_fee_name = NULL;
+//     const char * l_token_ticker = NULL;
+//     const char * l_net_name = NULL;
+//     const char * l_chain_name = NULL;
+//     const char * l_url_str = NULL;
+//     uint16_t l_port = 0;
+
+//     const char * l_hash_out_type = NULL;
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type);
+//     if(!l_hash_out_type)
+//         l_hash_out_type = "hex";
+//     if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) {
+//         printf("Invalid parameter -H, valid values: -H <hex | base58>");
+//         return -1;
+//     }
 
-    const char *l_wallet_path = NULL;
-    dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
-    if (!l_wallet_path) {
-        l_wallet_path =
-        #ifdef DAP_OS_WINDOWS
-                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-        #elif defined DAP_OS_MAC
-                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-        #elif defined DAP_OS_UNIX
-                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-        #endif
-    }  
-
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
-    if (!l_net_name) {
-        printf("tx_create requires parameter '-net'");
-        return -1;
-    }
+//     const char *l_wallet_path = NULL;
+//     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
+//     if (!l_wallet_path) {
+//         l_wallet_path =
+//         #ifdef DAP_OS_WINDOWS
+//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+//         #elif defined DAP_OS_MAC
+//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+//         #elif defined DAP_OS_UNIX
+//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+//         #endif
+//     }  
 
-    if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str)) {
-        l_url_str = dap_compose_get_net_url(l_net_name);
-    }
-    const char *l_port_str = NULL;
-    if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str)) {
-        l_port = dap_compose_get_net_port(l_net_name);
-    } else {
-        l_port = atoi(l_port_str);
-    }
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
+//     if (!l_net_name) {
+//         printf("tx_create requires parameter '-net'");
+//         return -1;
+//     }
 
-    uint256_t *l_value = NULL;
-    uint256_t l_value_fee = {};
-    dap_chain_addr_t **l_addr_to = NULL;
-    size_t l_addr_el_count = 0;
-    size_t l_value_el_count = 0;
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-wallet_fee", &l_wallet_fee_name);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name);
+//     if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str)) {
+//         l_url_str = dap_compose_get_net_url(l_net_name);
+//     }
+//     const char *l_port_str = NULL;
+//     if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str)) {
+//         l_port = dap_compose_get_net_port(l_net_name);
+//     } else {
+//         l_port = atoi(l_port_str);
+//     }
 
-    // Validator's fee
-    if (dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) {
-        if (!str_tmp) {
-            printf("tx_create requires parameter '-fee'");
-            return -1;
-        }
-        l_value_fee = dap_chain_balance_scan(str_tmp);
-    }
-    if (IS_ZERO_256(l_value_fee) && (str_tmp && strcmp(str_tmp, "0"))) {
-        printf("tx_create requires parameter '-fee' to be valid uint256");
-        return -2;
-    }
+//     uint256_t *l_value = NULL;
+//     uint256_t l_value_fee = {};
+//     dap_chain_addr_t **l_addr_to = NULL;
+//     size_t l_addr_el_count = 0;
+//     size_t l_value_el_count = 0;
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-wallet_fee", &l_wallet_fee_name);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name);
+
+//     // Validator's fee
+//     if (dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) {
+//         if (!str_tmp) {
+//             printf("tx_create requires parameter '-fee'");
+//             return -1;
+//         }
+//         l_value_fee = dap_chain_balance_scan(str_tmp);
+//     }
+//     if (IS_ZERO_256(l_value_fee) && (str_tmp && strcmp(str_tmp, "0"))) {
+//         printf("tx_create requires parameter '-fee' to be valid uint256");
+//         return -2;
+//     }
 
-    if (!l_from_wallet_name) {
-        printf("tx_create requires parameter '-from_wallet'");
-        return -3;
-    }
+//     if (!l_from_wallet_name) {
+//         printf("tx_create requires parameter '-from_wallet'");
+//         return -3;
+//     }
 
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
-    if (!l_token_ticker) {
-        printf("tx_create requires parameter '-token'");
-        return -4;
-    }
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
+//     if (!l_token_ticker) {
+//         printf("tx_create requires parameter '-token'");
+//         return -4;
+//     }
 
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp);
 
-    if (!str_tmp) {
-        printf("tx_create requires parameter '-value' to be valid uint256 value");
-        return -6;
-    }
-    l_value_el_count = dap_str_symbol_count(str_tmp, ',') + 1;
+//     if (!str_tmp) {
+//         printf("tx_create requires parameter '-value' to be valid uint256 value");
+//         return -6;
+//     }
+//     l_value_el_count = dap_str_symbol_count(str_tmp, ',') + 1;
 
-    if (addr_base58_to)
-        l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1;
-    else 
-        l_addr_el_count = l_value_el_count;
+//     if (addr_base58_to)
+//         l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1;
+//     else 
+//         l_addr_el_count = l_value_el_count;
 
-    if (addr_base58_to && l_addr_el_count != l_value_el_count) {
-        printf("num of '-to_addr' and '-value' should be equal");
-        return -5;
-    }
+//     if (addr_base58_to && l_addr_el_count != l_value_el_count) {
+//         printf("num of '-to_addr' and '-value' should be equal");
+//         return -5;
+//     }
 
-    l_value = DAP_NEW_Z_COUNT(uint256_t, l_value_el_count);
-    if (!l_value) {
-        printf("Can't allocate memory");
-        return -6;
-    }
-    char **l_value_array = dap_strsplit(str_tmp, ",", l_value_el_count);
-    if (!l_value_array) {
-        DAP_DELETE(l_value);
-        printf("Can't read '-to_addr' arg");
-        return -7;
-    }
-    for (size_t i = 0; i < l_value_el_count; ++i) {
-        l_value[i] = dap_chain_balance_scan(l_value_array[i]);
-        if(IS_ZERO_256(l_value[i])) {
-            DAP_DEL_MULTY(l_value_array, l_value);
-            printf("tx_create requires parameter '-value' to be valid uint256 value");
-            return -8;
-        }
-    }
-    DAP_DELETE(l_value_array);
+//     l_value = DAP_NEW_Z_COUNT(uint256_t, l_value_el_count);
+//     if (!l_value) {
+//         printf("Can't allocate memory");
+//         return -6;
+//     }
+//     char **l_value_array = dap_strsplit(str_tmp, ",", l_value_el_count);
+//     if (!l_value_array) {
+//         DAP_DELETE(l_value);
+//         printf("Can't read '-to_addr' arg");
+//         return -7;
+//     }
+//     for (size_t i = 0; i < l_value_el_count; ++i) {
+//         l_value[i] = dap_chain_balance_scan(l_value_array[i]);
+//         if(IS_ZERO_256(l_value[i])) {
+//             DAP_DEL_MULTY(l_value_array, l_value);
+//             printf("tx_create requires parameter '-value' to be valid uint256 value");
+//             return -8;
+//         }
+//     }
+//     DAP_DELETE(l_value_array);
 
-    if (addr_base58_to) {
-        l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count);
-        if (!l_addr_to) {
-            printf("Can't allocate memory");
-            DAP_DELETE(l_value);
-            return -9;
-        }
-        char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count);
-        if (!l_addr_base58_to_array) {
-            DAP_DEL_MULTY(l_addr_to, l_value);
-            printf("Can't read '-to_addr' arg");
-            return -10;
-        }
-        for (size_t i = 0; i < l_addr_el_count; ++i) {
-            l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]);
-            if(!l_addr_to[i]) {
-                for (size_t j = 0; j < i; ++j) {
-                    DAP_DELETE(l_addr_to[j]);
-                }
-                DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value);
-                printf("destination address is invalid");
-                return -11;
-            }
-        }
-        DAP_DELETE(l_addr_base58_to_array);
-    }
+//     if (addr_base58_to) {
+//         l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count);
+//         if (!l_addr_to) {
+//             printf("Can't allocate memory");
+//             DAP_DELETE(l_value);
+//             return -9;
+//         }
+//         char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count);
+//         if (!l_addr_base58_to_array) {
+//             DAP_DEL_MULTY(l_addr_to, l_value);
+//             printf("Can't read '-to_addr' arg");
+//             return -10;
+//         }
+//         for (size_t i = 0; i < l_addr_el_count; ++i) {
+//             l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]);
+//             if(!l_addr_to[i]) {
+//                 for (size_t j = 0; j < i; ++j) {
+//                     DAP_DELETE(l_addr_to[j]);
+//                 }
+//                 DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value);
+//                 printf("destination address is invalid");
+//                 return -11;
+//             }
+//         }
+//         DAP_DELETE(l_addr_base58_to_array);
+//     }
     
-    dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, l_wallet_path, NULL);
-    if(!l_wallet) {
-        printf("Can't open wallet %s", l_from_wallet_name);
-        return -12;
-    }
+//     dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, l_wallet_path, NULL);
+//     if(!l_wallet) {
+//         printf("Can't open wallet %s", l_from_wallet_name);
+//         return -12;
+//     }
 
 
-    dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name));
-    for (size_t i = 0; l_addr_to && i < l_addr_el_count; ++i) {
-        if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) {
-            printf("The transaction cannot be directed to the same address as the source.");
-            for (size_t j = 0; j < l_addr_el_count; ++j) {
-                    DAP_DELETE(l_addr_to[j]);
-            }
-            DAP_DEL_MULTY(l_addr_to, l_value);
-            return -13;
-        }
-    }
+//     dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name));
+//     for (size_t i = 0; l_addr_to && i < l_addr_el_count; ++i) {
+//         if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) {
+//             printf("The transaction cannot be directed to the same address as the source.");
+//             for (size_t j = 0; j < l_addr_el_count; ++j) {
+//                     DAP_DELETE(l_addr_to[j]);
+//             }
+//             DAP_DEL_MULTY(l_addr_to, l_value);
+//             return -13;
+//         }
+//     }
 
 
-    dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count, l_url_str, l_port);
+//     dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count, l_url_str, l_port);
 
-    json_object * l_json_obj_ret = json_object_new_object();
-    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-    printf("%s", json_object_to_json_string(l_json_obj_ret));
-    json_object_put(l_json_obj_ret);
-    dap_chain_datum_tx_delete(l_tx);
-    DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from);
-    return 0;
-}
+//     json_object * l_json_obj_ret = json_object_new_object();
+//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+//     printf("%s", json_object_to_json_string(l_json_obj_ret));
+//     json_object_put(l_json_obj_ret);
+//     dap_chain_datum_tx_delete(l_tx);
+//     DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from);
+//     return 0;
+// }
 
-int dap_chain_datum_tx_add_out_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value) {
-    if (IS_ZERO_256(a_value))
-        return -1;
+// int dap_chain_datum_tx_add_out_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value) {
+//     if (IS_ZERO_256(a_value))
+//         return -1;
     
-    dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t);
-    if (!l_item)
-        return -1;
+//     dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t);
+//     if (!l_item)
+//         return -1;
     
-    l_item->header.type = TX_ITEM_TYPE_OUT;
-    l_item->header.value = a_value;
+//     l_item->header.type = TX_ITEM_TYPE_OUT;
+//     l_item->header.value = a_value;
     
-    int res = dap_chain_datum_tx_add_item(a_tx, l_item);
-    DAP_DELETE(l_item);
+//     int res = dap_chain_datum_tx_add_item(a_tx, l_item);
+//     DAP_DELETE(l_item);
     
-    return res;
-}
+//     return res;
+// }
 
 
-int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value, const char *a_token)
-{
-    if (!a_token || IS_ZERO_256(a_value))
-        return -1;
+// int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value, const char *a_token)
+// {
+//     if (!a_token || IS_ZERO_256(a_value))
+//         return -1;
 
-    dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t);
-    if (!l_item)
-        return -2;
-    l_item->header.type = TX_ITEM_TYPE_OUT_EXT;
-    l_item->header.value = a_value;
-    dap_strncpy((char*)l_item->token, a_token, sizeof(l_item->token) - 1);
+//     dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t);
+//     if (!l_item)
+//         return -2;
+//     l_item->header.type = TX_ITEM_TYPE_OUT_EXT;
+//     l_item->header.value = a_value;
+//     dap_strncpy((char*)l_item->token, a_token, sizeof(l_item->token) - 1);
 
-    int result = dap_chain_datum_tx_add_item(a_tx, l_item);
-    DAP_DELETE(l_item);
-    return result;
-}
+//     int result = dap_chain_datum_tx_add_item(a_tx, l_item);
+//     DAP_DELETE(l_item);
+//     return result;
+// }
 
 
-dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
-        const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port)
-{
-    if (!a_addr_from || !a_token_ticker || !a_value) {
-        return NULL;
-    }
+// dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
+//         const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port)
+// {
+//     if (!a_addr_from || !a_token_ticker || !a_value) {
+//         return NULL;
+//     }
 
-    if (dap_chain_addr_check_sum(a_addr_from)) {
-        return NULL;
-    }
+//     if (dap_chain_addr_check_sum(a_addr_from)) {
+//         return NULL;
+//     }
 
-    for (size_t i = 0; i < a_tx_num; ++i) {
-        // if (!a_addr_to || !a_addr_to[i]) {
-        //     return NULL;
-        // }
-        if (a_addr_to && dap_chain_addr_check_sum(a_addr_to[i])) {
-            return NULL;
-        }
-        if (IS_ZERO_256(a_value[i])) {
-            return NULL;
-        }
-    }
-    const char * l_native_ticker = s_get_native_ticker(l_net_name);
-    bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker);
+//     for (size_t i = 0; i < a_tx_num; ++i) {
+//         // if (!a_addr_to || !a_addr_to[i]) {
+//         //     return NULL;
+//         // }
+//         if (a_addr_to && dap_chain_addr_check_sum(a_addr_to[i])) {
+//             return NULL;
+//         }
+//         if (IS_ZERO_256(a_value[i])) {
+//             return NULL;
+//         }
+//     }
+//     const char * l_native_ticker = s_get_native_ticker(l_net_name);
+//     bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker);
 
-    uint256_t l_value_transfer = {}; // how many coins to transfer
-    uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {};
-    for (size_t i = 0; i < a_tx_num; ++i) {
-        SUM_256_256(l_value_total, a_value[i], &l_value_total);
-    }
-    uint256_t l_value_need = l_value_total;
+//     uint256_t l_value_transfer = {}; // how many coins to transfer
+//     uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {};
+//     for (size_t i = 0; i < a_tx_num; ++i) {
+//         SUM_256_256(l_value_total, a_value[i], &l_value_total);
+//     }
+//     uint256_t l_value_need = l_value_total;
 
-    dap_list_t *l_list_fee_out = NULL;
-    uint256_t l_net_fee = {};
-    dap_chain_addr_t *l_addr_fee = NULL;
-    if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port)) {
-        return NULL;
-    }
+//     dap_list_t *l_list_fee_out = NULL;
+//     uint256_t l_net_fee = {};
+//     dap_chain_addr_t *l_addr_fee = NULL;
+//     if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port)) {
+//         return NULL;
+//     }
 
-    bool l_net_fee_used = !IS_ZERO_256(l_net_fee);
-    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
-    json_object *l_outs = NULL;
-    int l_outputs_count = 0;
-    if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) {
-        return NULL;
-    }
+//     bool l_net_fee_used = !IS_ZERO_256(l_net_fee);
+//     SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
+//     json_object *l_outs = NULL;
+//     int l_outputs_count = 0;
+//     if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) {
+//         return NULL;
+//     }
 
-    if (l_single_channel)
-        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
-    else if (!IS_ZERO_256(l_total_fee)) {
-        l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
-                                                               l_total_fee, 
-                                                               &l_fee_transfer);
-        if (!l_list_fee_out) {
-            printf("Not enough funds to pay fee");
-            json_object_put(l_outs);
-            return NULL;
-        }
-    }
-    dap_list_t *l_list_used_out = NULL;
-    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
-                                                            l_value_need,
-                                                            &l_value_transfer);
-    json_object_put(l_outs);
-    if (!l_list_used_out) {
-        printf("Not enough funds to transfer");
-        return NULL;
-    }
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-    // add 'in' items
-    {
-        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-        assert(EQUAL_256(l_value_to_items, l_value_transfer));
-        dap_list_free_full(l_list_used_out, NULL);
-        if (l_list_fee_out) {
-            uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-            assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
-            dap_list_free_full(l_list_fee_out, NULL);
-        }
+//     if (l_single_channel)
+//         SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+//     else if (!IS_ZERO_256(l_total_fee)) {
+//         l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+//                                                                l_total_fee, 
+//                                                                &l_fee_transfer);
+//         if (!l_list_fee_out) {
+//             printf("Not enough funds to pay fee");
+//             json_object_put(l_outs);
+//             return NULL;
+//         }
+//     }
+//     dap_list_t *l_list_used_out = NULL;
+//     l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+//                                                             l_value_need,
+//                                                             &l_value_transfer);
+//     json_object_put(l_outs);
+//     if (!l_list_used_out) {
+//         printf("Not enough funds to transfer");
+//         return NULL;
+//     }
+//     // create empty transaction
+//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+//     // add 'in' items
+//     {
+//         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+//         assert(EQUAL_256(l_value_to_items, l_value_transfer));
+//         dap_list_free_full(l_list_used_out, NULL);
+//         if (l_list_fee_out) {
+//             uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+//             assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+//             dap_list_free_full(l_list_fee_out, NULL);
+//         }
 
-    }
-    if (a_tx_num > 1) {
-        uint32_t l_tx_num = a_tx_num;
-        dap_chain_tx_tsd_t *l_out_count = dap_chain_datum_tx_item_tsd_create(&l_tx_num, DAP_CHAIN_DATUM_TRANSFER_TSD_TYPE_OUT_COUNT, sizeof(uint32_t));
-        dap_chain_datum_tx_add_item(&l_tx, l_out_count);
-    }
+//     }
+//     if (a_tx_num > 1) {
+//         uint32_t l_tx_num = a_tx_num;
+//         dap_chain_tx_tsd_t *l_out_count = dap_chain_datum_tx_item_tsd_create(&l_tx_num, DAP_CHAIN_DATUM_TRANSFER_TSD_TYPE_OUT_COUNT, sizeof(uint32_t));
+//         dap_chain_datum_tx_add_item(&l_tx, l_out_count);
+//     }
     
-    if (l_single_channel) { // add 'out' items
-        uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
-        for (size_t i = 0; i < a_tx_num; ++i) {
-            if (a_addr_to) {
-                if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) != 1) {
-                    dap_chain_datum_tx_delete(l_tx);
-                    return NULL;
-                }
-            } else {
-                if (dap_chain_datum_tx_add_out_without_addr(&l_tx, a_value[i]) != 1) {
-                    dap_chain_datum_tx_delete(l_tx);
-                    return NULL;
-                }
-            }
-                SUM_256_256(l_value_pack, a_value[i], &l_value_pack);
-        }
-        // Network fee
-        if (l_net_fee_used) {
-            if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
-                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-            else {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
-            }
-        }
-        // Validator's fee
-        if (!IS_ZERO_256(a_value_fee)) {
-            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
-                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
-            else {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
-            }
-        }
-        // coin back
-        uint256_t l_value_back;
-        SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-        if(!IS_ZERO_256(l_value_back)) {
-            if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
-            }
-        }
-    } else { // add 'out_ext' items
-        for (size_t i = 0; i < a_tx_num; ++i) {
-            if (a_addr_to) {
-                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) {
-                    dap_chain_datum_tx_delete(l_tx);
-                    return NULL;
-                }
-            } else {
-                if (dap_chain_datum_tx_add_out_ext_item_without_addr(&l_tx, a_value[i], a_token_ticker) != 1) {
-                    dap_chain_datum_tx_delete(l_tx);
-                    return NULL;
-                }
-            }
-        }
-        // coin back
-        uint256_t l_value_back;
-        SUBTRACT_256_256(l_value_transfer, l_value_total, &l_value_back);
-        if(!IS_ZERO_256(l_value_back)) {
-            if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
-            }
-        }
-        // Network fee
-        if (l_net_fee_used) {
-            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
-            }
-        }
-        // Validator's fee
-        if (!IS_ZERO_256(a_value_fee)) {
-            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
-            }
-        }
-        // fee coin back
-        SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back);
-        if(!IS_ZERO_256(l_value_back)) {
-            if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
-            }
-        }
-    }
-    DAP_DELETE(l_addr_fee);
-    return l_tx;
-}
+//     if (l_single_channel) { // add 'out' items
+//         uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
+//         for (size_t i = 0; i < a_tx_num; ++i) {
+//             if (a_addr_to) {
+//                 if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) != 1) {
+//                     dap_chain_datum_tx_delete(l_tx);
+//                     return NULL;
+//                 }
+//             } else {
+//                 if (dap_chain_datum_tx_add_out_without_addr(&l_tx, a_value[i]) != 1) {
+//                     dap_chain_datum_tx_delete(l_tx);
+//                     return NULL;
+//                 }
+//             }
+//                 SUM_256_256(l_value_pack, a_value[i], &l_value_pack);
+//         }
+//         // Network fee
+//         if (l_net_fee_used) {
+//             if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
+//                 SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+//             else {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 return NULL;
+//             }
+//         }
+//         // Validator's fee
+//         if (!IS_ZERO_256(a_value_fee)) {
+//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+//                 SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+//             else {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 return NULL;
+//             }
+//         }
+//         // coin back
+//         uint256_t l_value_back;
+//         SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+//         if(!IS_ZERO_256(l_value_back)) {
+//             if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 return NULL;
+//             }
+//         }
+//     } else { // add 'out_ext' items
+//         for (size_t i = 0; i < a_tx_num; ++i) {
+//             if (a_addr_to) {
+//                 if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) {
+//                     dap_chain_datum_tx_delete(l_tx);
+//                     return NULL;
+//                 }
+//             } else {
+//                 if (dap_chain_datum_tx_add_out_ext_item_without_addr(&l_tx, a_value[i], a_token_ticker) != 1) {
+//                     dap_chain_datum_tx_delete(l_tx);
+//                     return NULL;
+//                 }
+//             }
+//         }
+//         // coin back
+//         uint256_t l_value_back;
+//         SUBTRACT_256_256(l_value_transfer, l_value_total, &l_value_back);
+//         if(!IS_ZERO_256(l_value_back)) {
+//             if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 return NULL;
+//             }
+//         }
+//         // Network fee
+//         if (l_net_fee_used) {
+//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 return NULL;
+//             }
+//         }
+//         // Validator's fee
+//         if (!IS_ZERO_256(a_value_fee)) {
+//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 return NULL;
+//             }
+//         }
+//         // fee coin back
+//         SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back);
+//         if(!IS_ZERO_256(l_value_back)) {
+//             if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 return NULL;
+//             }
+//         }
+//     }
+//     DAP_DELETE(l_addr_fee);
+//     return l_tx;
+// }
 
 dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer)
 {
@@ -1018,157 +1052,162 @@ dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array,
     }
 }
 
-uint256_t get_balance_from_json(json_object *l_json_outs, const char *a_token_sell) {
-    uint256_t l_value = {};
-    if (l_json_outs && json_object_is_type(l_json_outs, json_type_array)) {
-        for (size_t i = 0; i < json_object_array_length(l_json_outs); i++) {
-            json_object *outer_array = json_object_array_get_idx(l_json_outs, i);
-            if (json_object_is_type(outer_array, json_type_array)) {
-                for (size_t j = 0; j < json_object_array_length(outer_array); j++) {
-                    json_object *addr_obj = json_object_array_get_idx(outer_array, j);
-                    if (json_object_is_type(addr_obj, json_type_object)) {
-                        json_object *tokens = NULL;
-                        if (json_object_object_get_ex(addr_obj, "tokens", &tokens) && json_object_is_type(tokens, json_type_array)) {
-                            for (size_t k = 0; k < json_object_array_length(tokens); k++) {
-                                json_object *token_obj = json_object_array_get_idx(tokens, k);
-                                json_object *token = NULL;
-                                if (json_object_object_get_ex(token_obj, "token", &token) && json_object_is_type(token, json_type_object)) {
-                                    json_object *ticker = NULL;
-                                    if (json_object_object_get_ex(token, "ticker", &ticker) && json_object_is_type(ticker, json_type_string)) {
-                                        const char *ticker_str = json_object_get_string(ticker);
-                                        if (strcmp(ticker_str, a_token_sell) == 0) {
-                                            json_object *datoshi = NULL;
-                                            if (json_object_object_get_ex(token_obj, "datoshi", &datoshi) && json_object_is_type(datoshi, json_type_string)) {
-                                                const char *datoshi_str = json_object_get_string(datoshi);
-                                                l_value = dap_uint256_scan_uninteger(datoshi_str);
-                                                break;
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-    return l_value;
-}
+// uint256_t get_balance_from_json(json_object *l_json_outs, const char *a_token_sell) {
+//     uint256_t l_value = {};
+//     if (l_json_outs && json_object_is_type(l_json_outs, json_type_array)) {
+//         for (size_t i = 0; i < json_object_array_length(l_json_outs); i++) {
+//             json_object *outer_array = json_object_array_get_idx(l_json_outs, i);
+//             if (json_object_is_type(outer_array, json_type_array)) {
+//                 for (size_t j = 0; j < json_object_array_length(outer_array); j++) {
+//                     json_object *addr_obj = json_object_array_get_idx(outer_array, j);
+//                     if (json_object_is_type(addr_obj, json_type_object)) {
+//                         json_object *tokens = NULL;
+//                         if (json_object_object_get_ex(addr_obj, "tokens", &tokens) && json_object_is_type(tokens, json_type_array)) {
+//                             for (size_t k = 0; k < json_object_array_length(tokens); k++) {
+//                                 json_object *token_obj = json_object_array_get_idx(tokens, k);
+//                                 json_object *token = NULL;
+//                                 if (json_object_object_get_ex(token_obj, "token", &token) && json_object_is_type(token, json_type_object)) {
+//                                     json_object *ticker = NULL;
+//                                     if (json_object_object_get_ex(token, "ticker", &ticker) && json_object_is_type(ticker, json_type_string)) {
+//                                         const char *ticker_str = json_object_get_string(ticker);
+//                                         if (strcmp(ticker_str, a_token_sell) == 0) {
+//                                             json_object *datoshi = NULL;
+//                                             if (json_object_object_get_ex(token_obj, "datoshi", &datoshi) && json_object_is_type(datoshi, json_type_string)) {
+//                                                 const char *datoshi_str = json_object_get_string(datoshi);
+//                                                 l_value = dap_uint256_scan_uninteger(datoshi_str);
+//                                                 break;
+//                                             }
+//                                         }
+//                                     }
+//                                 }
+//                             }
+//                         }
+//                     }
+//                 }
+//             }
+//         }
+//     }
+//     return l_value;
+// }
 
-bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) {
-    if (json_object_is_type(l_json_coins, json_type_array)) {
-        for (size_t i = 0; i < json_object_array_length(l_json_coins); i++) {
-            json_object *token_array = json_object_array_get_idx(l_json_coins, i);
-            if (json_object_is_type(token_array, json_type_array)) {
-                for (size_t j = 0; j < json_object_array_length(token_array); j++) {
-                    json_object *token_obj = json_object_array_get_idx(token_array, j);
-                    json_object *token_name = NULL;
-                    if (json_object_object_get_ex(token_obj, "-->Token name", &token_name) && json_object_is_type(token_name, json_type_string)) {
-                        const char *token_name_str = json_object_get_string(token_name);
-                        if (strcmp(token_name_str, a_token) == 0) {
-                            return true;
-                        }
-                    }
-                }
-            }
-        }
-    }
-    return false;
-}
+// bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) {
+//     if (json_object_is_type(l_json_coins, json_type_array)) {
+//         for (size_t i = 0; i < json_object_array_length(l_json_coins); i++) {
+//             json_object *token_array = json_object_array_get_idx(l_json_coins, i);
+//             if (json_object_is_type(token_array, json_type_array)) {
+//                 for (size_t j = 0; j < json_object_array_length(token_array); j++) {
+//                     json_object *token_obj = json_object_array_get_idx(token_array, j);
+//                     json_object *token_name = NULL;
+//                     if (json_object_object_get_ex(token_obj, "-->Token name", &token_name) && json_object_is_type(token_name, json_type_string)) {
+//                         const char *token_name_str = json_object_get_string(token_name);
+//                         if (strcmp(token_name_str, a_token) == 0) {
+//                             return true;
+//                         }
+//                     }
+//                 }
+//             }
+//         }
+//     }
+//     return false;
+// }
 
-dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,
-                                     const char *a_token_sell, uint256_t a_datoshi_sell,
-                                     uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port){
-    if (!a_net_name || !a_token_buy || !a_token_sell || !a_wallet) {
-        return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMEN
-    }
-    if (IS_ZERO_256(a_rate)) {
-        return NULL; // XCHANGE_CREATE_ERROR_RATE_IS_ZERO
-    }
-    if (IS_ZERO_256(a_fee)) {
-        return NULL; // XCHANGE_CREATE_ERROR_FEE_IS_ZERO
-    }
-    if (IS_ZERO_256(a_datoshi_sell)) {
-        return NULL; // XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO
-    }
-    char data[512];
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name);
-    json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
-    if (!l_json_coins) {
-        return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS
-    }
-    if (!check_token_in_ledger(l_json_coins, a_token_sell) || !check_token_in_ledger(l_json_coins, a_token_buy)) {
-        json_object_put(l_json_coins);
-        return NULL; // XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER
-    }
-    json_object_put(l_json_coins);
-    dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name));
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
-            dap_chain_addr_to_str(l_wallet_addr), a_net_name);
-    DAP_DEL_Z(l_wallet_addr);
-    json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
-    uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell);
-
-    uint256_t l_value_sell = a_datoshi_sell;
-    if (!dap_strcmp(s_get_native_ticker(a_net_name), a_token_sell)) {
-        if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) {
-            return NULL; // XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE
-        }
-    } else { // sell non-native ticker
-        uint256_t l_fee_value = get_balance_from_json(l_json_outs, s_get_native_ticker(a_net_name));
-        if (compare256(l_fee_value, a_fee) == -1) {
-            return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET
-        }
-    }
-    if (compare256(l_value, l_value_sell) == -1) {
-        return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET
-    }
-    // Create the price
-    dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
-    if (!l_price) {
-        return NULL; // XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED
-    }
-    dap_stpcpy(l_price->token_sell, a_token_sell);
-    dap_stpcpy(l_price->token_buy, a_token_buy);
-    l_price->datoshi_sell = a_datoshi_sell;
-    l_price->rate = a_rate;
-    l_price->fee = a_fee;
-    dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name, a_url_str, a_port);
-    return l_tx;
-}
+// dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,
+//                                      const char *a_token_sell, uint256_t a_datoshi_sell,
+//                                      uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port){
+//     if (!a_net_name || !a_token_buy || !a_token_sell || !a_wallet) {
+//         return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMEN
+//     }
+//     if (IS_ZERO_256(a_rate)) {
+//         return NULL; // XCHANGE_CREATE_ERROR_RATE_IS_ZERO
+//     }
+//     if (IS_ZERO_256(a_fee)) {
+//         return NULL; // XCHANGE_CREATE_ERROR_FEE_IS_ZERO
+//     }
+//     if (IS_ZERO_256(a_datoshi_sell)) {
+//         return NULL; // XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO
+//     }
+//     char data[512];
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name);
+//     json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
+//     if (!l_json_coins) {
+//         return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS
+//     }
+//     if (!check_token_in_ledger(l_json_coins, a_token_sell) || !check_token_in_ledger(l_json_coins, a_token_buy)) {
+//         json_object_put(l_json_coins);
+//         return NULL; // XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER
+//     }
+//     json_object_put(l_json_coins);
+//     dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name));
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
+//             dap_chain_addr_to_str(l_wallet_addr), a_net_name);
+//     DAP_DEL_Z(l_wallet_addr);
+//     json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
+//     uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell);
+
+//     uint256_t l_value_sell = a_datoshi_sell;
+//     if (!dap_strcmp(s_get_native_ticker(a_net_name), a_token_sell)) {
+//         if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) {
+//             return NULL; // XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE
+//         }
+//     } else { // sell non-native ticker
+//         uint256_t l_fee_value = get_balance_from_json(l_json_outs, s_get_native_ticker(a_net_name));
+//         if (compare256(l_fee_value, a_fee) == -1) {
+//             return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET
+//         }
+//     }
+//     if (compare256(l_value, l_value_sell) == -1) {
+//         return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET
+//     }
+//     // Create the price
+//     dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
+//     if (!l_price) {
+//         return NULL; // XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED
+//     }
+//     dap_stpcpy(l_price->token_sell, a_token_sell);
+//     dap_stpcpy(l_price->token_buy, a_token_buy);
+//     l_price->datoshi_sell = a_datoshi_sell;
+//     l_price->rate = a_rate;
+//     l_price->fee = a_fee;
+//     dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name, a_url_str, a_port);
+//     return l_tx;
+// }
 
-json_object *dap_get_remote_tx_outs(const char *a_token_ticker, const char *a_net_name,  dap_chain_addr_t * a_addr, const char *a_url_str, uint16_t a_port) { 
+json_object *dap_get_remote_tx_outs(const char *a_token_ticker,  dap_chain_addr_t * a_addr, compose_config_t *a_config) { 
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
-            dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name);
-    json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
+            dap_chain_addr_to_str(a_addr), a_token_ticker, a_config->net_name);
+    json_object *l_json_outs = dap_request_command_to_rpc(data, a_config);
     if (!l_json_outs) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Failed to get response from RPC request");
         return NULL;
     }
 
     if (!json_object_is_type(l_json_outs, json_type_array)) {
         json_object_put(l_json_outs);
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is not an array");
         return NULL;
     }
 
     if (json_object_array_length(l_json_outs) == 0) {
         json_object_put(l_json_outs);
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is empty");
         return NULL;
     }
 
     json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0);
     if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) {
         json_object_put(l_json_outs);
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is not an array");
         return NULL;
     }
 
     json_object *l_first_item = json_object_array_get_idx(l_first_array, 0);
     if (!l_first_item) {
         json_object_put(l_json_outs);
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is not an array");
         return NULL;
     }
 
@@ -1176,6 +1215,7 @@ json_object *dap_get_remote_tx_outs(const char *a_token_ticker, const char *a_ne
     if (!json_object_object_get_ex(l_first_item, "outs", &l_outs) ||
         !json_object_is_type(l_outs, json_type_array)) {
         json_object_put(l_json_outs);
+        dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is not an array");
         return NULL;
     }
     json_object_get(l_outs);
@@ -1184,1158 +1224,1158 @@ json_object *dap_get_remote_tx_outs(const char *a_token_ticker, const char *a_ne
 }
 
 
-dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
-                                                                 const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port)
-{
-    if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) {
-        return NULL;
-    }
-    const char *l_native_ticker = s_get_native_ticker(a_net_name);
-    bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker);
-    // find the transactions from which to take away coins
-    uint256_t l_value_transfer; // how many coins to transfer
-    uint256_t l_value_need = a_price->datoshi_sell,
-              l_net_fee,
-              l_total_fee = a_price->fee,
-              l_fee_transfer;
-    dap_chain_addr_t * l_addr_net_fee = NULL;
-    dap_list_t *l_list_fee_out = NULL;
+// dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
+//                                                                  const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port)
+// {
+//     if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) {
+//         return NULL;
+//     }
+//     const char *l_native_ticker = s_get_native_ticker(a_net_name);
+//     bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker);
+//     // find the transactions from which to take away coins
+//     uint256_t l_value_transfer; // how many coins to transfer
+//     uint256_t l_value_need = a_price->datoshi_sell,
+//               l_net_fee,
+//               l_total_fee = a_price->fee,
+//               l_fee_transfer;
+//     dap_chain_addr_t * l_addr_net_fee = NULL;
+//     dap_list_t *l_list_fee_out = NULL;
+
+//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee, a_url_str, a_port);
+//     if (l_net_fee_used)
+//         SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
+
+//     dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name));
+//     dap_chain_addr_t l_seller_addr = *l_wallet_addr;
+//     json_object *l_outs_native = dap_get_remote_tx_outs(a_native_ticker, a_net_name, l_wallet_addr, a_url_str, a_port);
+//     if (!l_outs_native) {
+//         return NULL;
+//     }
 
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee, a_url_str, a_port);
-    if (l_net_fee_used)
-        SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
+//     json_object *l_outs = NULL;
+//     if (!dap_strcmp(a_price->token_sell, a_native_ticker)) {
+//         l_outs = l_outs_native;
+//     } else {
+//         l_outs = dap_get_remote_tx_outs(a_price->token_sell, a_net_name, l_wallet_addr, a_url_str, a_port);
+//     }
+//     DAP_DELETE(l_wallet_addr);
+//     int l_out_native_count = json_object_array_length(l_outs_native);
+//     int l_out_count = json_object_array_length(l_outs);
+
+//     if (l_single_channel)
+//         SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+//     else if (!IS_ZERO_256(l_total_fee)) {
+//         l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+//                                                                l_total_fee, 
+//                                                                &l_fee_transfer);
+//         if (!l_list_fee_out) {
+//             printf("Not enough funds to pay fee");
+//             json_object_put(l_outs_native);
+//             json_object_put(l_outs);
+//             return NULL;
+//         }
+//     }
+//     dap_list_t *l_list_used_out = NULL;
+//     l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_out_count,
+//                                                             l_value_need,
+//                                                             &l_value_transfer);
+//     if (!l_list_used_out) {
+//         printf("Not enough funds to transfer");
+//         json_object_put(l_outs_native);
+//         json_object_put(l_outs);
+//         return NULL;
+//     }
 
-    dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name));
-    dap_chain_addr_t l_seller_addr = *l_wallet_addr;
-    json_object *l_outs_native = dap_get_remote_tx_outs(a_native_ticker, a_net_name, l_wallet_addr, a_url_str, a_port);
-    if (!l_outs_native) {
-        return NULL;
-    }
+//     // create empty transaction
+//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+//     // add 'in' items to sell
+//     uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+//     dap_list_free_full(l_list_used_out, NULL);
+//     if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) {
+//         dap_chain_datum_tx_delete(l_tx);
+//         printf("Can't compose the transaction input\n");
+//         return NULL;
+//     }
+//     if (!l_single_channel) {
+//         // add 'in' items to fee
+//         uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+//         if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Can't compose the transaction input\n");
+//             return NULL;
+//         }
+//     }
 
-    json_object *l_outs = NULL;
-    if (!dap_strcmp(a_price->token_sell, a_native_ticker)) {
-        l_outs = l_outs_native;
-    } else {
-        l_outs = dap_get_remote_tx_outs(a_price->token_sell, a_net_name, l_wallet_addr, a_url_str, a_port);
-    }
-    DAP_DELETE(l_wallet_addr);
-    int l_out_native_count = json_object_array_length(l_outs_native);
-    int l_out_count = json_object_array_length(l_outs);
-
-    if (l_single_channel)
-        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
-    else if (!IS_ZERO_256(l_total_fee)) {
-        l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
-                                                               l_total_fee, 
-                                                               &l_fee_transfer);
-        if (!l_list_fee_out) {
-            printf("Not enough funds to pay fee");
-            json_object_put(l_outs_native);
-            json_object_put(l_outs);
-            return NULL;
-        }
-    }
-    dap_list_t *l_list_used_out = NULL;
-    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_out_count,
-                                                            l_value_need,
-                                                            &l_value_transfer);
-    if (!l_list_used_out) {
-        printf("Not enough funds to transfer");
-        json_object_put(l_outs_native);
-        json_object_put(l_outs);
-        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, s_get_net_id(a_net_name), a_price->datoshi_sell,
+//                                                                                                 s_get_net_id(a_net_name), a_price->token_buy, a_price->rate,
+//                                                                                                 &l_seller_addr, NULL, 0);
+//         if (!l_tx_out) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Can't compose the transaction conditional output\n");
+//             return NULL;
+//         }
+//         dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
+//         DAP_DELETE(l_tx_out);
+//         // Network fee
+//         if (l_net_fee_used) {
+//             if ((l_single_channel &&
+//                         dap_chain_datum_tx_add_out_item(&l_tx, l_addr_net_fee, l_net_fee) != 1) ||
+//                     (!l_single_channel &&
+//                         dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Cant add network fee output\n");
+//                 return NULL;
+//             }
+//         }
+//         DAP_DELETE(l_addr_net_fee);
+//         // Validator's fee
+//         if (!IS_ZERO_256(a_price->fee)) {
+//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Cant add validator's fee output\n");
+//                 return NULL;
+//             }
+//         }
+//         // coin back
+//         uint256_t l_value_back = {};
+//         SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back);
+//         if (!IS_ZERO_256(l_value_back)) {
+//             if ((l_single_channel &&
+//                         dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) ||
+//                     (!l_single_channel &&
+//                         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);
+//                 printf("Cant add coin back output\n");
+//                 return NULL;
+//             }
+//         }
+//         // Fee coinback
+//         if (!l_single_channel) {
+//             uint256_t l_fee_coinback = {};
+//             SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback);
+//             if (!IS_ZERO_256(l_fee_coinback)) {
+//                 if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) {
+//                     dap_chain_datum_tx_delete(l_tx);
+//                     printf("Cant add fee back output\n");
+//                     return NULL;
+//                 }
+//             }
+//         }
+//     }
+//     return l_tx;
+// }
 
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-    // add 'in' items to sell
-    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-    dap_list_free_full(l_list_used_out, NULL);
-    if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) {
-        dap_chain_datum_tx_delete(l_tx);
-        printf("Can't compose the transaction input\n");
-        return NULL;
-    }
-    if (!l_single_channel) {
-        // add 'in' items to fee
-        uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-        if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Can't compose the transaction input\n");
-            return NULL;
-        }
-    }
+// // tx_cond_create -net <net_name> -token <token_ticker> -w <wallet_name> -cert <pub_cert_name> -value <value_datoshi> -fee <value> -unit {B | SEC} -srv_uid <numeric_uid>
+// int dap_tx_cond_create_compose(int argc, char ** argv)
+// {
+//     int arg_index = 1;
+//     const char * l_token_ticker = NULL;
+//     const char * l_wallet_str = NULL;
+//     const char * l_cert_str = NULL;
+//     const char * l_value_datoshi_str = NULL;
+//     const char * l_value_fee_str = NULL;
+//     const char * l_net_name = NULL;
+//     const char * l_unit_str = NULL;
+//     const char * l_srv_uid_str = NULL;
+//     uint256_t l_value_datoshi = {};    
+//     uint256_t l_value_fee = {};
+//     const char * l_url_str = NULL;
+//     const char * l_port_str = NULL;
+//     uint16_t l_port = 0;
+
+//     const char *l_wallet_path = NULL;
+//     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
+//     if (!l_wallet_path) {
+//         l_wallet_path =
+//         #ifdef DAP_OS_WINDOWS
+//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+//         #elif defined DAP_OS_MAC
+//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+//         #elif defined DAP_OS_UNIX
+//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+//         #endif
+//     }  
+
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_datoshi_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_value_fee_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str);
+//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str);
 
-    // add 'out_cond' & 'out' items
+//     if(!l_token_ticker) {
+//         printf("tx_cond_create requires parameter '-token'\n");
+//         return -2;
+//     }
+//     if (!l_wallet_str) {
+//         printf("tx_cond_create requires parameter '-w'\n");
+//         return -3;
+//     }
+//     if (!l_cert_str) {
+//         printf("tx_cond_create requires parameter '-cert'\n");
+//         return -4;
+//     }
+//     if(!l_value_datoshi_str) {
+//         printf("tx_cond_create requires parameter '-value'\n");
+//         return -5;
+//     }
+//     if(!l_value_fee_str){
+//         printf("tx_cond_create requires parameter '-fee'\n");
+//         return -6;
+//     }
+//     if(!l_net_name) {
+//         printf("tx_cond_create requires parameter '-net'\n");
+//         return -7;
+//     }
+//     if(!l_url_str) {
+//         l_url_str = dap_compose_get_net_url(l_net_name);
+//     }
+//     if(!l_port_str) {
+//         l_port = dap_compose_get_net_port(l_net_name);
+//     } else {
+//         l_port = atoi(l_port_str);
+//     }
+//     if(!l_unit_str) {
+//         printf("tx_cond_create requires parameter '-unit'\n");
+//         return -8;
+//     }
 
-    {
-        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, s_get_net_id(a_net_name), a_price->datoshi_sell,
-                                                                                                s_get_net_id(a_net_name), a_price->token_buy, a_price->rate,
-                                                                                                &l_seller_addr, NULL, 0);
-        if (!l_tx_out) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Can't compose the transaction conditional output\n");
-            return NULL;
-        }
-        dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
-        DAP_DELETE(l_tx_out);
-        // Network fee
-        if (l_net_fee_used) {
-            if ((l_single_channel &&
-                        dap_chain_datum_tx_add_out_item(&l_tx, l_addr_net_fee, l_net_fee) != 1) ||
-                    (!l_single_channel &&
-                        dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) {
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Cant add network fee output\n");
-                return NULL;
-            }
-        }
-        DAP_DELETE(l_addr_net_fee);
-        // Validator's fee
-        if (!IS_ZERO_256(a_price->fee)) {
-            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Cant add validator's fee output\n");
-                return NULL;
-            }
-        }
-        // coin back
-        uint256_t l_value_back = {};
-        SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back);
-        if (!IS_ZERO_256(l_value_back)) {
-            if ((l_single_channel &&
-                        dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) ||
-                    (!l_single_channel &&
-                        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);
-                printf("Cant add coin back output\n");
-                return NULL;
-            }
-        }
-        // Fee coinback
-        if (!l_single_channel) {
-            uint256_t l_fee_coinback = {};
-            SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback);
-            if (!IS_ZERO_256(l_fee_coinback)) {
-                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) {
-                    dap_chain_datum_tx_delete(l_tx);
-                    printf("Cant add fee back output\n");
-                    return NULL;
-                }
-            }
-        }
-    }
-    return l_tx;
-}
+//     if(!l_srv_uid_str) {
+//         printf("tx_cond_create requires parameter '-srv_uid'\n");
+//         return -9;
+//     }
+//     dap_chain_net_srv_uid_t l_srv_uid = {};
+//     l_srv_uid.uint64 = strtoll(l_srv_uid_str, NULL, 10);
+//     if (!l_srv_uid.uint64) {
+//         printf("Can't find service UID %s\n", l_srv_uid_str);
+//         return -10;
+//     }
 
-// tx_cond_create -net <net_name> -token <token_ticker> -w <wallet_name> -cert <pub_cert_name> -value <value_datoshi> -fee <value> -unit {B | SEC} -srv_uid <numeric_uid>
-int dap_tx_cond_create_compose(int argc, char ** argv)
-{
-    int arg_index = 1;
-    const char * l_token_ticker = NULL;
-    const char * l_wallet_str = NULL;
-    const char * l_cert_str = NULL;
-    const char * l_value_datoshi_str = NULL;
-    const char * l_value_fee_str = NULL;
-    const char * l_net_name = NULL;
-    const char * l_unit_str = NULL;
-    const char * l_srv_uid_str = NULL;
-    uint256_t l_value_datoshi = {};    
-    uint256_t l_value_fee = {};
-    const char * l_url_str = NULL;
-    const char * l_port_str = NULL;
-    uint16_t l_port = 0;
-
-    const char *l_wallet_path = NULL;
-    dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
-    if (!l_wallet_path) {
-        l_wallet_path =
-        #ifdef DAP_OS_WINDOWS
-                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-        #elif defined DAP_OS_MAC
-                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-        #elif defined DAP_OS_UNIX
-                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-        #endif
-    }  
-
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_datoshi_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_value_fee_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str);
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str);
-
-    if(!l_token_ticker) {
-        printf("tx_cond_create requires parameter '-token'\n");
-        return -2;
-    }
-    if (!l_wallet_str) {
-        printf("tx_cond_create requires parameter '-w'\n");
-        return -3;
-    }
-    if (!l_cert_str) {
-        printf("tx_cond_create requires parameter '-cert'\n");
-        return -4;
-    }
-    if(!l_value_datoshi_str) {
-        printf("tx_cond_create requires parameter '-value'\n");
-        return -5;
-    }
-    if(!l_value_fee_str){
-        printf("tx_cond_create requires parameter '-fee'\n");
-        return -6;
-    }
-    if(!l_net_name) {
-        printf("tx_cond_create requires parameter '-net'\n");
-        return -7;
-    }
-    if(!l_url_str) {
-        l_url_str = dap_compose_get_net_url(l_net_name);
-    }
-    if(!l_port_str) {
-        l_port = dap_compose_get_net_port(l_net_name);
-    } else {
-        l_port = atoi(l_port_str);
-    }
-    if(!l_unit_str) {
-        printf("tx_cond_create requires parameter '-unit'\n");
-        return -8;
-    }
+//     dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)l_unit_str)};
 
-    if(!l_srv_uid_str) {
-        printf("tx_cond_create requires parameter '-srv_uid'\n");
-        return -9;
-    }
-    dap_chain_net_srv_uid_t l_srv_uid = {};
-    l_srv_uid.uint64 = strtoll(l_srv_uid_str, NULL, 10);
-    if (!l_srv_uid.uint64) {
-        printf("Can't find service UID %s\n", l_srv_uid_str);
-        return -10;
-    }
+//     if(l_price_unit.enm == SERV_UNIT_UNDEFINED) {
+//         printf("Can't recognize unit '%s'. Unit must look like { B | SEC }\n", l_unit_str);
+//         return -11;
+//     }
 
-    dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)l_unit_str)};
+//     l_value_datoshi = dap_chain_balance_scan(l_value_datoshi_str);
+//     if(IS_ZERO_256(l_value_datoshi)) {
+//         printf("Can't recognize value '%s' as a number\n", l_value_datoshi_str);
+//         return -12;
+//     }
 
-    if(l_price_unit.enm == SERV_UNIT_UNDEFINED) {
-        printf("Can't recognize unit '%s'. Unit must look like { B | SEC }\n", l_unit_str);
-        return -11;
-    }
+//     l_value_fee = dap_chain_balance_scan(l_value_fee_str);
+//     if(IS_ZERO_256(l_value_fee)) {
+//         printf("Can't recognize value '%s' as a number\n", l_value_fee_str);
+//         return -13;
+//     }
 
-    l_value_datoshi = dap_chain_balance_scan(l_value_datoshi_str);
-    if(IS_ZERO_256(l_value_datoshi)) {
-        printf("Can't recognize value '%s' as a number\n", l_value_datoshi_str);
-        return -12;
-    }
+//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
+//     if(!l_wallet) {
+//         printf("Can't open wallet '%s'\n", l_wallet_str);
+//         return -15;
+//     }
 
-    l_value_fee = dap_chain_balance_scan(l_value_fee_str);
-    if(IS_ZERO_256(l_value_fee)) {
-        printf("Can't recognize value '%s' as a number\n", l_value_fee_str);
-        return -13;
-    }
+//     dap_cert_t *l_cert_cond = dap_cert_find_by_name(l_cert_str);
+//     if(!l_cert_cond) {
+//         dap_chain_wallet_close(l_wallet);
+//         printf("Can't find cert '%s'\n", l_cert_str);
+//         return -16;
+//     }
 
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
-    if(!l_wallet) {
-        printf("Can't open wallet '%s'\n", l_wallet_str);
-        return -15;
-    }
+//     dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
+//     dap_pkey_t *l_key_cond = dap_pkey_from_enc_key(l_cert_cond->enc_key);
+//     if (!l_key_cond) {
+//         dap_chain_wallet_close(l_wallet);
+//         dap_enc_key_delete(l_key_from);
+//         printf("Cert '%s' doesn't contain a valid public key\n", l_cert_str);
+//         return -17;
+//     }
 
-    dap_cert_t *l_cert_cond = dap_cert_find_by_name(l_cert_str);
-    if(!l_cert_cond) {
-        dap_chain_wallet_close(l_wallet);
-        printf("Can't find cert '%s'\n", l_cert_str);
-        return -16;
-    }
+//     uint256_t l_value_per_unit_max = {};
+//     dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker,
+//                                                         l_value_datoshi, l_value_per_unit_max, l_price_unit,
+//                                                         l_srv_uid, l_value_fee, NULL, 0, l_url_str, l_port);
+    
+//     json_object * l_json_obj_ret = json_object_new_object();
+//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+//     printf("%s", json_object_to_json_string(l_json_obj_ret));
+//     json_object_put(l_json_obj_ret);
+//     dap_chain_datum_tx_delete(l_tx);
+//     dap_chain_wallet_close(l_wallet);
+//     dap_enc_key_delete(l_key_from);
+//     DAP_DELETE(l_key_cond);
+//     return 0;
+// }
 
-    dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
-    dap_pkey_t *l_key_cond = dap_pkey_from_enc_key(l_cert_cond->enc_key);
-    if (!l_key_cond) {
-        dap_chain_wallet_close(l_wallet);
-        dap_enc_key_delete(l_key_from);
-        printf("Cert '%s' doesn't contain a valid public key\n", l_cert_str);
-        return -17;
-    }
 
-    uint256_t l_value_per_unit_max = {};
-    dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker,
-                                                        l_value_datoshi, l_value_per_unit_max, l_price_unit,
-                                                        l_srv_uid, l_value_fee, NULL, 0, l_url_str, l_port);
-    
-    json_object * l_json_obj_ret = json_object_new_object();
-    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-    printf("%s", json_object_to_json_string(l_json_obj_ret));
-    json_object_put(l_json_obj_ret);
-    dap_chain_datum_tx_delete(l_tx);
-    dap_chain_wallet_close(l_wallet);
-    dap_enc_key_delete(l_key_from);
-    DAP_DELETE(l_key_cond);
-    return 0;
-}
+// dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name,
+//         dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
+//         const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+//         uint256_t a_value, uint256_t a_value_per_unit_max,
+//         dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
+//         uint256_t a_value_fee, const void *a_cond,
+//         size_t a_cond_size, const char *a_url_str, uint16_t a_port)
+// {
+//     // check valid param
+//     if (!a_net_name || !*a_net_name || !a_key_from || !a_key_cond ||
+//             !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value) || !a_url_str || !*a_url_str || a_port == 0)
+//         return NULL;
+
+//     if (dap_strcmp(s_get_native_ticker(a_net_name), a_token_ticker)) {
+//         printf("Pay for service should be only in native token ticker\n");
+//         return NULL;
+//     }
 
+//     uint256_t l_net_fee = {};
+//     dap_chain_addr_t* l_addr_fee = NULL;
+//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port);
+//     // find the transactions from which to take away coins
+//     uint256_t l_value_transfer = {}; // how many coins to transfer
+//     uint256_t l_value_need = {};
+//     SUM_256_256(a_value, a_value_fee, &l_value_need);
+//     if (l_net_fee_used) {
+//         SUM_256_256(l_value_need, l_net_fee, &l_value_need);
+//     }
+//     // where to take coins for service
+//     dap_chain_addr_t l_addr_from;
+//     dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, s_get_net_id(a_net_name));
+//     // list of transaction with 'out' items
+//     json_object *l_outs = NULL;
+//     int l_outputs_count = 0;
+//     if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) {
+//         return NULL;
+//     }
+//     dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+//                                                             l_value_need,
+//                                                             &l_value_transfer);
+//     json_object_put(l_outs);
+//     if(!l_list_used_out) {
+//         printf("Nothing to transfer (not enough funds)\n");
+//         return NULL;
+//     }
 
-dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name,
-        dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
-        const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-        uint256_t a_value, uint256_t a_value_per_unit_max,
-        dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
-        uint256_t a_value_fee, const void *a_cond,
-        size_t a_cond_size, const char *a_url_str, uint16_t a_port)
-{
-    // check valid param
-    if (!a_net_name || !*a_net_name || !a_key_from || !a_key_cond ||
-            !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value) || !a_url_str || !*a_url_str || a_port == 0)
-        return NULL;
+//     // create empty transaction
+//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+//     // add 'in' items
+//     {
+//         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+//         assert(EQUAL_256(l_value_to_items, l_value_transfer));
+//         dap_list_free_full(l_list_used_out, NULL);
+//     }
+//     // add 'out_cond' and 'out' items
+//     {
+//         uint256_t l_value_pack = {}; // how much coin add to 'out' items
+//         if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond,
+//                 a_cond_size) == 1) {
+//             SUM_256_256(l_value_pack, a_value, &l_value_pack);
+//         } else {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Cant add conditional output\n");
+//             return NULL;
+//         }
+//         // Network fee
+//         if (l_net_fee_used) {
+//             if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
+//                 SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+//             else {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 return NULL;
+//             }
+//         }
+//         // Validator's fee
+//         if (!IS_ZERO_256(a_value_fee)) {
+//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+//                 SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+//             else {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 return NULL;
+//             }
+//         }
+//         // coin back
+//         uint256_t l_value_back = {};
+//         SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+//         if (!IS_ZERO_256(l_value_back)) {
+//             if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Cant add coin back output\n");
+//                 return NULL;
+//             }
+//         }
+//     }
 
-    if (dap_strcmp(s_get_native_ticker(a_net_name), a_token_ticker)) {
-        printf("Pay for service should be only in native token ticker\n");
-        return NULL;
-    }
+//     return l_tx;
+// }
 
-    uint256_t l_net_fee = {};
-    dap_chain_addr_t* l_addr_fee = NULL;
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port);
-    // find the transactions from which to take away coins
-    uint256_t l_value_transfer = {}; // how many coins to transfer
-    uint256_t l_value_need = {};
-    SUM_256_256(a_value, a_value_fee, &l_value_need);
-    if (l_net_fee_used) {
-        SUM_256_256(l_value_need, l_net_fee, &l_value_need);
-    }
-    // where to take coins for service
-    dap_chain_addr_t l_addr_from;
-    dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, s_get_net_id(a_net_name));
-    // list of transaction with 'out' items
-    json_object *l_outs = NULL;
-    int l_outputs_count = 0;
-    if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) {
-        return NULL;
-    }
-    dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
-                                                            l_value_need,
-                                                            &l_value_transfer);
-    json_object_put(l_outs);
-    if(!l_list_used_out) {
-        printf("Nothing to transfer (not enough funds)\n");
-        return NULL;
-    }
+// // stake_lock hold -net <net_name> -w <wallet_name> -time_staking <YYMMDD> -token <ticker> -value <value> -fee <value>[-chain <chain_name>] [-reinvest <percentage>]
+// int  dap_cli_hold_compose(int a_argc, char **a_argv)
+// {
+//     int arg_index = 1;
+//     const char *l_net_name = NULL, *l_ticker_str = NULL, *l_coins_str = NULL,
+//             *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL,
+//             *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL;
+
+//     char 	l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
+//     dap_time_t              			l_time_staking		=	0;
+//     uint256_t						    l_reinvest_percent	=	{};
+//     uint256_t							l_value_delegated	=	{};
+//     uint256_t                           l_value_fee     	=	{};
+//     uint256_t 							l_value;
+//     dap_enc_key_t						*l_key_from;
+//     dap_chain_wallet_t					*l_wallet;
+//     dap_chain_addr_t					*l_addr_holder;
+//     const char                          *l_url_str = NULL;
+//     uint16_t                            l_port = 0;
+
+//     const char *l_wallet_path = NULL;
+//     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
+//     if (!l_wallet_path) {
+//         l_wallet_path =
+//         #ifdef DAP_OS_WINDOWS
+//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+//         #elif defined DAP_OS_MAC
+//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+//         #elif defined DAP_OS_UNIX
+//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+//         #endif
+//     }  
+
+
+//     const char *l_hash_out_type = NULL;
+//     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
+//     if(!l_hash_out_type)
+//         l_hash_out_type = "hex";
+//     if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type, "base58")) {
+//         printf("Error: Invalid hash type argument\n");
+//         return -1;
+//     }
 
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-    // add 'in' items
-    {
-        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-        assert(EQUAL_256(l_value_to_items, l_value_transfer));
-        dap_list_free_full(l_list_used_out, NULL);
-    }
-    // add 'out_cond' and 'out' items
-    {
-        uint256_t l_value_pack = {}; // how much coin add to 'out' items
-        if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond,
-                a_cond_size) == 1) {
-            SUM_256_256(l_value_pack, a_value, &l_value_pack);
-        } else {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Cant add conditional output\n");
-            return NULL;
-        }
-        // Network fee
-        if (l_net_fee_used) {
-            if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
-                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-            else {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
-            }
-        }
-        // Validator's fee
-        if (!IS_ZERO_256(a_value_fee)) {
-            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
-                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
-            else {
-                dap_chain_datum_tx_delete(l_tx);
-                return NULL;
-            }
-        }
-        // coin back
-        uint256_t l_value_back = {};
-        SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-        if (!IS_ZERO_256(l_value_back)) {
-            if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Cant add coin back output\n");
-                return NULL;
-            }
-        }
-    }
-
-    return l_tx;
-}
-
-// stake_lock hold -net <net_name> -w <wallet_name> -time_staking <YYMMDD> -token <ticker> -value <value> -fee <value>[-chain <chain_name>] [-reinvest <percentage>]
-int  dap_cli_hold_compose(int a_argc, char **a_argv)
-{
-    int arg_index = 1;
-    const char *l_net_name = NULL, *l_ticker_str = NULL, *l_coins_str = NULL,
-            *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL,
-            *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL;
-
-    char 	l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
-    dap_time_t              			l_time_staking		=	0;
-    uint256_t						    l_reinvest_percent	=	{};
-    uint256_t							l_value_delegated	=	{};
-    uint256_t                           l_value_fee     	=	{};
-    uint256_t 							l_value;
-    dap_enc_key_t						*l_key_from;
-    dap_chain_wallet_t					*l_wallet;
-    dap_chain_addr_t					*l_addr_holder;
-    const char                          *l_url_str = NULL;
-    uint16_t                            l_port = 0;
-
-    const char *l_wallet_path = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
-    if (!l_wallet_path) {
-        l_wallet_path =
-        #ifdef DAP_OS_WINDOWS
-                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-        #elif defined DAP_OS_MAC
-                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-        #elif defined DAP_OS_UNIX
-                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-        #endif
-    }  
-
-
-    const char *l_hash_out_type = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
-    if(!l_hash_out_type)
-        l_hash_out_type = "hex";
-    if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type, "base58")) {
-        printf("Error: Invalid hash type argument\n");
-        return -1;
-    }
-
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_name) || NULL == l_net_name) {
-        printf("Error: Missing or invalid network argument\n");
-        return -2;
-    }
-
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_ticker_str) || NULL == l_ticker_str || dap_strlen(l_ticker_str) > 8) {
-        printf("Error: Missing or invalid token argument\n");
-        return -3;
-    }
-
-    if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) {
-        l_url_str = dap_compose_get_net_url(l_net_name);
-    }
-
-    const char *l_port_str = NULL;
-    if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) {
-        l_port = dap_compose_get_net_port(l_net_name);
-    } else {
-        l_port = atoi(l_port_str);
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_name) || NULL == l_net_name) {
+//         printf("Error: Missing or invalid network argument\n");
+//         return -2;
+//     }
 
-    char data[512];
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name);
-    json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
-    if (!l_json_coins) {
-        return -4;
-    }
-    if (!check_token_in_ledger(l_json_coins, l_ticker_str)) {
-        printf("Error: Invalid token '%s'\n", l_ticker_str);
-        return -4;
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_ticker_str) || NULL == l_ticker_str || dap_strlen(l_ticker_str) > 8) {
+//         printf("Error: Missing or invalid token argument\n");
+//         return -3;
+//     }
 
-    if ((!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-coins", &l_coins_str) || NULL == l_coins_str) &&
-            (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-value", &l_coins_str) || NULL == l_coins_str)) {
-        printf("Error: Missing coins or value argument\n");
-        return -5;
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) {
+//         l_url_str = dap_compose_get_net_url(l_net_name);
+//     }
 
-    if (IS_ZERO_256((l_value = dap_chain_balance_scan(l_coins_str)))) {
-        printf("Error: Invalid coins format\n");
-        return -6;
-    }
+//     const char *l_port_str = NULL;
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) {
+//         l_port = dap_compose_get_net_port(l_net_name);
+//     } else {
+//         l_port = atoi(l_port_str);
+//     }
 
-    dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str);
+//     char data[512];
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name);
+//     json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
+//     if (!l_json_coins) {
+//         return -4;
+//     }
+//     if (!check_token_in_ledger(l_json_coins, l_ticker_str)) {
+//         printf("Error: Invalid token '%s'\n", l_ticker_str);
+//         return -4;
+//     }
 
-    if (!check_token_in_ledger(l_json_coins, l_delegated_ticker_str)) {
-        printf("Error: No delegated token found\n");
-        return -7;
-    }
-    json_object_put(l_json_coins);
+//     if ((!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-coins", &l_coins_str) || NULL == l_coins_str) &&
+//             (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-value", &l_coins_str) || NULL == l_coins_str)) {
+//         printf("Error: Missing coins or value argument\n");
+//         return -5;
+//     }
 
-    uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001");  // TODO 16126
-    // uint256_t l_emission_rate = dap_ledger_token_get_emission_rate(l_ledger, l_delegated_ticker_str);
-    // if (IS_ZERO_256(l_emission_rate)) {
-    //     printf("Error: Invalid token emission rate\n");
-    //     return -8;
-    // }
+//     if (IS_ZERO_256((l_value = dap_chain_balance_scan(l_coins_str)))) {
+//         printf("Error: Invalid coins format\n");
+//         return -6;
+//     }
 
-    if (MULT_256_COIN(l_value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) {
-        printf("Error: Invalid coins format\n");
-        return -9;
-    }
+//     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str);
 
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str);
-    if (!l_chain_id_str) {
-        printf("Error: Missing or invalid chain_id argument\n");
-        return -10;
-    }
+//     if (!check_token_in_ledger(l_json_coins, l_delegated_ticker_str)) {
+//         printf("Error: No delegated token found\n");
+//         return -7;
+//     }
+//     json_object_put(l_json_coins);
+
+//     uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001");  // TODO 16126
+//     // uint256_t l_emission_rate = dap_ledger_token_get_emission_rate(l_ledger, l_delegated_ticker_str);
+//     // if (IS_ZERO_256(l_emission_rate)) {
+//     //     printf("Error: Invalid token emission rate\n");
+//     //     return -8;
+//     // }
+
+//     if (MULT_256_COIN(l_value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) {
+//         printf("Error: Invalid coins format\n");
+//         return -9;
+//     }
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) {
-        printf("Error: Missing wallet argument\n");
-        return -11;
-    }
+//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str);
+//     if (!l_chain_id_str) {
+//         printf("Error: Missing or invalid chain_id argument\n");
+//         return -10;
+//     }
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) {
-        printf("Error: Missing fee argument\n");
-        return -12;
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) {
+//         printf("Error: Missing wallet argument\n");
+//         return -11;
+//     }
 
-    if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) {
-        printf("Error: Invalid fee format\n");
-        return -13;
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) {
+//         printf("Error: Missing fee argument\n");
+//         return -12;
+//     }
 
-    // Read time staking
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-time_staking", &l_time_staking_str) || !l_time_staking_str) {
-        printf("Error: Missing time staking argument\n");
-        return -14;
-    }
+//     if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) {
+//         printf("Error: Invalid fee format\n");
+//         return -13;
+//     }
 
-    if (dap_strlen(l_time_staking_str) != 6) {
-        printf("Error: Invalid time staking format\n");
-        return -15;
-    }
+//     // Read time staking
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-time_staking", &l_time_staking_str) || !l_time_staking_str) {
+//         printf("Error: Missing time staking argument\n");
+//         return -14;
+//     }
 
-    char l_time_staking_month_str[3] = {l_time_staking_str[2], l_time_staking_str[3], 0};
-    int l_time_staking_month = atoi(l_time_staking_month_str);
-    if (l_time_staking_month < 1 || l_time_staking_month > 12) {
-        printf("Error: Invalid time staking month\n");
-        return -16;
-    }
+//     if (dap_strlen(l_time_staking_str) != 6) {
+//         printf("Error: Invalid time staking format\n");
+//         return -15;
+//     }
 
-    char l_time_staking_day_str[3] = {l_time_staking_str[4], l_time_staking_str[5], 0};
-    int l_time_staking_day = atoi(l_time_staking_day_str);
-    if (l_time_staking_day < 1 || l_time_staking_day > 31) {
-        printf("Error: Invalid time staking day\n");
-        return -17;
-    }
+//     char l_time_staking_month_str[3] = {l_time_staking_str[2], l_time_staking_str[3], 0};
+//     int l_time_staking_month = atoi(l_time_staking_month_str);
+//     if (l_time_staking_month < 1 || l_time_staking_month > 12) {
+//         printf("Error: Invalid time staking month\n");
+//         return -16;
+//     }
 
-    l_time_staking = dap_time_from_str_simplified(l_time_staking_str);
-    if (0 == l_time_staking) {
-        printf("Error: Invalid time staking\n");
-        return -18;
-    }
-    dap_time_t l_time_now = dap_time_now();
-    if (l_time_staking < l_time_now) {
-        printf("Error: Time staking is in the past\n");
-        return -19;
-    }
-    l_time_staking -= l_time_now;
+//     char l_time_staking_day_str[3] = {l_time_staking_str[4], l_time_staking_str[5], 0};
+//     int l_time_staking_day = atoi(l_time_staking_day_str);
+//     if (l_time_staking_day < 1 || l_time_staking_day > 31) {
+//         printf("Error: Invalid time staking day\n");
+//         return -17;
+//     }
 
-    if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-reinvest", &l_reinvest_percent_str) && NULL != l_reinvest_percent_str) {
-        l_reinvest_percent = dap_chain_coins_to_balance(l_reinvest_percent_str);
-        if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1) {
-            printf("Error: Invalid reinvest percentage\n");
-            return -20;
-        }
-        if (IS_ZERO_256(l_reinvest_percent)) {
-            int l_reinvest_percent_int = atoi(l_reinvest_percent_str);
-            if (l_reinvest_percent_int < 0 || l_reinvest_percent_int > 100) {
-                printf("Error: Invalid reinvest percentage\n");
-                return -21;
-            }
-            l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int);
-            MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent);
-        }
-    }
+//     l_time_staking = dap_time_from_str_simplified(l_time_staking_str);
+//     if (0 == l_time_staking) {
+//         printf("Error: Invalid time staking\n");
+//         return -18;
+//     }
+//     dap_time_t l_time_now = dap_time_now();
+//     if (l_time_staking < l_time_now) {
+//         printf("Error: Time staking is in the past\n");
+//         return -19;
+//     }
+//     l_time_staking -= l_time_now;
 
-    if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) {
-        printf("Error: Unable to open wallet '%s'\n", l_wallet_str);
-        return -22;
-    }
+//     if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-reinvest", &l_reinvest_percent_str) && NULL != l_reinvest_percent_str) {
+//         l_reinvest_percent = dap_chain_coins_to_balance(l_reinvest_percent_str);
+//         if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1) {
+//             printf("Error: Invalid reinvest percentage\n");
+//             return -20;
+//         }
+//         if (IS_ZERO_256(l_reinvest_percent)) {
+//             int l_reinvest_percent_int = atoi(l_reinvest_percent_str);
+//             if (l_reinvest_percent_int < 0 || l_reinvest_percent_int > 100) {
+//                 printf("Error: Invalid reinvest percentage\n");
+//                 return -21;
+//             }
+//             l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int);
+//             MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent);
+//         }
+//     }
 
+//     if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) {
+//         printf("Error: Unable to open wallet '%s'\n", l_wallet_str);
+//         return -22;
+//     }
 
-    if (NULL == (l_addr_holder = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)))) {
-        dap_chain_wallet_close(l_wallet);
-        printf("Error: Unable to get wallet address for '%s'\n", l_wallet_str);
-        return -24;
-    }
 
-    snprintf(data, sizeof(data), 
-        "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
-        dap_chain_addr_to_str(l_addr_holder), l_net_name);
-    DAP_DEL_Z(l_addr_holder);
+//     if (NULL == (l_addr_holder = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)))) {
+//         dap_chain_wallet_close(l_wallet);
+//         printf("Error: Unable to get wallet address for '%s'\n", l_wallet_str);
+//         return -24;
+//     }
 
-    json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
-    uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str);
-    json_object_put(l_json_outs);
-    if (compare256(l_value_balance, l_value) == -1) {
-        dap_chain_wallet_close(l_wallet);
-        printf("Error: Insufficient funds in wallet\n");
-        return -23;
-    }
+//     snprintf(data, sizeof(data), 
+//         "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
+//         dap_chain_addr_to_str(l_addr_holder), l_net_name);
+//     DAP_DEL_Z(l_addr_holder);
+
+//     json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
+//     uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str);
+//     json_object_put(l_json_outs);
+//     if (compare256(l_value_balance, l_value) == -1) {
+//         dap_chain_wallet_close(l_wallet);
+//         printf("Error: Insufficient funds in wallet\n");
+//         return -23;
+//     }
 
-    l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
+//     l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
 
-    // Make transfer transaction
-    dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_net_name, l_key_from,
-                                                           l_ticker_str, l_value, l_value_fee,
-                                                           l_time_staking, l_reinvest_percent,
-                                                           l_delegated_ticker_str, l_value_delegated, l_chain_id_str, l_url_str, l_port);
+//     // Make transfer transaction
+//     dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_net_name, l_key_from,
+//                                                            l_ticker_str, l_value, l_value_fee,
+//                                                            l_time_staking, l_reinvest_percent,
+//                                                            l_delegated_ticker_str, l_value_delegated, l_chain_id_str, l_url_str, l_port);
 
-    json_object * l_json_obj_ret = json_object_new_object();
-    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-    printf("%s", json_object_to_json_string(l_json_obj_ret));
-    json_object_put(l_json_obj_ret);
-    dap_chain_datum_tx_delete(l_tx);
+//     json_object * l_json_obj_ret = json_object_new_object();
+//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+//     printf("%s", json_object_to_json_string(l_json_obj_ret));
+//     json_object_put(l_json_obj_ret);
+//     dap_chain_datum_tx_delete(l_tx);
 
-    dap_chain_wallet_close(l_wallet);
-    dap_enc_key_delete(l_key_from);
+//     dap_chain_wallet_close(l_wallet);
+//     dap_enc_key_delete(l_key_from);
     
-    return 0;
-}
-
-
-dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
-                                                    const char *a_main_ticker,
-                                                    uint256_t a_value, uint256_t a_value_fee,
-                                                    dap_time_t a_time_staking, uint256_t a_reinvest_percent,
-                                                    const char *a_delegated_ticker_str, uint256_t a_delegated_value,
-                                                    const char * l_chain_id_str, const char *l_url_str, uint16_t l_port)
-{
-    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
-    // check valid param
-    if (!a_net_name || !a_key_from ||
-        !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value))
-        return NULL;
-
-    const char *l_native_ticker = s_get_native_ticker(a_net_name);
-    bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker);
-    // find the transactions from which to take away coins
-    uint256_t l_value_transfer = {}; // how many coins to transfer
-    uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
-    dap_chain_addr_t * l_addr_fee = NULL;
-    dap_chain_addr_t l_addr = {};
-
-    dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name));
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port);
-    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
-
-    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port);
-    if (!l_outs_native) {
-        return NULL;
-    }
+//     return 0;
+// }
 
-    json_object *l_outs_main = NULL;
-    if (!dap_strcmp(a_main_ticker, l_native_ticker)) {
-        l_outs_main = l_outs_native;
-    } else {
-        l_outs_main = dap_get_remote_tx_outs(a_main_ticker, a_net_name, &l_addr, l_url_str, l_port);
-    }
-    int l_out_native_count = json_object_array_length(l_outs_native);
-    int l_out_main_count = json_object_array_length(l_outs_main);
 
-    dap_list_t *l_list_fee_out = NULL;
-    if (l_main_native)
-        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
-    else if (!IS_ZERO_256(l_total_fee)) {
-        l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
-                                                               l_total_fee, 
-                                                               &l_fee_transfer);
-        if (!l_list_fee_out) {
-            printf("Not enough funds to pay fee");
-            json_object_put(l_outs_native);
-            json_object_put(l_outs_main);
-            return NULL;
-        }
-    }
-    // list of transaction with 'out' items
-    dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_main, l_out_main_count,
-                                                            l_value_need,
-                                                            &l_value_transfer);
-    if (!l_list_used_out) {
-        printf("Not enough funds to transfer");
-        json_object_put(l_outs_native);
-        json_object_put(l_outs_main);
-        return NULL;
-    }
+// dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
+//                                                     const char *a_main_ticker,
+//                                                     uint256_t a_value, uint256_t a_value_fee,
+//                                                     dap_time_t a_time_staking, uint256_t a_reinvest_percent,
+//                                                     const char *a_delegated_ticker_str, uint256_t a_delegated_value,
+//                                                     const char * l_chain_id_str, const char *l_url_str, uint16_t l_port)
+// {
+//     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
+//     // check valid param
+//     if (!a_net_name || !a_key_from ||
+//         !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value))
+//         return NULL;
+
+//     const char *l_native_ticker = s_get_native_ticker(a_net_name);
+//     bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker);
+//     // find the transactions from which to take away coins
+//     uint256_t l_value_transfer = {}; // how many coins to transfer
+//     uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
+//     dap_chain_addr_t * l_addr_fee = NULL;
+//     dap_chain_addr_t l_addr = {};
+
+//     dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name));
+//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port);
+//     SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
+
+//     json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port);
+//     if (!l_outs_native) {
+//         return NULL;
+//     }
 
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+//     json_object *l_outs_main = NULL;
+//     if (!dap_strcmp(a_main_ticker, l_native_ticker)) {
+//         l_outs_main = l_outs_native;
+//     } else {
+//         l_outs_main = dap_get_remote_tx_outs(a_main_ticker, a_net_name, &l_addr, l_url_str, l_port);
+//     }
+//     int l_out_native_count = json_object_array_length(l_outs_native);
+//     int l_out_main_count = json_object_array_length(l_outs_main);
+
+//     dap_list_t *l_list_fee_out = NULL;
+//     if (l_main_native)
+//         SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+//     else if (!IS_ZERO_256(l_total_fee)) {
+//         l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+//                                                                l_total_fee, 
+//                                                                &l_fee_transfer);
+//         if (!l_list_fee_out) {
+//             printf("Not enough funds to pay fee");
+//             json_object_put(l_outs_native);
+//             json_object_put(l_outs_main);
+//             return NULL;
+//         }
+//     }
+//     // list of transaction with 'out' items
+//     dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_main, l_out_main_count,
+//                                                             l_value_need,
+//                                                             &l_value_transfer);
+//     if (!l_list_used_out) {
+//         printf("Not enough funds to transfer");
+//         json_object_put(l_outs_native);
+//         json_object_put(l_outs_main);
+//         return NULL;
+//     }
 
-    // add 'in' items
-    {
-        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-        assert(EQUAL_256(l_value_to_items, l_value_transfer));
-        dap_list_free_full(l_list_used_out, NULL);
-        if (l_list_fee_out) {
-            uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-            assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
-            dap_list_free_full(l_list_fee_out, NULL);
-        }
-    }
+//     // create empty transaction
+//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
+//     // add 'in' items
+//     {
+//         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+//         assert(EQUAL_256(l_value_to_items, l_value_transfer));
+//         dap_list_free_full(l_list_used_out, NULL);
+//         if (l_list_fee_out) {
+//             uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+//             assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+//             dap_list_free_full(l_list_fee_out, NULL);
+//         }
+//     }
 
-    // add 'in_ems' item
-    {
-        dap_chain_id_t l_chain_id = { };
-        dap_chain_id_parse(l_chain_id_str, &l_chain_id);
-        dap_hash_fast_t l_blank_hash = {};
-        dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(l_chain_id, &l_blank_hash, a_delegated_ticker_str);
-        dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems);
-    }
+//     // add 'in_ems' item
+//     {
+//         dap_chain_id_t l_chain_id = { };
+//         dap_chain_id_parse(l_chain_id_str, &l_chain_id);
+//         dap_hash_fast_t l_blank_hash = {};
+//         dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(l_chain_id, &l_blank_hash, a_delegated_ticker_str);
+//         dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems);
+//     }
 
-    // add 'out_cond' and 'out_ext' items
-    {
-        uint256_t l_value_pack = {}, l_native_pack = {}; // how much coin add to 'out_ext' items
-        dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock(
-                                                        l_uid, a_value, a_time_staking, a_reinvest_percent);
-        if (l_tx_out_cond) {
-            SUM_256_256(l_value_pack, a_value, &l_value_pack);
-            dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond);
-            DAP_DEL_Z(l_tx_out_cond);
-        } else {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Error: Cant add conditional output\n");
-            return NULL;
-        }
+//     // add 'out_cond' and 'out_ext' items
+//     {
+//         uint256_t l_value_pack = {}, l_native_pack = {}; // how much coin add to 'out_ext' items
+//         dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock(
+//                                                         l_uid, a_value, a_time_staking, a_reinvest_percent);
+//         if (l_tx_out_cond) {
+//             SUM_256_256(l_value_pack, a_value, &l_value_pack);
+//             dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond);
+//             DAP_DEL_Z(l_tx_out_cond);
+//         } else {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Error: Cant add conditional output\n");
+//             return NULL;
+//         }
 
-        uint256_t l_value_back = {};
-        // Network fee
-        if (l_net_fee_used) {
-            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Error: Cant add network fee output\n");
-                return NULL;
-            }
-            if (l_main_native)
-                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-            else
-                SUM_256_256(l_native_pack, l_net_fee, &l_native_pack);
-        }
-        // Validator's fee
-        if (!IS_ZERO_256(a_value_fee)) {
-            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Error: Cant add validator's fee output\n");
-                return NULL;
-            }
-            if (l_main_native)
-                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
-            else
-                SUM_256_256(l_native_pack, a_value_fee, &l_native_pack);
-        }
-        // coin back
-        SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-        if (!IS_ZERO_256(l_value_back)) {
-            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Error: Cant add coin back output for main ticker\n");
-                return NULL;
-            }
-        }
-        // fee coin back
-        if (!IS_ZERO_256(l_fee_transfer)) {
-            SUBTRACT_256_256(l_fee_transfer, l_native_pack, &l_value_back);
-            if (!IS_ZERO_256(l_value_back)) {
-                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker) != 1) {
-                    dap_chain_datum_tx_delete(l_tx);
-                    printf("Error: Cant add coin back output for native ticker\n");
-                    return NULL;
-                }
-            }
-        }
-    }
+//         uint256_t l_value_back = {};
+//         // Network fee
+//         if (l_net_fee_used) {
+//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Error: Cant add network fee output\n");
+//                 return NULL;
+//             }
+//             if (l_main_native)
+//                 SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+//             else
+//                 SUM_256_256(l_native_pack, l_net_fee, &l_native_pack);
+//         }
+//         // Validator's fee
+//         if (!IS_ZERO_256(a_value_fee)) {
+//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Error: Cant add validator's fee output\n");
+//                 return NULL;
+//             }
+//             if (l_main_native)
+//                 SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+//             else
+//                 SUM_256_256(l_native_pack, a_value_fee, &l_native_pack);
+//         }
+//         // coin back
+//         SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+//         if (!IS_ZERO_256(l_value_back)) {
+//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Error: Cant add coin back output for main ticker\n");
+//                 return NULL;
+//             }
+//         }
+//         // fee coin back
+//         if (!IS_ZERO_256(l_fee_transfer)) {
+//             SUBTRACT_256_256(l_fee_transfer, l_native_pack, &l_value_back);
+//             if (!IS_ZERO_256(l_value_back)) {
+//                 if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker) != 1) {
+//                     dap_chain_datum_tx_delete(l_tx);
+//                     printf("Error: Cant add coin back output for native ticker\n");
+//                     return NULL;
+//                 }
+//             }
+//         }
+//     }
 
-    // add delegated token emission 'out_ext'
-    if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_delegated_value, a_delegated_ticker_str) != 1) {
-        dap_chain_datum_tx_delete(l_tx);
-        printf("Error: Cant add delegated token emission output\n");
-        return NULL;
-    }
+//     // add delegated token emission 'out_ext'
+//     if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_delegated_value, a_delegated_ticker_str) != 1) {
+//         dap_chain_datum_tx_delete(l_tx);
+//         printf("Error: Cant add delegated token emission output\n");
+//         return NULL;
+//     }
 
-    return l_tx;
-}
+//     return l_tx;
+// }
 
 
-int dap_cli_take_compose(int a_argc, char **a_argv)
-{
-    int arg_index = 1;
-    const char *l_net_str, *l_ticker_str, *l_wallet_str, *l_tx_str, *l_tx_burning_str, *l_chain_id_str, *l_value_fee_str;
-    l_net_str = l_ticker_str = l_wallet_str = l_tx_str = l_tx_burning_str = l_chain_id_str = l_value_fee_str = NULL;
-    char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
-    int									l_prev_cond_idx		=	0;
-    uint256_t							l_value_delegated	= 	{};
-    uint256_t                           l_value_fee     	=	{};
-    dap_chain_wallet_t					*l_wallet;
-    dap_hash_fast_t						l_tx_hash;
-    dap_chain_tx_out_cond_t				*l_cond_tx = NULL;
-    dap_enc_key_t						*l_owner_key;
-    const char                          *l_url_str = NULL;
-    uint16_t                            l_port = 0;
-
-
-    const char *l_wallet_path = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
-    if (!l_wallet_path) {
-        l_wallet_path =
-        #ifdef DAP_OS_WINDOWS
-                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-        #elif defined DAP_OS_MAC
-                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-        #elif defined DAP_OS_UNIX
-                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-        #endif
-    }  
-
-
-    const char *l_hash_out_type = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
-    if (!l_hash_out_type)
-        l_hash_out_type = "hex";
-    if (dap_strcmp(l_hash_out_type, "hex") && dap_strcmp(l_hash_out_type, "base58")) {
-        printf("Error: Invalid hash type argument\n");
-        return -1;
-    }
+// int dap_cli_take_compose(int a_argc, char **a_argv)
+// {
+//     int arg_index = 1;
+//     const char *l_net_str, *l_ticker_str, *l_wallet_str, *l_tx_str, *l_tx_burning_str, *l_chain_id_str, *l_value_fee_str;
+//     l_net_str = l_ticker_str = l_wallet_str = l_tx_str = l_tx_burning_str = l_chain_id_str = l_value_fee_str = NULL;
+//     char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
+//     int									l_prev_cond_idx		=	0;
+//     uint256_t							l_value_delegated	= 	{};
+//     uint256_t                           l_value_fee     	=	{};
+//     dap_chain_wallet_t					*l_wallet;
+//     dap_hash_fast_t						l_tx_hash;
+//     dap_chain_tx_out_cond_t				*l_cond_tx = NULL;
+//     dap_enc_key_t						*l_owner_key;
+//     const char                          *l_url_str = NULL;
+//     uint16_t                            l_port = 0;
+
+
+//     const char *l_wallet_path = NULL;
+//     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
+//     if (!l_wallet_path) {
+//         l_wallet_path =
+//         #ifdef DAP_OS_WINDOWS
+//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+//         #elif defined DAP_OS_MAC
+//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+//         #elif defined DAP_OS_UNIX
+//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+//         #endif
+//     }  
+
+
+//     const char *l_hash_out_type = NULL;
+//     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
+//     if (!l_hash_out_type)
+//         l_hash_out_type = "hex";
+//     if (dap_strcmp(l_hash_out_type, "hex") && dap_strcmp(l_hash_out_type, "base58")) {
+//         printf("Error: Invalid hash type argument\n");
+//         return -1;
+//     }
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str) || NULL == l_net_str) {
-        printf("Error: Missing or invalid network argument\n");
-        return -2;
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str) || NULL == l_net_str) {
+//         printf("Error: Missing or invalid network argument\n");
+//         return -2;
+//     }
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) {
-        l_url_str = dap_compose_get_net_url(l_net_str);
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) {
+//         l_url_str = dap_compose_get_net_url(l_net_str);
+//     }
 
-    const char *l_port_str = NULL;
-    if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) {
-        l_port = dap_compose_get_net_port(l_net_str);
-    } else {
-        l_port = atoi(l_port_str);
-    }
+//     const char *l_port_str = NULL;
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) {
+//         l_port = dap_compose_get_net_port(l_net_str);
+//     } else {
+//         l_port = atoi(l_port_str);
+//     }
 
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str);
-    if (!l_chain_id_str) {
-        printf("Error: Missing or invalid chain_id argument\n");
-        return -10;
-    }
+//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str);
+//     if (!l_chain_id_str) {
+//         printf("Error: Missing or invalid chain_id argument\n");
+//         return -10;
+//     }
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_str) || NULL == l_tx_str) {
-        printf("Error: Missing or invalid transaction argument\n");
-        return -5;
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_str) || NULL == l_tx_str) {
+//         printf("Error: Missing or invalid transaction argument\n");
+//         return -5;
+//     }
 
-    if (dap_chain_hash_fast_from_str(l_tx_str, &l_tx_hash)) {
-        printf("Error: Invalid transaction hash\n");
-        return -6;
-    }
+//     if (dap_chain_hash_fast_from_str(l_tx_str, &l_tx_hash)) {
+//         printf("Error: Invalid transaction hash\n");
+//         return -6;
+//     }
 
-    char data[512];
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-            l_tx_str, l_net_str);
+//     char data[512];
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+//             l_tx_str, l_net_str);
     
-    json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
-    if (!response) {
-        printf("Error: Failed to get response from remote node\n");
-        return -15;
-    }
+//     json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+//     if (!response) {
+//         printf("Error: Failed to get response from remote node\n");
+//         return -15;
+//     }
     
-    json_object *items = NULL;
-    json_object *items_array = json_object_array_get_idx(response, 0);
-    if (items_array) {
-        items = json_object_object_get(items_array, "ITEMS");
-    }
-    if (!items) {
-        printf("Error: No items found in response\n");
-        return -16;
-    }
-    int items_count = json_object_array_length(items);
-    for (int i = 0; i < items_count; i++) {
-        json_object *item = json_object_array_get_idx(items, i);
-        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
-        if (dap_strcmp(item_type, "OUT COND") == 0) {
-            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
-            if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK")) {
-                l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
-                l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
-                l_cond_tx->header.value =  dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
-                l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK;
-                l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
-                l_cond_tx->subtype.srv_stake_lock.time_unlock =  dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "time_unlock")));
-                break;
-            }
-        }
-    }
-    if (!l_cond_tx) {
-        printf("Error: No transaction output condition found\n");
-        return -7;
-    }
+//     json_object *items = NULL;
+//     json_object *items_array = json_object_array_get_idx(response, 0);
+//     if (items_array) {
+//         items = json_object_object_get(items_array, "ITEMS");
+//     }
+//     if (!items) {
+//         printf("Error: No items found in response\n");
+//         return -16;
+//     }
+//     int items_count = json_object_array_length(items);
+//     for (int i = 0; i < items_count; i++) {
+//         json_object *item = json_object_array_get_idx(items, i);
+//         const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+//         if (dap_strcmp(item_type, "OUT COND") == 0) {
+//             const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+//             if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK")) {
+//                 l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+//                 l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+//                 l_cond_tx->header.value =  dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+//                 l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK;
+//                 l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+//                 l_cond_tx->subtype.srv_stake_lock.time_unlock =  dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "time_unlock")));
+//                 break;
+//             }
+//         }
+//     }
+//     if (!l_cond_tx) {
+//         printf("Error: No transaction output condition found\n");
+//         return -7;
+//     }
 
 
-    json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
-    const char *spent_outs_value = json_object_get_string(spent_outs);
-    if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
-        printf("Error: Transaction output item already used\n");
-        return -9;
-    }
-
-    json_object *response_header_array = json_object_array_get_idx(response, 0);
-    if (!response_header_array) {
-        printf("Error: Failed to get items array from response\n");
-        return -10;
-    }
+//     json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
+//     const char *spent_outs_value = json_object_get_string(spent_outs);
+//     if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
+//         printf("Error: Transaction output item already used\n");
+//         return -9;
+//     }
 
-    json_object *token_ticker_obj = json_object_object_get(response_header_array, "token ticker");
-    if (!token_ticker_obj) {
-        printf("Error: Token ticker not found in response\n");
-        return -11;
-    }
-    l_ticker_str = json_object_get_string(token_ticker_obj);
+//     json_object *response_header_array = json_object_array_get_idx(response, 0);
+//     if (!response_header_array) {
+//         printf("Error: Failed to get items array from response\n");
+//         return -10;
+//     }
 
+//     json_object *token_ticker_obj = json_object_object_get(response_header_array, "token ticker");
+//     if (!token_ticker_obj) {
+//         printf("Error: Token ticker not found in response\n");
+//         return -11;
+//     }
+//     l_ticker_str = json_object_get_string(token_ticker_obj);
 
 
-    dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str);
 
-    uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001");
+//     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str);
 
-    if (IS_ZERO_256(l_emission_rate) ||
-        MULT_256_COIN(l_cond_tx->header.value, l_emission_rate, &l_value_delegated) ||
-        IS_ZERO_256(l_value_delegated)) {
-        printf("Error: Invalid coins format\n");
-        return -12;
-    }
+//     uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001");
 
+//     if (IS_ZERO_256(l_emission_rate) ||
+//         MULT_256_COIN(l_cond_tx->header.value, l_emission_rate, &l_value_delegated) ||
+//         IS_ZERO_256(l_value_delegated)) {
+//         printf("Error: Invalid coins format\n");
+//         return -12;
+//     }
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) {
-        printf("Error: Missing or invalid wallet argument\n");
-        return -13;
-    }
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) {
-        printf("Error: Missing or invalid fee argument\n");
-        return -14;
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) {
+//         printf("Error: Missing or invalid wallet argument\n");
+//         return -13;
+//     }
 
-    if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) {
-        printf("Error: Invalid fee format\n");
-        return -15;
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) {
+//         printf("Error: Missing or invalid fee argument\n");
+//         return -14;
+//     }
 
-    if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) {
-        printf("Error: Unable to open wallet\n");
-        return -16;
-    }
+//     if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) {
+//         printf("Error: Invalid fee format\n");
+//         return -15;
+//     }
 
-    if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) {
-        dap_chain_wallet_close(l_wallet);
-        printf("Error: Owner key not found\n");
-        return -17;
-    }
+//     if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) {
+//         printf("Error: Unable to open wallet\n");
+//         return -16;
+//     }
 
-    if (l_cond_tx->subtype.srv_stake_lock.time_unlock > dap_time_now()) {
-        dap_chain_wallet_close(l_wallet);
-        dap_enc_key_delete(l_owner_key);
-        printf("Error: Not enough time has passed for unlocking\n");
-        return -19;
-    }
-    dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_net_str, l_owner_key, &l_tx_hash, l_prev_cond_idx,
-                                          l_ticker_str, l_cond_tx->header.value, l_value_fee,
-                                          l_delegated_ticker_str, l_value_delegated, l_url_str, l_port);
+//     if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) {
+//         dap_chain_wallet_close(l_wallet);
+//         printf("Error: Owner key not found\n");
+//         return -17;
+//     }
 
-    json_object * l_json_obj_ret = json_object_new_object();
-    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-    printf("%s", json_object_to_json_string(l_json_obj_ret));
-    json_object_put(l_json_obj_ret);
+//     if (l_cond_tx->subtype.srv_stake_lock.time_unlock > dap_time_now()) {
+//         dap_chain_wallet_close(l_wallet);
+//         dap_enc_key_delete(l_owner_key);
+//         printf("Error: Not enough time has passed for unlocking\n");
+//         return -19;
+//     }
+//     dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_net_str, l_owner_key, &l_tx_hash, l_prev_cond_idx,
+//                                           l_ticker_str, l_cond_tx->header.value, l_value_fee,
+//                                           l_delegated_ticker_str, l_value_delegated, l_url_str, l_port);
 
+//     json_object * l_json_obj_ret = json_object_new_object();
+//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+//     printf("%s", json_object_to_json_string(l_json_obj_ret));
+//     json_object_put(l_json_obj_ret);
 
-    dap_chain_datum_tx_delete(l_tx);
-    dap_enc_key_delete(l_owner_key);
 
-    return 0;
-}
+//     dap_chain_datum_tx_delete(l_tx);
+//     dap_enc_key_delete(l_owner_key);
 
-dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
-                                               dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
-                                               const char *a_main_ticker, uint256_t a_value,
-                                               uint256_t a_value_fee,
-                                               const char *a_delegated_ticker_str, uint256_t a_delegated_value,
-                                               const char *l_url_str, uint16_t l_port)
-{
-    // check valid param
-    if (!a_net_name | !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) {
-        printf("Error: Invalid parameters\n");
-        return NULL;
-    }
+//     return 0;
+// }
 
-    const char *l_native_ticker = s_get_native_ticker(a_net_name);
-    bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker);
-    // find the transactions from which to take away coins
-    uint256_t l_value_transfer = {}; // how many coins to transfer
-    uint256_t l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
-    dap_chain_addr_t* l_addr_fee = NULL;
-    dap_chain_addr_t l_addr = {};
+// dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
+//                                                dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
+//                                                const char *a_main_ticker, uint256_t a_value,
+//                                                uint256_t a_value_fee,
+//                                                const char *a_delegated_ticker_str, uint256_t a_delegated_value,
+//                                                const char *l_url_str, uint16_t l_port)
+// {
+//     // check valid param
+//     if (!a_net_name | !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) {
+//         printf("Error: Invalid parameters\n");
+//         return NULL;
+//     }
 
-    dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name));
-    dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL;
+//     const char *l_native_ticker = s_get_native_ticker(a_net_name);
+//     bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker);
+//     // find the transactions from which to take away coins
+//     uint256_t l_value_transfer = {}; // how many coins to transfer
+//     uint256_t l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
+//     dap_chain_addr_t* l_addr_fee = NULL;
+//     dap_chain_addr_t l_addr = {};
 
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port);
+//     dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name));
+//     dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL;
 
-    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port);
-    if (!l_outs_native) {
-        return NULL;
-    }
+//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port);
 
-    json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, a_net_name, &l_addr, l_url_str, l_port);
-    if (!l_outs_delegated) {
-        return NULL;
-    }
+//     json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port);
+//     if (!l_outs_native) {
+//         return NULL;
+//     }
 
-    int l_out_native_count = json_object_array_length(l_outs_native);
-    int l_out_delegated_count = json_object_array_length(l_outs_delegated);
+//     json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, a_net_name, &l_addr, l_url_str, l_port);
+//     if (!l_outs_delegated) {
+//         return NULL;
+//     }
 
-    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
-    if (!IS_ZERO_256(l_total_fee)) {
-        if (!l_main_native) {
-            l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
-                                                                l_total_fee, 
-                                                                &l_fee_transfer);
-            if (!l_list_fee_out) {
-                printf("Not enough funds to pay fee");
-                json_object_put(l_outs_native);
-                json_object_put(l_outs_delegated);
-                return NULL;
-            }
-        } else if (compare256(a_value, l_total_fee) == -1) {
-            printf("Error: Total fee more than stake\n");
-            return NULL;
-        }
-    }
-    if (!IS_ZERO_256(a_delegated_value)) {
-        l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count,
-                                                               a_delegated_value, 
-                                                               &l_value_transfer);
-        if (!l_list_used_out) {
-            printf("Not enough funds to pay fee");
-            json_object_put(l_outs_native);
-            json_object_put(l_outs_delegated);
-            return NULL;
-        }
-    }
+//     int l_out_native_count = json_object_array_length(l_outs_native);
+//     int l_out_delegated_count = json_object_array_length(l_outs_delegated);
+
+//     SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
+//     if (!IS_ZERO_256(l_total_fee)) {
+//         if (!l_main_native) {
+//             l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+//                                                                 l_total_fee, 
+//                                                                 &l_fee_transfer);
+//             if (!l_list_fee_out) {
+//                 printf("Not enough funds to pay fee");
+//                 json_object_put(l_outs_native);
+//                 json_object_put(l_outs_delegated);
+//                 return NULL;
+//             }
+//         } else if (compare256(a_value, l_total_fee) == -1) {
+//             printf("Error: Total fee more than stake\n");
+//             return NULL;
+//         }
+//     }
+//     if (!IS_ZERO_256(a_delegated_value)) {
+//         l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count,
+//                                                                a_delegated_value, 
+//                                                                &l_value_transfer);
+//         if (!l_list_used_out) {
+//             printf("Not enough funds to pay fee");
+//             json_object_put(l_outs_native);
+//             json_object_put(l_outs_delegated);
+//             return NULL;
+//         }
+//     }
 
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+//     // create empty transaction
+//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
-    // add 'in_cond' & 'in' items
-    {
-        dap_chain_datum_tx_add_in_cond_item(&l_tx, a_stake_tx_hash, a_prev_cond_idx, 0);
-        if (l_list_used_out) {
-            uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-            assert(EQUAL_256(l_value_to_items, l_value_transfer));
-            dap_list_free_full(l_list_used_out, NULL);
-        }
-        if (l_list_fee_out) {
-            uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-            assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
-            dap_list_free_full(l_list_fee_out, NULL);
-        }
-    }
+//     // add 'in_cond' & 'in' items
+//     {
+//         dap_chain_datum_tx_add_in_cond_item(&l_tx, a_stake_tx_hash, a_prev_cond_idx, 0);
+//         if (l_list_used_out) {
+//             uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+//             assert(EQUAL_256(l_value_to_items, l_value_transfer));
+//             dap_list_free_full(l_list_used_out, NULL);
+//         }
+//         if (l_list_fee_out) {
+//             uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+//             assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+//             dap_list_free_full(l_list_fee_out, NULL);
+//         }
+//     }
 
-    // add 'out_ext' items
-    uint256_t l_value_back;
-    {
-        uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
-        // Network fee
-        if(l_net_fee_used){
-            if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker)){
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Error: Can't add network fee output\n");
-                return NULL;
-            }
-            SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-        }
-        // Validator's fee
-        if (!IS_ZERO_256(a_value_fee)) {
-            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
-            {
-                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
-            }
-            else {
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Error: Can't add validator's fee output\n");
-                return NULL;
-            }
-        }
-        // coin back
-        //SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back);
-        if(l_main_native){
-            if (SUBTRACT_256_256(a_value, l_value_pack, &l_value_back)) {
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Error: Can't subtract value pack from value\n");
-                return NULL;
-            }
-            if(!IS_ZERO_256(l_value_back)) {
-                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker)!=1) {
-                    dap_chain_datum_tx_delete(l_tx);
-                    printf("Error: Can't add coin back output for main ticker\n");
-                    return NULL;
-                }
-            }
-        } else {
-            SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back);
-            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_value, a_main_ticker)!=1) {
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Error: Can't add coin back output for main ticker\n");
-                return NULL;
-            }
-            else
-            {
-                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker)!=1) {
-                    dap_chain_datum_tx_delete(l_tx);
-                    printf("Error: Can't add coin back output for native ticker\n");
-                    return NULL;
-                }
-            }
-        }
-    }
+//     // add 'out_ext' items
+//     uint256_t l_value_back;
+//     {
+//         uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
+//         // Network fee
+//         if(l_net_fee_used){
+//             if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker)){
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Error: Can't add network fee output\n");
+//                 return NULL;
+//             }
+//             SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+//         }
+//         // Validator's fee
+//         if (!IS_ZERO_256(a_value_fee)) {
+//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+//             {
+//                 SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+//             }
+//             else {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Error: Can't add validator's fee output\n");
+//                 return NULL;
+//             }
+//         }
+//         // coin back
+//         //SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back);
+//         if(l_main_native){
+//             if (SUBTRACT_256_256(a_value, l_value_pack, &l_value_back)) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Error: Can't subtract value pack from value\n");
+//                 return NULL;
+//             }
+//             if(!IS_ZERO_256(l_value_back)) {
+//                 if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker)!=1) {
+//                     dap_chain_datum_tx_delete(l_tx);
+//                     printf("Error: Can't add coin back output for main ticker\n");
+//                     return NULL;
+//                 }
+//             }
+//         } else {
+//             SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back);
+//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_value, a_main_ticker)!=1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Error: Can't add coin back output for main ticker\n");
+//                 return NULL;
+//             }
+//             else
+//             {
+//                 if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker)!=1) {
+//                     dap_chain_datum_tx_delete(l_tx);
+//                     printf("Error: Can't add coin back output for native ticker\n");
+//                     return NULL;
+//                 }
+//             }
+//         }
+//     }
 
-    // add burning 'out_ext'
-    if (!IS_ZERO_256(a_delegated_value)) {
-        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &c_dap_chain_addr_blank,
-                                               a_delegated_value, a_delegated_ticker_str) != 1) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Error: Can't add burning output for delegated value\n");
-            return NULL;
-        }
-        // delegated token coin back
-        SUBTRACT_256_256(l_value_transfer, a_delegated_value, &l_value_back);
-        if (!IS_ZERO_256(l_value_back)) {
-            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_delegated_ticker_str) != 1) {
-                dap_chain_datum_tx_delete(l_tx);
-                printf("Error: Can't add coin back output for delegated ticker\n");
-                return NULL;
-            }
-        }
-    }
+//     // add burning 'out_ext'
+//     if (!IS_ZERO_256(a_delegated_value)) {
+//         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &c_dap_chain_addr_blank,
+//                                                a_delegated_value, a_delegated_ticker_str) != 1) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Error: Can't add burning output for delegated value\n");
+//             return NULL;
+//         }
+//         // delegated token coin back
+//         SUBTRACT_256_256(l_value_transfer, a_delegated_value, &l_value_back);
+//         if (!IS_ZERO_256(l_value_back)) {
+//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_delegated_ticker_str) != 1) {
+//                 dap_chain_datum_tx_delete(l_tx);
+//                 printf("Error: Can't add coin back output for delegated ticker\n");
+//                 return NULL;
+//             }
+//         }
+//     }
 
-    return l_tx;
-}
+//     return l_tx;
+// }
 
-uint256_t s_get_key_delegating_min_value(const char *a_net_str, const char *l_url_str, uint16_t l_port){
+uint256_t s_get_key_delegating_min_value(compose_config_t *a_config){
     uint256_t l_key_delegating_min_value = uint256_0;
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", 
-            a_net_str);
+            a_config->net_name);
     
-    json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+    json_object *response = dap_request_command_to_rpc(data, a_config);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return l_key_delegating_min_value;
@@ -2375,320 +2415,320 @@ uint256_t s_get_key_delegating_min_value(const char *a_net_str, const char *l_ur
 }
 
 
-int dap_cli_voting_compose(int a_argc, char **a_argv)
-{
-    int arg_index = 1;
-    const char* l_question_str = NULL;
-    const char* l_options_list_str = NULL;
-    const char* l_voting_expire_str = NULL;
-    const char* l_max_votes_count_str = NULL;
-    const char* l_fee_str = NULL;
-    const char* l_wallet_str = NULL;
-    const char* l_net_str = NULL;
-    const char* l_token_str = NULL;
-    const char* l_url_str = NULL;
-    uint16_t l_port = 0;
-    const char *l_wallet_path = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
-    if (!l_wallet_path) {
-        l_wallet_path =
-        #ifdef DAP_OS_WINDOWS
-                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-        #elif defined DAP_OS_MAC
-                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-        #elif defined DAP_OS_UNIX
-                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-        #endif
-    }  
+// int dap_cli_voting_compose(int a_argc, char **a_argv)
+// {
+//     int arg_index = 1;
+//     const char* l_question_str = NULL;
+//     const char* l_options_list_str = NULL;
+//     const char* l_voting_expire_str = NULL;
+//     const char* l_max_votes_count_str = NULL;
+//     const char* l_fee_str = NULL;
+//     const char* l_wallet_str = NULL;
+//     const char* l_net_str = NULL;
+//     const char* l_token_str = NULL;
+//     const char* l_url_str = NULL;
+//     uint16_t l_port = 0;
+//     const char *l_wallet_path = NULL;
+//     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
+//     if (!l_wallet_path) {
+//         l_wallet_path =
+//         #ifdef DAP_OS_WINDOWS
+//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+//         #elif defined DAP_OS_MAC
+//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+//         #elif defined DAP_OS_UNIX
+//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+//         #endif
+//     }  
     
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
-    // Select chain network
-    if(!l_net_str) {
-        printf("Voting requires parameter '-net' to be valid.\n");
-        return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING;
-    }
+//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
+//     // Select chain network
+//     if(!l_net_str) {
+//         printf("Voting requires parameter '-net' to be valid.\n");
+//         return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING;
+//     }
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-url", &l_url_str)) {
-        l_url_str = dap_compose_get_net_url(l_net_str);
-    }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-url", &l_url_str)) {
+//         l_url_str = dap_compose_get_net_url(l_net_str);
+//     }
 
-    const char *l_port_str = NULL;
-    if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str)) {
-        l_port = dap_compose_get_net_port(l_net_str);
-    } else {
-        l_port = atoi(l_port_str);
-    }
+//     const char *l_port_str = NULL;
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str)) {
+//         l_port = dap_compose_get_net_port(l_net_str);
+//     } else {
+//         l_port = atoi(l_port_str);
+//     }
 
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str);
-    if (!l_question_str){
-        printf("Voting requires a question parameter to be valid.\n");
-        return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_PARAM_MISSING;
-    }
+//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str);
+//     if (!l_question_str){
+//         printf("Voting requires a question parameter to be valid.\n");
+//         return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_PARAM_MISSING;
+//     }
 
-    if (strlen(l_question_str) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
-        printf("The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH);
-        return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_CONTAIN_MAX_CHARACTERS;
-    }
+//     if (strlen(l_question_str) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
+//         printf("The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH);
+//         return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_CONTAIN_MAX_CHARACTERS;
+//     }
 
-    dap_list_t *l_options_list = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-options", &l_options_list_str);
-    if (!l_options_list_str){
-        printf("Voting requires a question parameter to be valid.\n");
-        return -DAP_CHAIN_NET_VOTE_CREATE_OPTION_PARAM_MISSING;
-    }
-    // Parse options list
-    l_options_list = dap_get_options_list_from_str(l_options_list_str);
-    if(!l_options_list || dap_list_length(l_options_list) < 2){
-        printf("Number of options must be 2 or greater.\n");
-        return -DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR;
-    }
+//     dap_list_t *l_options_list = NULL;
+//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-options", &l_options_list_str);
+//     if (!l_options_list_str){
+//         printf("Voting requires a question parameter to be valid.\n");
+//         return -DAP_CHAIN_NET_VOTE_CREATE_OPTION_PARAM_MISSING;
+//     }
+//     // Parse options list
+//     l_options_list = dap_get_options_list_from_str(l_options_list_str);
+//     if(!l_options_list || dap_list_length(l_options_list) < 2){
+//         printf("Number of options must be 2 or greater.\n");
+//         return -DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR;
+//     }
 
-    if(dap_list_length(l_options_list)>DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){
-        printf("The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT);            
-        return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS;
-    }
+//     if(dap_list_length(l_options_list)>DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){
+//         printf("The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT);            
+//         return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS;
+//     }
 
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str);
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str);
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str);
-    if (!l_fee_str){
-        printf("Voting requires parameter -fee to be valid.\n");
-        return -DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID;
-    }
-    uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str);
+//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str);
+//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str);
+//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str);
+//     if (!l_fee_str){
+//         printf("Voting requires parameter -fee to be valid.\n");
+//         return -DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID;
+//     }
+//     uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str);
 
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str);
-    if (!l_wallet_str){
-        printf("Voting requires parameter -w to be valid.\n");
-        return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID;
-    }
+//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str);
+//     if (!l_wallet_str){
+//         printf("Voting requires parameter -w to be valid.\n");
+//         return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID;
+//     }
 
-    dap_time_t l_time_expire = 0;
-    if (l_voting_expire_str)
-        l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str);
-    if (l_voting_expire_str && !l_time_expire){
-        printf("Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"\n");
-        return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT;
-    }
-    uint64_t l_max_count = 0;
-    if (l_max_votes_count_str)
-        l_max_count = strtoul(l_max_votes_count_str, NULL, 10);
-
-    bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false;
-    bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false;
-    dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
-    if (!l_wallet_fee) {
-        printf("Wallet %s does not exist\n", l_wallet_str);
-        return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
-    }
+//     dap_time_t l_time_expire = 0;
+//     if (l_voting_expire_str)
+//         l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str);
+//     if (l_voting_expire_str && !l_time_expire){
+//         printf("Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"\n");
+//         return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT;
+//     }
+//     uint64_t l_max_count = 0;
+//     if (l_max_votes_count_str)
+//         l_max_count = strtoul(l_max_votes_count_str, NULL, 10);
+
+//     bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false;
+//     bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false;
+//     dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
+//     if (!l_wallet_fee) {
+//         printf("Wallet %s does not exist\n", l_wallet_str);
+//         return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
+//     }
 
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str);
-    if (!l_token_str) {
-        printf("Command required -token argument");
-        return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
-    }
+//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str);
+//     if (!l_token_str) {
+//         printf("Command required -token argument");
+//         return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
+//     }
         
-    char data[512];
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str);
-    json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
-    if (!l_json_coins) {
-        printf("Error: Can't get ledger coins list\n");
-        return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
-    }
-    if (!check_token_in_ledger(l_json_coins, l_token_str)) {
-        json_object_put(l_json_coins);
-        printf("Token %s does not exist\n", l_token_str);
-        return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN;
-    }
-    json_object_put(l_json_coins);
-
-    dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count,
-                                                                l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, 
-                                                                l_wallet_fee, l_net_str, l_token_str, l_url_str, l_port);
-    dap_list_free(l_options_list);
-    dap_chain_wallet_close(l_wallet_fee);
-    json_object * l_json_obj_ret = json_object_new_object();
-    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-    printf("%s", json_object_to_json_string(l_json_obj_ret));
-    json_object_put(l_json_obj_ret);
-    return 0;
-}
+//     char data[512];
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str);
+//     json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+//     if (!l_json_coins) {
+//         printf("Error: Can't get ledger coins list\n");
+//         return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
+//     }
+//     if (!check_token_in_ledger(l_json_coins, l_token_str)) {
+//         json_object_put(l_json_coins);
+//         printf("Token %s does not exist\n", l_token_str);
+//         return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN;
+//     }
+//     json_object_put(l_json_coins);
+
+//     dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count,
+//                                                                 l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, 
+//                                                                 l_wallet_fee, l_net_str, l_token_str, l_url_str, l_port);
+//     dap_list_free(l_options_list);
+//     dap_chain_wallet_close(l_wallet_fee);
+//     json_object * l_json_obj_ret = json_object_new_object();
+//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+//     printf("%s", json_object_to_json_string(l_json_obj_ret));
+//     json_object_put(l_json_obj_ret);
+//     return 0;
+// }
 
 
-dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
-                              uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
-                              bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
-                              const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port) {
+// dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
+//                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
+//                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
+//                               const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port) {
 
-    if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
-        return NULL;
-    }
+//     if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
+//         return NULL;
+//     }
 
-    // Parse options list
+//     // Parse options list
 
-    if(dap_list_length(a_options) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){
-        return NULL;
-    }
+//     if(dap_list_length(a_options) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){
+//         return NULL;
+//     }
 
-    if (IS_ZERO_256(a_fee)) {
-        return NULL;
-    }
+//     if (IS_ZERO_256(a_fee)) {
+//         return NULL;
+//     }
 
-    dap_chain_addr_t *l_addr_from =  dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str));
+//     dap_chain_addr_t *l_addr_from =  dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str));
 
-    if(!l_addr_from) {
-        return NULL;
-    }
+//     if(!l_addr_from) {
+//         return NULL;
+//     }
 
-    const char *l_native_ticker = s_get_native_ticker(a_net_str);
-    uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer;
-    dap_chain_addr_t *l_addr_fee = NULL;
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port);
-    SUM_256_256(l_net_fee, a_fee, &l_total_fee);
+//     const char *l_native_ticker = s_get_native_ticker(a_net_str);
+//     uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer;
+//     dap_chain_addr_t *l_addr_fee = NULL;
+//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port);
+//     SUM_256_256(l_net_fee, a_fee, &l_total_fee);
 
-    json_object *l_outs = NULL;
-    int l_outputs_count = 0;
-    if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count, l_url_str, l_port)) {
-        return NULL;
-    }
+//     json_object *l_outs = NULL;
+//     int l_outputs_count = 0;
+//     if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count, l_url_str, l_port)) {
+//         return NULL;
+//     }
 
-    dap_list_t *l_list_used_out = NULL;
-    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
-                                                            l_total_fee,
-                                                            &l_value_transfer);
+//     dap_list_t *l_list_used_out = NULL;
+//     l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+//                                                             l_total_fee,
+//                                                             &l_value_transfer);
 
-    json_object_put(l_outs);
-    if (!l_list_used_out) {
-        printf("Not enough funds to transfer");
-        return NULL;
-    }
+//     json_object_put(l_outs);
+//     if (!l_list_used_out) {
+//         printf("Not enough funds to transfer");
+//         return NULL;
+//     }
 
 
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+//     // create empty transaction
+//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
-    // Add Voting item
-    dap_chain_tx_voting_t* l_voting_item = dap_chain_datum_tx_item_voting_create();
+//     // Add Voting item
+//     dap_chain_tx_voting_t* l_voting_item = dap_chain_datum_tx_item_voting_create();
 
-    dap_chain_datum_tx_add_item(&l_tx, l_voting_item);
-    DAP_DELETE(l_voting_item);
+//     dap_chain_datum_tx_add_item(&l_tx, l_voting_item);
+//     DAP_DELETE(l_voting_item);
 
-    // Add question to tsd data
-    dap_chain_tx_tsd_t* l_question_tsd = dap_chain_datum_voting_question_tsd_create(a_question, strlen(a_question));
-    dap_chain_datum_tx_add_item(&l_tx, l_question_tsd);
+//     // Add question to tsd data
+//     dap_chain_tx_tsd_t* l_question_tsd = dap_chain_datum_voting_question_tsd_create(a_question, strlen(a_question));
+//     dap_chain_datum_tx_add_item(&l_tx, l_question_tsd);
 
-    // Add options to tsd
-    dap_list_t *l_temp = a_options;
-    while(l_temp){
-        if(strlen((char*)l_temp->data) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH){
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-        dap_chain_tx_tsd_t* l_option = dap_chain_datum_voting_answer_tsd_create((char*)l_temp->data, strlen((char*)l_temp->data));
-        if(!l_option){
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-        dap_chain_datum_tx_add_item(&l_tx, l_option);
-        DAP_DEL_Z(l_option);
+//     // Add options to tsd
+//     dap_list_t *l_temp = a_options;
+//     while(l_temp){
+//         if(strlen((char*)l_temp->data) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH){
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
+//         dap_chain_tx_tsd_t* l_option = dap_chain_datum_voting_answer_tsd_create((char*)l_temp->data, strlen((char*)l_temp->data));
+//         if(!l_option){
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
+//         dap_chain_datum_tx_add_item(&l_tx, l_option);
+//         DAP_DEL_Z(l_option);
 
-        l_temp = l_temp->next;
-    }
+//         l_temp = l_temp->next;
+//     }
 
-    // add voting expire time if needed
-    if(a_expire_vote != 0){
-        dap_time_t l_expired_vote = a_expire_vote;
-        if (l_expired_vote < dap_time_now()){
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
+//     // add voting expire time if needed
+//     if(a_expire_vote != 0){
+//         dap_time_t l_expired_vote = a_expire_vote;
+//         if (l_expired_vote < dap_time_now()){
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
 
-        dap_chain_tx_tsd_t* l_expired_item = dap_chain_datum_voting_expire_tsd_create(l_expired_vote);
-        if(!l_expired_item){
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-        dap_chain_datum_tx_add_item(&l_tx, l_expired_item);
-        DAP_DEL_Z(l_expired_item);
-    }
+//         dap_chain_tx_tsd_t* l_expired_item = dap_chain_datum_voting_expire_tsd_create(l_expired_vote);
+//         if(!l_expired_item){
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
+//         dap_chain_datum_tx_add_item(&l_tx, l_expired_item);
+//         DAP_DEL_Z(l_expired_item);
+//     }
 
-    // Add vote max count if needed
-    if (a_max_vote != 0) {
-        dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote);
-        if(!l_max_votes_item){
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-        dap_chain_datum_tx_add_item(&l_tx, l_max_votes_item);
-        DAP_DEL_Z(l_max_votes_item);
-    }
+//     // Add vote max count if needed
+//     if (a_max_vote != 0) {
+//         dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote);
+//         if(!l_max_votes_item){
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
+//         dap_chain_datum_tx_add_item(&l_tx, l_max_votes_item);
+//         DAP_DEL_Z(l_max_votes_item);
+//     }
 
-    if (a_delegated_key_required) {
-        dap_chain_tx_tsd_t* l_delegated_key_req_item = dap_chain_datum_voting_delegated_key_required_tsd_create(true);
-        if(!l_delegated_key_req_item){
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-        dap_chain_datum_tx_add_item(&l_tx, l_delegated_key_req_item);
-        DAP_DEL_Z(l_delegated_key_req_item);
-    }
+//     if (a_delegated_key_required) {
+//         dap_chain_tx_tsd_t* l_delegated_key_req_item = dap_chain_datum_voting_delegated_key_required_tsd_create(true);
+//         if(!l_delegated_key_req_item){
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
+//         dap_chain_datum_tx_add_item(&l_tx, l_delegated_key_req_item);
+//         DAP_DEL_Z(l_delegated_key_req_item);
+//     }
 
-    if(a_vote_changing_allowed){
-        dap_chain_tx_tsd_t* l_vote_changing_item = dap_chain_datum_voting_vote_changing_allowed_tsd_create(true);
-        if(!l_vote_changing_item){
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-        dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item);
-        DAP_DEL_Z(l_vote_changing_item);
-    }
-    if (a_token_ticker) {
-        dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker);
-        if (!l_voting_token_item) {
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-        dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item);
-        DAP_DEL_Z(l_voting_token_item);
-    }
+//     if(a_vote_changing_allowed){
+//         dap_chain_tx_tsd_t* l_vote_changing_item = dap_chain_datum_voting_vote_changing_allowed_tsd_create(true);
+//         if(!l_vote_changing_item){
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
+//         dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item);
+//         DAP_DEL_Z(l_vote_changing_item);
+//     }
+//     if (a_token_ticker) {
+//         dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker);
+//         if (!l_voting_token_item) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
+//         dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item);
+//         DAP_DEL_Z(l_voting_token_item);
+//     }
 
-    // add 'in' items
-    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-    assert(EQUAL_256(l_value_to_items, l_value_transfer));
-    dap_list_free_full(l_list_used_out, NULL);
-    uint256_t l_value_pack = {};
-    // Network fee
-    if (l_net_fee_used) {
-        if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
-            SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-        else {
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-    }
-    // Validator's fee
-    if (!IS_ZERO_256(a_fee)) {
-        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1)
-            SUM_256_256(l_value_pack, a_fee, &l_value_pack);
-        else {
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-    }
-    // coin back
-    uint256_t l_value_back;
-    SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-    if(!IS_ZERO_256(l_value_back)) {
-        if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) {
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-    }
+//     // add 'in' items
+//     uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+//     assert(EQUAL_256(l_value_to_items, l_value_transfer));
+//     dap_list_free_full(l_list_used_out, NULL);
+//     uint256_t l_value_pack = {};
+//     // Network fee
+//     if (l_net_fee_used) {
+//         if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
+//             SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+//         else {
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
+//     }
+//     // Validator's fee
+//     if (!IS_ZERO_256(a_fee)) {
+//         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1)
+//             SUM_256_256(l_value_pack, a_fee, &l_value_pack);
+//         else {
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
+//     }
+//     // coin back
+//     uint256_t l_value_back;
+//     SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+//     if(!IS_ZERO_256(l_value_back)) {
+//         if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             return NULL;
+//         }
+//     }
 
 
-    return l_tx;
-}
+//     return l_tx;
+// }
 
 /**
 int dap_cli_vote_compose(int a_argc, char **a_argv){
@@ -3024,7 +3064,7 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
 json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
                         const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port)
 {
-    json_object* l_json_obj_ret = json_object_new_object();
+    compose_config_t* l_config = s_compose_config_init(a_net_str, a_url_str, a_port);
     dap_hash_fast_t l_tx_hash = {};
     if (a_tx_hash_str) {
         dap_chain_hash_fast_from_str(a_tx_hash_str, &l_tx_hash);
@@ -3033,27 +3073,26 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c
         if (a_cert_str) {
             dap_cert_t *l_cert = dap_cert_find_by_name(a_cert_str);
             if (!l_cert) {
-                dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND, "Specified certificate not found");
-                return l_json_obj_ret;
+                dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND, "Specified certificate not found");
+                return s_compose_config_return_response_handler(l_config);
             }
             if (!l_cert->enc_key->priv_key_data || l_cert->enc_key->priv_key_data_size == 0) {
-                dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING, "Private key missing in certificate");
-                return l_json_obj_ret;
+                dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING, "Private key missing in certificate");
+                return s_compose_config_return_response_handler(l_config);
             }
             if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, s_get_net_id(a_net_str))) {
-                dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_WRONG_CERT, "Wrong certificate");
-                return l_json_obj_ret;
+                dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_WRONG_CERT, "Wrong certificate");
+                return s_compose_config_return_response_handler(l_config);
             }
         }
         const char *l_addr_str = dap_chain_addr_to_str_static(&l_signing_addr);
 
         char data[512];
         snprintf(data, sizeof(data), 
-                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str);
-        json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
+                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", l_config->net_name);
+        json_object *l_json_coins = dap_request_command_to_rpc(data, l_config);
         if (!l_json_coins) {
-            dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger");
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
         
         int items_count = json_object_array_length(l_json_coins);
@@ -3065,8 +3104,8 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c
                 const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash"));
                 if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) {
                     json_object_put(l_json_coins);
-                    dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format");
-                    return l_json_obj_ret;
+                    dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format");
+                    return s_compose_config_return_response_handler(l_config);
                 }
                 found = true;
                 break;
@@ -3074,8 +3113,8 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c
         }
         json_object_put(l_json_coins);
         if (!found) {
-            dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED, "Specified certificate/pkey hash is not delegated");
-            return l_json_obj_ret;
+            dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED, "Specified certificate/pkey hash is not delegated");
+            return s_compose_config_return_response_handler(l_config);
         }
     }
 
@@ -3083,11 +3122,10 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c
 
     char data[512];
     snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, a_net_str);
-    json_object *l_json_response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_config->net_name);
+    json_object *l_json_response = dap_request_command_to_rpc(data, l_config);
     if (!l_json_response) {
-        dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger");
-        return l_json_obj_ret;
+        return s_compose_config_return_response_handler(l_config);
     }
 
     json_object *l_json_items = json_object_array_get_idx(l_json_response, 0);
@@ -3110,8 +3148,8 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c
 
     if (!has_delegate_out) {
         json_object_put(l_json_response);
-        dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT, "No delegate output found in transaction");
-        return l_json_obj_ret;
+        dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT, "No delegate output found in transaction");
+        return s_compose_config_return_response_handler(l_config);
     }
 
     json_object *l_json_spents = json_object_object_get(l_json_response, "Spent OUTs");
@@ -3123,17 +3161,17 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c
             if (spent_by_tx) {
                 if (dap_chain_hash_fast_from_str(spent_by_tx, &l_tx_hash)) {
                     json_object_put(l_json_response);
-                    dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format");
-                    return l_json_obj_ret;
+                    dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format");
+                    return s_compose_config_return_response_handler(l_config);
                 }
                 l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash);
                 snprintf(data, sizeof(data), 
-                        "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, a_net_str);
-                json_object *l_json_prev_tx = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
+                        "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_config->net_name);
+                json_object *l_json_prev_tx = dap_request_command_to_rpc(data, l_config);
                 if (!l_json_prev_tx) {
                     json_object_put(l_json_response);
-                    dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND, "Previous transaction not found");
-                    return l_json_obj_ret;
+                    dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND, "Previous transaction not found");
+                    return s_compose_config_return_response_handler(l_config);
                 }
                 json_object_put(l_json_prev_tx);
                 break; 
@@ -3145,11 +3183,10 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c
     if (a_tx_hash_str) {
         char data[512];
         snprintf(data, sizeof(data), 
-                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", a_net_str);
-        json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
+                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", l_config->net_name);
+        json_object *l_json_coins = dap_request_command_to_rpc(data, l_config);
         if (!l_json_coins) {
-            dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger");
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
 
         bool tx_exists = false;
@@ -3159,8 +3196,8 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c
             const char *tx_hash = json_object_get_string(json_object_object_get(tx_item, "tx_hash"));
             if (tx_hash && strcmp(tx_hash, l_tx_hash_str_tmp) == 0) {
                 json_object_put(l_json_coins);
-                dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_TX_EXISTS, "Transaction already exists");
-                return l_json_obj_ret;
+                dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_TX_EXISTS, "Transaction already exists");
+                return s_compose_config_return_response_handler(l_config);
             }
         }
         json_object_put(l_json_coins);
@@ -3169,40 +3206,40 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c
 
     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path,NULL);
     if (!l_wallet) {
-        dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND, "Specified wallet not found");
-        return l_json_obj_ret;
+        dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND, "Specified wallet not found");
+        return s_compose_config_return_response_handler(l_config);
     }
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
-    dap_chain_datum_tx_t *l_tx = dap_stake_tx_invalidate_compose(a_net_str, &l_tx_hash, a_fee, l_enc_key, a_url_str, a_port, l_json_obj_ret);
+    dap_chain_datum_tx_t *l_tx = dap_stake_tx_invalidate_compose(&l_tx_hash, a_fee, l_enc_key, l_config);
     if (l_tx) {
-        dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+        dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
         DAP_DELETE(l_tx);
     }
 
     dap_chain_wallet_close(l_wallet);
     dap_enc_key_delete(l_enc_key);
-    return l_json_obj_ret;
+    return s_compose_config_return_response_handler(l_config);
 }
 
-dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, json_object *a_error_handler)
+dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, compose_config_t *a_config)
 {
-    if(!a_net_str || !*a_net_str || !a_tx_hash || !a_key || !l_url_str || !*l_url_str || l_port == 0)
+    if(!a_config || !a_config->net_name || !*a_config->net_name || !a_tx_hash || !a_key || !a_config->url_str || !*a_config->url_str || a_config->port == 0)
         return NULL;
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-need_sign;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-            dap_hash_fast_to_str_static(a_tx_hash), a_net_str);
+            dap_hash_fast_to_str_static(a_tx_hash), a_config->net_name);
     
-    json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+    json_object *response = dap_request_command_to_rpc(data, a_config);
     if (!response) {
-        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR, "Failed to get ledger info");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR, "Failed to get ledger info");
         return NULL;
     }
     json_object *l_items_array = json_object_array_get_idx(response, 0);
     l_items_array = json_object_object_get(l_items_array, "ITEMS");
     if (!l_items_array) {
         json_object_put(response);
-        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND, "Items not found in ledger response");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND, "Items not found in ledger response");
         return NULL;
     }
 
@@ -3211,7 +3248,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         const char *all_unspent = json_object_get_string(l_unspent_outs);
         if (all_unspent && strcmp(all_unspent, "yes") == 0) {
             json_object_put(response);
-            if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT, "All outputs are already spent");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT, "All outputs are already spent");
             return NULL;
         }
     }
@@ -3234,19 +3271,19 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             if (!l_tx_prev_hash) {
                 json_object_put(response);
                 DAP_DELETE(l_tx_out_cond);
-                if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND, "Previous transaction hash not found");
+                dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND, "Previous transaction hash not found");
                 return NULL;
             }
             l_prev_cond_idx = json_object_get_int(json_object_object_get(l_item, "Tx_out_prev_idx"));
             snprintf(data, sizeof(data), 
                     "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-                    l_tx_prev_hash, a_net_str);
+                    l_tx_prev_hash, a_config->net_name);
             
-            json_object *response_cond = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+            json_object *response_cond = dap_request_command_to_rpc(data, a_config);
             if (!response_cond) {
                 json_object_put(response);
                 DAP_DELETE(l_tx_out_cond);
-                if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR, "Failed to get conditional transaction info");
+                dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR, "Failed to get conditional transaction info");
                 return NULL;
             }
             json_object_put(response_cond);
@@ -3256,7 +3293,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (!l_tx_out_cond || !l_tx_prev_hash) {
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
-        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND, "Conditional transaction not found");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND, "Conditional transaction not found");
         return NULL;
     }
 
@@ -3273,7 +3310,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (!l_sig_item) {
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
-        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND, "Signature item not found");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND, "Signature item not found");
         return NULL;
     }
 
@@ -3281,7 +3318,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     if (!l_sign_b64_str) {
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
-        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR, "Failed to decode signature");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR, "Failed to decode signature");
         return NULL;
     }
 
@@ -3297,18 +3334,18 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
 
     dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
     dap_chain_addr_t l_owner_addr;
-    dap_chain_addr_fill_from_sign(&l_owner_addr, l_sign, s_get_net_id(a_net_str));
+    dap_chain_addr_fill_from_sign(&l_owner_addr, l_sign, s_get_net_id(a_config->net_name));
     dap_chain_addr_t l_wallet_addr;
-    dap_chain_addr_fill_from_key(&l_wallet_addr, a_key, s_get_net_id(a_net_str));
+    dap_chain_addr_fill_from_key(&l_wallet_addr, a_key, s_get_net_id(a_config->net_name));
     if (!dap_chain_addr_compare(&l_owner_addr, &l_wallet_addr)) {
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
-        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER, "Wrong transaction owner");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER, "Wrong transaction owner");
         return NULL;
     }
     
-    const char *l_native_ticker = s_get_native_ticker(a_net_str);
+    const char *l_native_ticker = s_get_native_ticker(a_config->net_name);
 
     json_object *l_json_tiker = json_object_array_get_idx(response, 0);
     json_object *token_ticker_obj = json_object_object_get(l_json_tiker, "Token_ticker");
@@ -3318,18 +3355,18 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
-            if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND, "Token ticker not found");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND, "Token ticker not found");
             return NULL;
         }
     }
     const char *l_delegated_ticker = json_object_get_string(token_ticker_obj);
 
-    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
+    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, &l_owner_addr, a_config);
     if (!l_outs_native) {
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
-        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND, "Transaction outputs not found");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND, "Transaction outputs not found");
         return NULL;
     }
 
@@ -3338,7 +3375,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
     // list of transaction with 'out' items to sell
     uint256_t l_net_fee, l_fee_total = a_fee;
     dap_chain_addr_t*l_net_fee_addr = NULL;
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_net_fee_addr, l_url_str, l_port);
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_net_fee_addr, a_config);
     if (l_net_fee_used)
         SUM_256_256(l_fee_total, l_net_fee, &l_fee_total);
     dap_list_t *l_list_fee_out = NULL; 
@@ -3350,7 +3387,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
-        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS, "Not enough funds to pay fees");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS, "Not enough funds to pay fees");
         return NULL;
     }
 
@@ -3369,7 +3406,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
-        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR, "Error adding input items");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR, "Error adding input items");
         return NULL;
     }
 
@@ -3380,7 +3417,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
         json_object_put(response);
         DAP_DELETE(l_tx_out_cond);
         DAP_DELETE(l_tx_sig);
-        if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR, "Error adding output items");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR, "Error adding output items");
         return NULL;
     }
     // add fee items
@@ -3391,7 +3428,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
-            if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR, "Error adding network fee");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR, "Error adding network fee");
             return NULL;
         }
     }
@@ -3402,7 +3439,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
-            if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR, "Error adding fee");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR, "Error adding fee");
             return NULL;
         }
     }
@@ -3416,7 +3453,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap
             json_object_put(response);
             DAP_DELETE(l_tx_out_cond);
             DAP_DELETE(l_tx_sig);
-            if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR, "Error adding fee back");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR, "Error adding fee back");
             return NULL;
         }
     }
@@ -3486,44 +3523,43 @@ dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, con
     return l_order;
 }
 
-dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax,
+dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_order_hash_str, uint256_t* a_tax,
                                                     uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax,
-                                                    const char* l_url_str, uint16_t l_port){
+                                                    compose_config_t *a_config){
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", 
-            l_net_str);
-    json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+            a_config->net_name);
+    json_object *response = dap_request_command_to_rpc(data, a_config);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return NULL;
     }
 
-    dap_chain_net_srv_order_t *l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response);
+    dap_chain_net_srv_order_t *l_order = dap_check_remote_srv_order(a_config->net_name, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response);
     json_object_put(response);
 
     if (!l_order) {
         snprintf(data, sizeof(data), 
                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", 
-                l_net_str);
-        response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+                a_config->net_name);
+        response = dap_request_command_to_rpc(data, a_config);
         if (!response) {
             printf("Error: Failed to get response from remote node\n");
             return NULL;
         }
-        l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response);
+        l_order = dap_check_remote_srv_order(a_config->net_name, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response);
         json_object_put(response);
     }
     return l_order;
 }
 
-dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_order_hash_str,
-                                                    const char* l_url_str, uint16_t l_port){
+dap_sign_t* dap_get_remote_srv_order_sign(const char* l_order_hash_str, compose_config_t *a_config){
     char data[512];
     snprintf(data, sizeof(data), 
             "{\"method\": \"net_srv\",\"params\": [\"net_srv;-net;%s;order;dump;-hash;%s;-need_sign\"],\"id\": \"1\"}", 
-            l_net_str, l_order_hash_str);
-    json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
+            a_config->net_name, l_order_hash_str);
+    json_object *response = dap_request_command_to_rpc(data, a_config);
     if (!response) {
         printf("Error: Failed to get response from remote node\n");
         return NULL;
@@ -3565,11 +3601,11 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o
 json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
                                         const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, 
                                         const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path) {
-    json_object* l_json_obj_ret = json_object_new_object();
+    compose_config_t *l_config = s_compose_config_init(a_net_str, a_url_str, a_port);
     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallets_path, NULL);
     if (!l_wallet) {
-        dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND, "Specified wallet not found");
-        return l_json_obj_ret;
+        dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND, "Specified wallet not found");
+        return l_config->response_handler;
     }
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
     dap_chain_wallet_close(l_wallet);
@@ -3579,9 +3615,9 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha
     if (a_value_str) {
         l_value = dap_chain_balance_scan(a_value_str);
         if (IS_ZERO_256(l_value)) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-value' param");
+            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-value' param");
             dap_enc_key_delete(l_enc_key);
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
     }
     dap_pkey_t *l_pkey = NULL;
@@ -3589,39 +3625,39 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha
     if (a_cert_str) {
         dap_cert_t *l_signing_cert = dap_cert_find_by_name(a_cert_str);
         if (!l_signing_cert) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND, "Specified certificate not found");
+            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND, "Specified certificate not found");
             dap_enc_key_delete(l_enc_key);
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
         if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(a_net_str))) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG, "Specified certificate is wrong");
+            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG, "Specified certificate is wrong");
             dap_enc_key_delete(l_enc_key);
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
         l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key);
     }  else if (a_pkey_full_str) {
         dap_sign_type_t l_type = dap_sign_type_from_str(a_sign_type_str);
         if (l_type.type == SIG_TYPE_NULL) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE, "Wrong sign type");
+            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE, "Wrong sign type");
             dap_enc_key_delete(l_enc_key);
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
         l_pkey = dap_pkey_get_from_str(a_pkey_full_str);
         if (!l_pkey) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey string format, can't get pkey_full");
+            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey string format, can't get pkey_full");
             dap_enc_key_delete(l_enc_key);
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
         if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "pkey and sign types is different");
+            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "pkey and sign types is different");
             dap_enc_key_delete(l_enc_key);
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
         dap_chain_hash_fast_t l_hash_public_key = {0};
         if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey hash format");
+            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey hash format");
             dap_enc_key_delete(l_enc_key);
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
         dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(a_net_str));
     }
@@ -3629,34 +3665,34 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha
     dap_chain_node_addr_t l_node_addr = g_node_addr;
     if (a_node_addr_str) {
         if (dap_chain_node_addr_from_str(&l_node_addr, a_node_addr_str)) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Unrecognized node addr %s", a_node_addr_str);
+            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Unrecognized node addr %s", a_node_addr_str);
             dap_enc_key_delete(l_enc_key);
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
     }
     if (a_order_hash_str) {
         uint256_t l_tax;
         uint256_t l_value_max;
         int l_prev_tx_count = 0;
-        dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(a_net_str, a_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, a_url_str, a_port);
+        dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(a_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, l_config);
         if (!l_order) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND, "Error: Failed to get order from remote node");
+            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND, "Error: Failed to get order from remote node");
             dap_enc_key_delete(l_enc_key);
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
         l_sovereign_tax = l_tax;
 
         if (l_order->direction == SERV_DIR_BUY) { // Staker order
             if (!a_cert_str) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED, "Command 'delegate' requires parameter -cert with this order type");
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED, "Command 'delegate' requires parameter -cert with this order type");
                 dap_enc_key_delete(l_enc_key);
-                return l_json_obj_ret;
+                return s_compose_config_return_response_handler(l_config);
             }
             if (l_order->ext_size != 0) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Specified order has invalid size");
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Specified order has invalid size");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return l_json_obj_ret;
+                return s_compose_config_return_response_handler(l_config);
             }
 
             dap_chain_tx_out_cond_t *l_cond_tx = NULL;
@@ -3665,16 +3701,16 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha
                     "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
                     dap_chain_hash_fast_to_str_static(&l_order->tx_cond_hash), a_net_str);
             
-            json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
+            json_object *response = dap_request_command_to_rpc(data, l_config);
             if (!response) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE, "Error: Failed to get response from remote node");
-                return l_json_obj_ret;
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE, "Error: Failed to get response from remote node");
+                return s_compose_config_return_response_handler(l_config);
             }
             
             json_object *items = json_object_object_get(response, "ITEMS");
             if (!items) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS, "Error: No items found in response");
-                return l_json_obj_ret;
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS, "Error: No items found in response");
+                return s_compose_config_return_response_handler(l_config);
             }
             int items_count = json_object_array_length(items);
             for (int i = 0; i < items_count; i++) {
@@ -3691,8 +3727,8 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha
                         l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
                         l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr")));
                         if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) {
-                            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR, "Error: Failed to parse signer node address");
-                            return l_json_obj_ret;
+                            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR, "Error: Failed to parse signer node address");
+                            return s_compose_config_return_response_handler(l_config);
                         }
                         l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
                         l_prev_tx_count++;
@@ -3703,60 +3739,60 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha
                 }
             }
             if (!l_cond_tx) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Error: No transaction output condition found");
-                return l_json_obj_ret;
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Error: No transaction output condition found");
+                return s_compose_config_return_response_handler(l_config);
             }
 
             json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
             const char *spent_outs_value = json_object_get_string(spent_outs);
             if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Error: Transaction output item already used");
-                return l_json_obj_ret;
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Error: Transaction output item already used");
+                return s_compose_config_return_response_handler(l_config);
             }
 
             char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
             dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(a_net_str));
             const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker"));
             if (!l_token_ticker) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER, "Error: Token ticker not found in response");
-                return l_json_obj_ret;
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER, "Error: Token ticker not found in response");
+                return s_compose_config_return_response_handler(l_config);
             }
             json_object_put(response);
             if (dap_strcmp(l_token_ticker, l_delegated_ticker)) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER, "Requested conditional transaction have another ticker (not %s)", l_delegated_ticker);
-                return l_json_obj_ret;
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER, "Requested conditional transaction have another ticker (not %s)", l_delegated_ticker);
+                return s_compose_config_return_response_handler(l_config);
             }
             if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT, "The order's conditional transaction has invalid format");
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT, "The order's conditional transaction has invalid format");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return l_json_obj_ret;
+                return s_compose_config_return_response_handler(l_config);
             }
             if (compare256(l_cond_tx->header.value, l_order->price)) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE, "The order's conditional transaction has different value");
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE, "The order's conditional transaction has different value");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return l_json_obj_ret;
+                return s_compose_config_return_response_handler(l_config);
             }
             if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) ||
                     l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR, "The order's conditional transaction gas not blank address or key");
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR, "The order's conditional transaction gas not blank address or key");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return l_json_obj_ret;
+                return s_compose_config_return_response_handler(l_config);
             }
             l_value = l_order->price;
         } else {
             if (!a_value_str) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED, "Command 'delegate' requires parameter -value with this order type");
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED, "Command 'delegate' requires parameter -value with this order type");
                 dap_enc_key_delete(l_enc_key);
-                return l_json_obj_ret;
+                return s_compose_config_return_response_handler(l_config);
             }
             if (a_sovereign_addr_str) {
                 dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(a_sovereign_addr_str);
                 if (!l_spec_addr) {
-                    dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR, "Specified address is invalid");
-                    return l_json_obj_ret;
+                    dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR, "Specified address is invalid");
+                    return s_compose_config_return_response_handler(l_config);
                 }
                 l_sovereign_addr = *l_spec_addr;
                 DAP_DELETE(l_spec_addr);
@@ -3766,52 +3802,52 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha
             if (a_order_hash_str && compare256(l_value, l_order->price) == -1) {
                 const char *l_coin_min_str, *l_value_min_str =
                     dap_uint256_to_char(l_order->price, &l_coin_min_str);
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW, "Number in '-value' param %s is lower than order minimum allowed value %s(%s)",
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW, "Number in '-value' param %s is lower than order minimum allowed value %s(%s)",
                                                   a_value_str, l_coin_min_str, l_value_min_str);
                 dap_enc_key_delete(l_enc_key);
-                return l_json_obj_ret;
+                return s_compose_config_return_response_handler(l_config);
             }
             if (a_order_hash_str && compare256(l_value, l_value_max) == 1) {
                 const char *l_coin_max_str, *l_value_max_str =
                     dap_uint256_to_char(l_value_max, &l_coin_max_str);
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH, "Number in '-value' param %s is higher than order minimum allowed value %s(%s)",
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH, "Number in '-value' param %s is higher than order minimum allowed value %s(%s)",
                                                   a_value_str, l_coin_max_str, l_value_max_str);
                 dap_enc_key_delete(l_enc_key);
-                return l_json_obj_ret;
+                return s_compose_config_return_response_handler(l_config);
             }
             size_t l_sign_size = 0;
-            dap_sign_t *l_sign = dap_get_remote_srv_order_sign(a_net_str, a_order_hash_str, a_url_str, a_port);
+            dap_sign_t *l_sign = dap_get_remote_srv_order_sign(a_order_hash_str, l_config);
             if (!l_sign) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER, "Specified order is unsigned");
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER, "Specified order is unsigned");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return l_json_obj_ret;
+                return s_compose_config_return_response_handler(l_config);
             }
             dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, s_get_net_id(a_net_str));
             l_pkey = dap_pkey_get_from_sign(l_sign);
             char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX];
             dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, s_get_native_ticker(a_net_str));
             if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) {
-                dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER, "Specified order is invalid");
+                dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER, "Specified order is invalid");
                 dap_enc_key_delete(l_enc_key);
                 DAP_DELETE(l_order);
-                return l_json_obj_ret;
+                return s_compose_config_return_response_handler(l_config);
             }
             l_node_addr = l_order->node_addr;
         }
         DAP_DELETE(l_order);
         if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 ||
                 compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%");
+            dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%");
             dap_enc_key_delete(l_enc_key);
-            return l_json_obj_ret;
+            return s_compose_config_return_response_handler(l_config);
         }
         DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
     }
     if (!l_pkey) {
-        dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED, "pkey not defined");
+        dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED, "pkey not defined");
         dap_enc_key_delete(l_enc_key);
-        return l_json_obj_ret;
+        return s_compose_config_return_response_handler(l_config);
     }
 
     // TODO: need to make sure that the key and node are required verification 
@@ -3823,73 +3859,70 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha
     // }
  
 
-    uint256_t l_allowed_min = s_get_key_delegating_min_value(a_net_str, a_url_str, a_port);
+    uint256_t l_allowed_min = s_get_key_delegating_min_value(l_config);
     if (compare256(l_value, l_allowed_min) == -1) {
         const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str);
-        dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN, "Number in '-value' param %s is lower than minimum allowed value %s(%s)",
+        dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN, "Number in '-value' param %s is lower than minimum allowed value %s(%s)",
                                           a_value_str, l_coin_min_str, l_value_min_str);
         dap_enc_key_delete(l_enc_key);
-        return l_json_obj_ret;
+        return s_compose_config_return_response_handler(l_config);
     }
 
     uint256_t l_fee = dap_chain_balance_scan(a_fee_str);
     if (IS_ZERO_256(l_fee)) {
-        dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-fee' param");
+        dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-fee' param");
         dap_enc_key_delete(l_enc_key);
-        return l_json_obj_ret;
+        return s_compose_config_return_response_handler(l_config);
     }
-    dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(a_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr,
-                                                   a_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, a_url_str, a_port, l_json_obj_ret);
+    dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr,
+                                                   a_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, l_config);
     
     dap_enc_key_delete(l_enc_key);
     DAP_DELETE(l_pkey);
 
     if (l_tx) {
-        dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+        dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
         DAP_DELETE(l_tx);
-    }
+    } 
 
-    return l_json_obj_ret;
+    return s_compose_config_return_response_handler(l_config);
 
 }
 
-dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
+dap_chain_datum_tx_t *dap_stake_tx_create_compose(dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
-                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, json_object *l_error_handle)
+                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, compose_config_t *a_config)
 {
-    if  (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) {
-        if (l_error_handle)
-            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS, "Invalid parameters for transaction creation");
+    if  (!a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS, "Invalid parameters for transaction creation");
         return NULL;
     }
-    const char *l_native_ticker = s_get_native_ticker(a_net_str);
+    const char *l_native_ticker = s_get_native_ticker(a_config->net_name);
     char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker);
     uint256_t l_value_transfer = {}, l_fee_transfer = {}; 
     // list of transaction with 'out' items to sell
     dap_chain_addr_t l_owner_addr;
-    dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str));
+    dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_config->net_name));
     uint256_t l_net_fee, l_fee_total = a_fee;
     dap_chain_addr_t * l_net_fee_addr = NULL;
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_net_fee_addr, l_url_str, l_port);
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_net_fee_addr, a_config);
     if (l_net_fee_used)
         SUM_256_256(l_fee_total, l_net_fee, &l_fee_total);
 
     dap_list_t *l_list_fee_out = NULL;
 
-    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
+    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, &l_owner_addr, a_config);
     if (!l_outs_native) {
-        if (l_error_handle)
-            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee");
         return NULL;
     }
 
-    json_object *l_outs_delegated = dap_get_remote_tx_outs(l_delegated_ticker, a_net_str, &l_owner_addr, l_url_str, l_port);
+    json_object *l_outs_delegated = dap_get_remote_tx_outs(l_delegated_ticker, &l_owner_addr, a_config);
     if (!l_outs_delegated) {
-        if (l_error_handle)
-            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value");
         return NULL;
     }
 
@@ -3902,8 +3935,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     if (!l_list_fee_out) {
         json_object_put(l_outs_native);
         json_object_put(l_outs_delegated);
-        if (l_error_handle)
-            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee");
         return NULL;
     }
 
@@ -3917,16 +3949,14 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
         if (!l_list_used_out) {
             json_object_put(l_outs_native);
             json_object_put(l_outs_delegated);
-            if (l_error_handle)
-                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value");
             return NULL;
         }
         // add 'in' items to pay for delegate
         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
         dap_list_free_full(l_list_used_out, NULL);
         if (!EQUAL_256(l_value_to_items, l_value_transfer)) {
-            if (l_error_handle)
-                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input");
             goto tx_fail;
         }
     } else {
@@ -3936,8 +3966,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
         dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num);
         // add 'in' item to buy from conditional transaction
         if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_out_num, -1)) {
-            if (l_error_handle)
-                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input");
             goto tx_fail;
         }
     }
@@ -3945,8 +3974,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
     dap_list_free_full(l_list_fee_out, NULL);
     if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
-        if (l_error_handle)
-            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input");
         goto tx_fail;
     }
 
@@ -3956,8 +3984,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
                                                                                           a_sovereign_addr, a_sovereign_tax, a_pkey);
 
     if (!l_tx_out) {
-        if (l_error_handle)
-            dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR, "Error creating conditional transaction output");
+        dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR, "Error creating conditional transaction output");
         goto tx_fail;
     }
     dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
@@ -3968,8 +3995,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
         SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back);
         if (!IS_ZERO_256(l_value_back)) {
             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) {
-                if (l_error_handle)
-                    dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR, "Error creating transaction output");
+                dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR, "Error creating transaction output");
                 goto tx_fail;
             }
         }
@@ -3978,15 +4004,13 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     // add fee items
     if (l_net_fee_used) {
         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) {
-            if (l_error_handle)
-                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR, "Error with network fee");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR, "Error with network fee");
             goto tx_fail;
         }
     }
     if (!IS_ZERO_256(a_fee)) {
         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
-            if (l_error_handle)
-                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR, "Error with validator fee");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR, "Error with validator fee");
             goto tx_fail;
         }
     }
@@ -3995,8 +4019,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en
     SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back);
     if (!IS_ZERO_256(l_fee_back)) {
         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) {
-            if (l_error_handle)
-                dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR, "Error with fee back");
+            dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR, "Error with fee back");
             goto tx_fail;
         }
     }
@@ -4008,41 +4031,46 @@ tx_fail:
     return NULL;
 }
 
-static dap_chain_datum_tx_t *dap_order_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
+static dap_chain_datum_tx_t *dap_order_tx_create_compose(dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                 uint256_t a_sovereign_tax, dap_chain_addr_t *a_sovereign_addr,
-                                                const char *l_url_str, int l_port, json_object *l_error_handle)
+                                                compose_config_t *a_config)
 {
     dap_chain_node_addr_t l_node_addr = {};
-    return dap_stake_tx_create_compose(a_net_str, a_key, a_value, a_fee,
+    return dap_stake_tx_create_compose(a_key, a_value, a_fee,
                              (dap_chain_addr_t *)&c_dap_chain_addr_blank, &l_node_addr,
-                             a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, l_error_handle);
+                             a_sovereign_addr, a_sovereign_tax, NULL, NULL, a_config);
 }
 
 
 json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) {
-    json_object* l_json_obj_ret = json_object_new_object();
+    compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port);
+    if (!l_config) {
+        json_object *l_json_obj_ret = json_object_new_object();
+        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_PARAMS, "Invalid arguments");
+        return l_json_obj_ret;
+    }
     uint256_t l_value = dap_chain_balance_scan(l_value_str);
     if (IS_ZERO_256(l_value)) {
-        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE, "Format -value <256 bit integer>");
-        return l_json_obj_ret;
+        dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE, "Format -value <256 bit integer>");
+        return s_compose_config_return_response_handler(l_config);
     }
     uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
     if (IS_ZERO_256(l_fee)) {
-        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE, "Format -fee <256 bit integer>");
-        return l_json_obj_ret;
+        dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE, "Format -fee <256 bit integer>");
+        return s_compose_config_return_response_handler(l_config);
     }
     uint256_t l_tax = dap_chain_coins_to_balance(l_tax_str);
     if (compare256(l_tax, dap_chain_coins_to_balance("100.0")) == 1 ||
             compare256(l_tax, GET_256_FROM_64(100)) == -1) {
-        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%");
-        return l_json_obj_ret;
+        dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%");
+        return s_compose_config_return_response_handler(l_config);
     }
 
     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
     if (!l_wallet) {
-        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND, "Specified wallet not found");
-        return l_json_obj_ret;
+        dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND, "Specified wallet not found");
+        return s_compose_config_return_response_handler(l_config);
     }
 
     const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet);
@@ -4050,505 +4078,504 @@ json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str
     dap_chain_wallet_close(l_wallet);
 
     if (!l_enc_key) {
-        dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND, "Failed to retrieve encryption key");
-        return l_json_obj_ret;
+        dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND, "Failed to retrieve encryption key");
+        return s_compose_config_return_response_handler(l_config);
     }
 
     dap_chain_addr_t l_addr = {};
     if (l_addr_str) {
         dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str);
         if (!l_spec_addr) {
-            dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR, "Specified address is invalid");
+            dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR, "Specified address is invalid");
             DAP_DELETE(l_enc_key);
-            return NULL;
+            return s_compose_config_return_response_handler(l_config);
         }
         l_addr = *l_spec_addr;
         DAP_DELETE(l_spec_addr);
     } else
         dap_chain_addr_fill_from_key(&l_addr, l_enc_key, s_get_net_id(l_net_str));
     DIV_256(l_tax, GET_256_FROM_64(100), &l_tax);
-    dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, 
-                                                            &l_addr, l_url_str, l_port, l_json_obj_ret);
+    dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_enc_key, l_value, l_fee, l_tax, &l_addr, l_config);
     DAP_DEL_Z(l_enc_key);
 
     if (l_tx) {
-        dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+        dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
         DAP_DELETE(l_tx);
     }
 
-    return l_json_obj_ret;
+    return s_compose_config_return_response_handler(l_config);
 }
 
-int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) {
-    int l_arg_index = 1;
-    const char * l_order_hash_str = NULL;
-    const char * l_fee_str = NULL;
-    const char * l_net_str = NULL;
-    const char * l_wallet_str = NULL;
-    const char * l_url_str = NULL;
-    const char * l_port_str = NULL;
-    int l_port = 0;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
-    if (!l_net_str) {
-        printf("Command 'order remove' requires parameter -net\n");
-        return -1;
-    }
+// int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) {
+//     int l_arg_index = 1;
+//     const char * l_order_hash_str = NULL;
+//     const char * l_fee_str = NULL;
+//     const char * l_net_str = NULL;
+//     const char * l_wallet_str = NULL;
+//     const char * l_url_str = NULL;
+//     const char * l_port_str = NULL;
+//     int l_port = 0;
+//     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
+//     if (!l_net_str) {
+//         printf("Command 'order remove' requires parameter -net\n");
+//         return -1;
+//     }
 
-        if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
-        l_url_str = dap_compose_get_net_url(l_net_str);
-    }
-    if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
-        l_port = dap_compose_get_net_port(l_net_str);
-    } else {
-        l_port = atoi(l_port_str);
-    }
+//         if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
+//         l_url_str = dap_compose_get_net_url(l_net_str);
+//     }
+//     if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
+//         l_port = dap_compose_get_net_port(l_net_str);
+//     } else {
+//         l_port = atoi(l_port_str);
+//     }
 
-    const char *l_wallet_path = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
-    if (!l_wallet_path) {
-        l_wallet_path =
-        #ifdef DAP_OS_WINDOWS
-                    dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-        #elif defined DAP_OS_MAC
-                    dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-        #elif defined DAP_OS_UNIX
-                    dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-        #endif
-    }  
-
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
-    if (!l_wallet_str) {
-        printf("Command 'order remove' requires parameter -w\n");
-        return -3;
-    }
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
-    if (!l_wallet) {
-        printf("Specified wallet not found\n");
-        return -4;
-    }
-    const char* l_sign_str = dap_chain_wallet_check_sign(l_wallet);
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str);
-    if (!l_order_hash_str) {
-        printf("Command 'order remove' requires parameter -order\n");
-        return -5;
-    }
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
-    if (!l_fee_str) {
-        printf("Command 'order remove' requires parameter -fee\n");
-        return -6;
-    }
-    uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
-    dap_hash_fast_t l_tx_hash = {};
-    dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash);
-    char *l_tx_hash_ret = NULL;
-    dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_remove_compose(l_net_str, &l_tx_hash, l_fee, l_wallet, l_url_str, l_port);
-    dap_chain_wallet_close(l_wallet);
+//     const char *l_wallet_path = NULL;
+//     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
+//     if (!l_wallet_path) {
+//         l_wallet_path =
+//         #ifdef DAP_OS_WINDOWS
+//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
+//         #elif defined DAP_OS_MAC
+//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
+//         #elif defined DAP_OS_UNIX
+//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
+//         #endif
+//     }  
+
+//     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
+//     if (!l_wallet_str) {
+//         printf("Command 'order remove' requires parameter -w\n");
+//         return -3;
+//     }
+//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
+//     if (!l_wallet) {
+//         printf("Specified wallet not found\n");
+//         return -4;
+//     }
+//     const char* l_sign_str = dap_chain_wallet_check_sign(l_wallet);
+//     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str);
+//     if (!l_order_hash_str) {
+//         printf("Command 'order remove' requires parameter -order\n");
+//         return -5;
+//     }
+//     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
+//     if (!l_fee_str) {
+//         printf("Command 'order remove' requires parameter -fee\n");
+//         return -6;
+//     }
+//     uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+//     dap_hash_fast_t l_tx_hash = {};
+//     dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash);
+//     char *l_tx_hash_ret = NULL;
+//     dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_remove_compose(l_net_str, &l_tx_hash, l_fee, l_wallet, l_url_str, l_port);
+//     dap_chain_wallet_close(l_wallet);
     
-    return 0;
-}
+//     return 0;
+// }
 
-bool process_ledger_response(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, 
-                                                dap_chain_hash_fast_t *a_tx_hash, const char *a_url_str, int a_port, dap_chain_hash_fast_t *a_out_hash) {
-    *a_out_hash = *a_tx_hash;
-    int l_prev_tx_count = 0;
-    dap_chain_hash_fast_t l_hash = {};
-    char data[512];
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-            dap_chain_hash_fast_to_str_static(a_tx_hash), a_net_str);
+// bool process_ledger_response(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, 
+//                                                 dap_chain_hash_fast_t *a_tx_hash, const char *a_url_str, int a_port, dap_chain_hash_fast_t *a_out_hash) {
+//     *a_out_hash = *a_tx_hash;
+//     int l_prev_tx_count = 0;
+//     dap_chain_hash_fast_t l_hash = {};
+//     char data[512];
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+//             dap_chain_hash_fast_to_str_static(a_tx_hash), a_net_str);
     
-    json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
-    if (!response) {
-        printf("Error: Failed to get response from remote node\n");
-        return false;
-    }
+//     json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
+//     if (!response) {
+//         printf("Error: Failed to get response from remote node\n");
+//         return false;
+//     }
     
-    json_object *l_response_array = json_object_array_get_idx(response, 0);
-    if (!l_response_array) {
-        printf("Error: Can't get the first element from the response array\n");
-        json_object_put(response);
-        return false;
-    }
+//     json_object *l_response_array = json_object_array_get_idx(response, 0);
+//     if (!l_response_array) {
+//         printf("Error: Can't get the first element from the response array\n");
+//         json_object_put(response);
+//         return false;
+//     }
 
-    json_object *items = json_object_object_get(l_response_array, "ITEMS");
-    if (!items) {
-        printf("Error: No items found in response\n");
-        return false;
-    }
-    bool l_found = false;
-    int items_count = json_object_array_length(items);
-    for (int i = 0; i < items_count; i++) {
-        json_object *item = json_object_array_get_idx(items, i);
-        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
-        if (dap_strcmp(item_type, "OUT COND") == 0) {
-            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
-            if (!dap_strcmp(subtype, dap_chain_tx_out_cond_subtype_to_str(a_cond_type))) {
-                dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(item, "hash")), &l_hash);
-                l_prev_tx_count++;
-                l_found = true;
-                break;
-            }
-        } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) {
-            l_prev_tx_count++;
-        }
-    }
-    if (!l_found) {
-        return false;
-    }
-    bool l_another_tx = false;
-    json_object *spent_outs = json_object_object_get(l_response_array, "Spent OUTs");
-    if (spent_outs) {
-        int spent_outs_count = json_object_array_length(spent_outs);
-        for (int i = 0; i < spent_outs_count; i++) {
-            json_object *spent_out = json_object_array_get_idx(spent_outs, i);
-            int out_index = json_object_get_int(json_object_object_get(spent_out, "OUT - "));
-            if (out_index == l_prev_tx_count) {
-                dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(spent_out, "is spent by tx")), &l_hash);
-                l_another_tx = true;
-                break;
-            }
-        }
-    }
-    if (l_another_tx) {
-        *a_out_hash = l_hash;
-        return true;
-    }
-    return false;
-}
+//     json_object *items = json_object_object_get(l_response_array, "ITEMS");
+//     if (!items) {
+//         printf("Error: No items found in response\n");
+//         return false;
+//     }
+//     bool l_found = false;
+//     int items_count = json_object_array_length(items);
+//     for (int i = 0; i < items_count; i++) {
+//         json_object *item = json_object_array_get_idx(items, i);
+//         const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+//         if (dap_strcmp(item_type, "OUT COND") == 0) {
+//             const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+//             if (!dap_strcmp(subtype, dap_chain_tx_out_cond_subtype_to_str(a_cond_type))) {
+//                 dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(item, "hash")), &l_hash);
+//                 l_prev_tx_count++;
+//                 l_found = true;
+//                 break;
+//             }
+//         } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) {
+//             l_prev_tx_count++;
+//         }
+//     }
+//     if (!l_found) {
+//         return false;
+//     }
+//     bool l_another_tx = false;
+//     json_object *spent_outs = json_object_object_get(l_response_array, "Spent OUTs");
+//     if (spent_outs) {
+//         int spent_outs_count = json_object_array_length(spent_outs);
+//         for (int i = 0; i < spent_outs_count; i++) {
+//             json_object *spent_out = json_object_array_get_idx(spent_outs, i);
+//             int out_index = json_object_get_int(json_object_object_get(spent_out, "OUT - "));
+//             if (out_index == l_prev_tx_count) {
+//                 dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(spent_out, "is spent by tx")), &l_hash);
+//                 l_another_tx = true;
+//                 break;
+//             }
+//         }
+//     }
+//     if (l_another_tx) {
+//         *a_out_hash = l_hash;
+//         return true;
+//     }
+//     return false;
+// }
 
-dap_chain_hash_fast_t dap_ledger_get_final_chain_tx_hash_compose(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash, bool a_unspent_only, const char *a_url_str, int a_port)
-{
-    dap_chain_hash_fast_t l_hash = { };
-    if(!a_net_str || !a_tx_hash || dap_hash_fast_is_blank(a_tx_hash))
-        return l_hash;
-    l_hash = *a_tx_hash;
+// dap_chain_hash_fast_t dap_ledger_get_final_chain_tx_hash_compose(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash, bool a_unspent_only, const char *a_url_str, int a_port)
+// {
+//     dap_chain_hash_fast_t l_hash = { };
+//     if(!a_net_str || !a_tx_hash || dap_hash_fast_is_blank(a_tx_hash))
+//         return l_hash;
+//     l_hash = *a_tx_hash;
 
-    while(process_ledger_response(a_net_str, a_cond_type, a_tx_hash, a_url_str, a_port, &l_hash));
+//     while(process_ledger_response(a_net_str, a_cond_type, a_tx_hash, a_url_str, a_port, &l_hash));
 
-    return l_hash;
-}
+//     return l_hash;
+// }
 
-dap_chain_net_srv_xchange_price_t *dap_chain_net_srv_xchange_price_from_order_compose(const char *a_net_str, dap_chain_tx_out_cond_t *a_cond_tx, 
-                                                                                    dap_time_t a_ts_created, const char *a_token_ticker, dap_hash_fast_t *a_order_hash, 
-                                                                                    uint256_t *a_fee, bool a_ret_is_invalid, const char *a_url_str, int a_port)
-{
-    if (!a_net_str || !*a_net_str || !a_cond_tx || !a_token_ticker || !a_order_hash || !a_url_str || !*a_url_str || a_port == 0)
-        return NULL;
-    dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
-    if (!l_price)
-        return NULL;
-    l_price->creation_date = a_ts_created;
-    dap_strncpy(l_price->token_buy, a_cond_tx->subtype.srv_xchange.buy_token, sizeof(l_price->token_buy) - 1);
-
-    l_price->order_hash = *a_order_hash;
-    strncpy(l_price->token_sell, a_token_ticker, sizeof(l_price->token_sell) - 1);
-
-    if (a_fee)
-        l_price->fee = *a_fee;
-
-    l_price->datoshi_sell = a_cond_tx->header.value;
-    l_price->creator_addr = a_cond_tx->subtype.srv_xchange.seller_addr;
-    l_price->rate = a_cond_tx->subtype.srv_xchange.rate;
-    dap_chain_hash_fast_t l_final_hash = dap_ledger_get_final_chain_tx_hash_compose(a_net_str,
-                                        DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->order_hash, false, a_url_str, a_port);
-    if ( !dap_hash_fast_is_blank(&l_final_hash) ) {
-        l_price->tx_hash = l_final_hash;
-        return l_price;
-    } else {
-        printf( "This order have no active conditional transaction");
-        if (a_ret_is_invalid) {
-            dap_hash_fast_t l_tx_hash_zero = {0};
-            l_price->tx_hash = l_tx_hash_zero;
-            return l_price;
-        }
-    }
+// dap_chain_net_srv_xchange_price_t *dap_chain_net_srv_xchange_price_from_order_compose(const char *a_net_str, dap_chain_tx_out_cond_t *a_cond_tx, 
+//                                                                                     dap_time_t a_ts_created, const char *a_token_ticker, dap_hash_fast_t *a_order_hash, 
+//                                                                                     uint256_t *a_fee, bool a_ret_is_invalid, const char *a_url_str, int a_port)
+// {
+//     if (!a_net_str || !*a_net_str || !a_cond_tx || !a_token_ticker || !a_order_hash || !a_url_str || !*a_url_str || a_port == 0)
+//         return NULL;
+//     dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
+//     if (!l_price)
+//         return NULL;
+//     l_price->creation_date = a_ts_created;
+//     dap_strncpy(l_price->token_buy, a_cond_tx->subtype.srv_xchange.buy_token, sizeof(l_price->token_buy) - 1);
+
+//     l_price->order_hash = *a_order_hash;
+//     strncpy(l_price->token_sell, a_token_ticker, sizeof(l_price->token_sell) - 1);
+
+//     if (a_fee)
+//         l_price->fee = *a_fee;
+
+//     l_price->datoshi_sell = a_cond_tx->header.value;
+//     l_price->creator_addr = a_cond_tx->subtype.srv_xchange.seller_addr;
+//     l_price->rate = a_cond_tx->subtype.srv_xchange.rate;
+//     dap_chain_hash_fast_t l_final_hash = dap_ledger_get_final_chain_tx_hash_compose(a_net_str,
+//                                         DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->order_hash, false, a_url_str, a_port);
+//     if ( !dap_hash_fast_is_blank(&l_final_hash) ) {
+//         l_price->tx_hash = l_final_hash;
+//         return l_price;
+//     } else {
+//         printf( "This order have no active conditional transaction");
+//         if (a_ret_is_invalid) {
+//             dap_hash_fast_t l_tx_hash_zero = {0};
+//             l_price->tx_hash = l_tx_hash_zero;
+//             return l_price;
+//         }
+//     }
 
-    return NULL;
-}
+//     return NULL;
+// }
 
 
-dap_chain_datum_tx_t* dap_xchange_tx_invalidate_compose(const char *a_net_str, dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port)
-{
-    char * l_ret = NULL;
+// dap_chain_datum_tx_t* dap_xchange_tx_invalidate_compose(const char *a_net_str, dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port)
+// {
+//     char * l_ret = NULL;
 
-    if (!a_price) {
-        printf("An a_price NULL argument was passed to the s_xchange_tx_invalidate() function.");
-        return NULL;
-    }
-    if (!a_wallet) {
-        printf("An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function.");
-        return NULL;
-    }
-    const char *l_native_ticker = s_get_native_ticker(a_net_str);
+//     if (!a_price) {
+//         printf("An a_price NULL argument was passed to the s_xchange_tx_invalidate() function.");
+//         return NULL;
+//     }
+//     if (!a_wallet) {
+//         printf("An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function.");
+//         return NULL;
+//     }
+//     const char *l_native_ticker = s_get_native_ticker(a_net_str);
 
-    dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str));
-    dap_chain_addr_t l_seller_addr = *l_wallet_addr;
-    DAP_DELETE(l_wallet_addr);
+//     dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str));
+//     dap_chain_addr_t l_seller_addr = *l_wallet_addr;
+//     DAP_DELETE(l_wallet_addr);
 
 
-    dap_chain_tx_out_cond_t *l_cond_tx = NULL;
-    char data[512];
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-        dap_chain_hash_fast_to_str_static(&a_price->tx_hash), a_net_str);
+//     dap_chain_tx_out_cond_t *l_cond_tx = NULL;
+//     char data[512];
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+//         dap_chain_hash_fast_to_str_static(&a_price->tx_hash), a_net_str);
     
-    json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
-    if (!response) {
-        printf("Error: Failed to get response from remote node\n");
-        return NULL;
-    }
+//     json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+//     if (!response) {
+//         printf("Error: Failed to get response from remote node\n");
+//         return NULL;
+//     }
     
-    json_object *l_response_array = json_object_array_get_idx(response, 0);
-    if (!l_response_array) {
-        printf("Error: Can't get the first element from the response array\n");
-        json_object_put(response);
-        return NULL;
-    }
-
-    json_object *items = json_object_object_get(l_response_array, "ITEMS");
-    if (!items) {
-        printf("Error: No items found in response\n");
-        return NULL;
-    }
-    int l_prev_cond_idx = 0;
-    int items_count = json_object_array_length(items);
-    for (int i = 0; i < items_count; i++) {
-        json_object *item = json_object_array_get_idx(items, i);
-        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
-        if (dap_strcmp(item_type, "OUT COND") == 0) {
-            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
-            if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
-                l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
-                l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
-                l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
-                l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
-                l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
-                l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
-                strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
-                l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
-                l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
-                l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
-                break;
-            } else if (dap_strcmp(subtype, "OUT") == 0 || dap_strcmp(subtype, "OUT COND") == 0 || dap_strcmp(subtype, "OUT OLD") == 0) {
-                l_prev_cond_idx++;
-            }
-        }
-    }
-    if (!l_cond_tx) {
-        printf("Error: No transaction output condition found\n");
-        return NULL;
-    }
-
-    const char *l_tx_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
-    if (!l_tx_ticker) {
-        printf("Error: Token_ticker not found in response\n");
-        return NULL;
-    }
+//     json_object *l_response_array = json_object_array_get_idx(response, 0);
+//     if (!l_response_array) {
+//         printf("Error: Can't get the first element from the response array\n");
+//         json_object_put(response);
+//         return NULL;
+//     }
 
-    bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker);
+//     json_object *items = json_object_object_get(l_response_array, "ITEMS");
+//     if (!items) {
+//         printf("Error: No items found in response\n");
+//         return NULL;
+//     }
+//     int l_prev_cond_idx = 0;
+//     int items_count = json_object_array_length(items);
+//     for (int i = 0; i < items_count; i++) {
+//         json_object *item = json_object_array_get_idx(items, i);
+//         const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+//         if (dap_strcmp(item_type, "OUT COND") == 0) {
+//             const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+//             if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
+//                 l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+//                 l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+//                 l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+//                 l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
+//                 l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+//                 l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
+//                 strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
+//                 l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
+//                 l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
+//                 l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
+//                 break;
+//             } else if (dap_strcmp(subtype, "OUT") == 0 || dap_strcmp(subtype, "OUT COND") == 0 || dap_strcmp(subtype, "OUT OLD") == 0) {
+//                 l_prev_cond_idx++;
+//             }
+//         }
+//     }
+//     if (!l_cond_tx) {
+//         printf("Error: No transaction output condition found\n");
+//         return NULL;
+//     }
 
-    json_object *spent_outs = json_object_object_get(l_response_array, "all OUTs yet unspent");
-    const char *spent_outs_value = json_object_get_string(spent_outs);
-    if (spent_outs_value && !dap_strcmp(spent_outs_value, "yes")) {
-        printf("Error: Transaction output item already used\n");
-        return NULL;
-    }
+//     const char *l_tx_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
+//     if (!l_tx_ticker) {
+//         printf("Error: Token_ticker not found in response\n");
+//         return NULL;
+//     }
 
-    if (!dap_chain_addr_compare(&l_seller_addr, &l_cond_tx->subtype.srv_xchange.seller_addr)) {
-        printf("Only owner can invalidate exchange transaction");
-        return NULL;
-    }
+//     bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker);
 
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-    // add 'in' item to buy from conditional transaction
-    dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0);
-    uint256_t l_net_fee = {};
-    dap_chain_addr_t* l_addr_fee = NULL;
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port);
-    uint256_t l_total_fee = a_price->fee;
-    if (l_net_fee_used)
-        SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
+//     json_object *spent_outs = json_object_object_get(l_response_array, "all OUTs yet unspent");
+//     const char *spent_outs_value = json_object_get_string(spent_outs);
+//     if (spent_outs_value && !dap_strcmp(spent_outs_value, "yes")) {
+//         printf("Error: Transaction output item already used\n");
+//         return NULL;
+//     }
 
-    if (!l_single_channel) {
-        json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_seller_addr, l_url_str, l_port);
-        if (!l_outs_native) {
-            return NULL;
-        }
-        int l_out_native_count = json_object_array_length(l_outs_native);
-        uint256_t l_transfer_fee = {}, l_fee_back = {};
-        // list of transaction with 'out' items to get net fee
-        dap_list_t *l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
-                                                               l_total_fee, 
-                                                               &l_transfer_fee);
-        if (!l_list_fee_out) {
-            printf("Not enough funds to pay fee");
-            json_object_put(l_outs_native);
-            return NULL;
-        }
+//     if (!dap_chain_addr_compare(&l_seller_addr, &l_cond_tx->subtype.srv_xchange.seller_addr)) {
+//         printf("Only owner can invalidate exchange transaction");
+//         return NULL;
+//     }
 
+//     // create empty transaction
+//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+//     // add 'in' item to buy from conditional transaction
+//     dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0);
+//     uint256_t l_net_fee = {};
+//     dap_chain_addr_t* l_addr_fee = NULL;
+//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port);
+//     uint256_t l_total_fee = a_price->fee;
+//     if (l_net_fee_used)
+//         SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
+
+//     if (!l_single_channel) {
+//         json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_seller_addr, l_url_str, l_port);
+//         if (!l_outs_native) {
+//             return NULL;
+//         }
+//         int l_out_native_count = json_object_array_length(l_outs_native);
+//         uint256_t l_transfer_fee = {}, l_fee_back = {};
+//         // list of transaction with 'out' items to get net fee
+//         dap_list_t *l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+//                                                                l_total_fee, 
+//                                                                &l_transfer_fee);
+//         if (!l_list_fee_out) {
+//             printf("Not enough funds to pay fee");
+//             json_object_put(l_outs_native);
+//             return NULL;
+//         }
 
-        // add 'in' items to net fee
-        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-        dap_list_free_full(l_list_fee_out, NULL);
-        if (!EQUAL_256(l_value_to_items, l_transfer_fee)) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Can't compose the transaction input");
-            return NULL;
-        }
-        // return coins to owner
-        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_cond_tx->header.value, l_tx_ticker) == -1) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Cant add returning coins output");
-            return NULL;
-        }
-        // Network fee
-        if (l_net_fee_used &&
-                dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Cant add network fee output");
-            return NULL;
-        }
-        // put fee coinback
-        SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back);
-        if (!IS_ZERO_256(l_fee_back) &&
-                dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Cant add fee cachback output");
-            return NULL;
-        }
-    } else {
-        uint256_t l_coin_back = {};
-        if (compare256(l_total_fee, l_cond_tx->header.value) >= 0) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Total fee is greater or equal than order liquidity");
-            return NULL;
-        }
-        SUBTRACT_256_256(l_cond_tx->header.value, l_total_fee, &l_coin_back);
-        // return coins to owner
-        if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Cant add returning coins output");
-            return NULL;
-        }
-        // Network fee
-        if (l_net_fee_used &&
-                dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) != 1) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Cant add network fee output");
-            return NULL;
-        }
-    }
-    // Validator's fee
-    if (!IS_ZERO_256(a_price->fee)) {
-        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) {
-            dap_chain_datum_tx_delete(l_tx);
-            printf("Cant add validator's fee output");
-            return NULL;
-        }
-    }
-    // // add 'sign' items
-    // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
-    // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
-    //     dap_chain_datum_tx_delete(l_tx);
-    //     dap_enc_key_delete(l_seller_key);
-    //     log_it( L_ERROR, "Can't add sign output");
-    //     return false;
-    // }
-    // dap_enc_key_delete(l_seller_key);
-    // l_ret = s_xchange_tx_put(l_tx, a_price->net);
 
-    return l_tx;
-}
+//         // add 'in' items to net fee
+//         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+//         dap_list_free_full(l_list_fee_out, NULL);
+//         if (!EQUAL_256(l_value_to_items, l_transfer_fee)) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Can't compose the transaction input");
+//             return NULL;
+//         }
+//         // return coins to owner
+//         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_cond_tx->header.value, l_tx_ticker) == -1) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Cant add returning coins output");
+//             return NULL;
+//         }
+//         // Network fee
+//         if (l_net_fee_used &&
+//                 dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Cant add network fee output");
+//             return NULL;
+//         }
+//         // put fee coinback
+//         SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back);
+//         if (!IS_ZERO_256(l_fee_back) &&
+//                 dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Cant add fee cachback output");
+//             return NULL;
+//         }
+//     } else {
+//         uint256_t l_coin_back = {};
+//         if (compare256(l_total_fee, l_cond_tx->header.value) >= 0) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Total fee is greater or equal than order liquidity");
+//             return NULL;
+//         }
+//         SUBTRACT_256_256(l_cond_tx->header.value, l_total_fee, &l_coin_back);
+//         // return coins to owner
+//         if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Cant add returning coins output");
+//             return NULL;
+//         }
+//         // Network fee
+//         if (l_net_fee_used &&
+//                 dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) != 1) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Cant add network fee output");
+//             return NULL;
+//         }
+//     }
+//     // Validator's fee
+//     if (!IS_ZERO_256(a_price->fee)) {
+//         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             printf("Cant add validator's fee output");
+//             return NULL;
+//         }
+//     }
+//     // // add 'sign' items
+//     // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
+//     // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
+//     //     dap_chain_datum_tx_delete(l_tx);
+//     //     dap_enc_key_delete(l_seller_key);
+//     //     log_it( L_ERROR, "Can't add sign output");
+//     //     return false;
+//     // }
+//     // dap_enc_key_delete(l_seller_key);
+//     // l_ret = s_xchange_tx_put(l_tx, a_price->net);
+
+//     return l_tx;
+// }
 
 
-dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
-                                     dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) {
-    if (!a_net_str || !a_hash_tx || !a_wallet) {
-        return NULL;
-    }
-    if(IS_ZERO_256(a_fee)){
-        return NULL;
-    }
+// dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
+//                                      dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) {
+//     if (!a_net_str || !a_hash_tx || !a_wallet) {
+//         return NULL;
+//     }
+//     if(IS_ZERO_256(a_fee)){
+//         return NULL;
+//     }
 
-    dap_time_t ts_created = 0;
+//     dap_time_t ts_created = 0;
 
-    dap_chain_tx_out_cond_t *l_cond_tx = NULL;
-    char data[512];
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-        dap_chain_hash_fast_to_str_static(a_hash_tx), a_net_str);
+//     dap_chain_tx_out_cond_t *l_cond_tx = NULL;
+//     char data[512];
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+//         dap_chain_hash_fast_to_str_static(a_hash_tx), a_net_str);
     
-    json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
-    if (!response) {
-        printf("Error: Failed to get response from remote node\n");
-        return NULL;
-    }
+//     json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
+//     if (!response) {
+//         printf("Error: Failed to get response from remote node\n");
+//         return NULL;
+//     }
     
-    const char *items_str = json_object_get_string(response);
-    json_object *l_response_array = json_object_array_get_idx(response, 0);
-    if (!l_response_array) {
-        printf("Error: Can't get the first element from the response array\n");
-        json_object_put(response);
-        return NULL;
-    }
-    json_object *items = json_object_object_get(l_response_array, "ITEMS");
-    if (!items) {
-        printf("Error: No items found in response\n");
-        return NULL;
-    }
-    int items_count = json_object_array_length(items);
-    for (int i = 0; i < items_count; i++) {
-        json_object *item = json_object_array_get_idx(items, i);
-        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
-        if (dap_strcmp(item_type, "OUT COND") == 0) {
-            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
-            if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
-                l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
-                l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
-                l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
-                l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
-                l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
-                l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
-                strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
-                l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
-                l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
-                l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
-                break;
-            }
-        }
-    }
-    if (!l_cond_tx) {
-        printf("Error: No transaction output condition found\n");
-        return NULL;
-    }
-
-    const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
-    if (!token_ticker) {
-        printf("Error: Token_ticker not found in response\n");
-        return NULL;
-    }
-    const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created"));
-    if (ts_created_str) {
-        ts_created = dap_time_from_str_rfc822(ts_created_str);
-    } else {
-        printf("Error: TS_Created not found in response\n");
-        return NULL;
-    }
+//     const char *items_str = json_object_get_string(response);
+//     json_object *l_response_array = json_object_array_get_idx(response, 0);
+//     if (!l_response_array) {
+//         printf("Error: Can't get the first element from the response array\n");
+//         json_object_put(response);
+//         return NULL;
+//     }
+//     json_object *items = json_object_object_get(l_response_array, "ITEMS");
+//     if (!items) {
+//         printf("Error: No items found in response\n");
+//         return NULL;
+//     }
+//     int items_count = json_object_array_length(items);
+//     for (int i = 0; i < items_count; i++) {
+//         json_object *item = json_object_array_get_idx(items, i);
+//         const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+//         if (dap_strcmp(item_type, "OUT COND") == 0) {
+//             const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+//             if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
+//                 l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+//                 l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+//                 l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+//                 l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
+//                 l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+//                 l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
+//                 strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
+//                 l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
+//                 l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
+//                 l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
+//                 break;
+//             }
+//         }
+//     }
+//     if (!l_cond_tx) {
+//         printf("Error: No transaction output condition found\n");
+//         return NULL;
+//     }
 
-    dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(a_net_str, l_cond_tx, ts_created, token_ticker, a_hash_tx, &a_fee, false, l_url_str, l_port);
-    if (!l_price) {
-        return NULL;
-    }
-    dap_chain_datum_tx_t *l_tx = dap_xchange_tx_invalidate_compose(a_net_str, l_price, a_wallet, l_url_str, l_port);
-    json_object * l_json_obj_ret = json_object_new_object();
-    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-    printf("%s", json_object_to_json_string(l_json_obj_ret));
-    json_object_put(l_json_obj_ret);
+//     const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
+//     if (!token_ticker) {
+//         printf("Error: Token_ticker not found in response\n");
+//         return NULL;
+//     }
+//     const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created"));
+//     if (ts_created_str) {
+//         ts_created = dap_time_from_str_rfc822(ts_created_str);
+//     } else {
+//         printf("Error: TS_Created not found in response\n");
+//         return NULL;
+//     }
 
-    DAP_DELETE(l_price);
-    return l_tx;
-}
+//     dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(a_net_str, l_cond_tx, ts_created, token_ticker, a_hash_tx, &a_fee, false, l_url_str, l_port);
+//     if (!l_price) {
+//         return NULL;
+//     }
+//     dap_chain_datum_tx_t *l_tx = dap_xchange_tx_invalidate_compose(a_net_str, l_price, a_wallet, l_url_str, l_port);
+//     json_object * l_json_obj_ret = json_object_new_object();
+//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+//     printf("%s", json_object_to_json_string(l_json_obj_ret));
+//     json_object_put(l_json_obj_ret);
+
+//     DAP_DELETE(l_price);
+//     return l_tx;
+// }
 
 
 // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value>
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 92d8bc19c1..8eca82a87f 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -43,6 +43,13 @@ typedef struct {
     uint16_t port;
 } NetInfo;
 
+typedef struct {
+    const char *net_name;
+    const char *url_str;
+    uint16_t port;
+    json_object *response_handler;
+} compose_config_t;
+
 static NetInfo netinfo[NET_COUNT] = {
     {"riemann",  "tKEL",  {.uint64 = 0x000000000000dddd}, "45.76.140.191", 8081},
     {"raiden",   "tCELL", {.uint64 = 0x000000000000bbbb}, "http://rpc.cellframe.net", 8081},
@@ -53,13 +60,13 @@ static NetInfo netinfo[NET_COUNT] = {
 };
 
 
-const char* dap_compose_get_net_url(const char* name);
-uint16_t dap_compose_get_net_port(const char* name);
 
 
 #ifdef __cplusplus
 extern "C" {
 #endif
+const char* dap_compose_get_net_url(const char* name);
+uint16_t dap_compose_get_net_port(const char* name);
 
 int dap_tx_create_compose(int argc, char ** argv);
 int dap_tx_create_xchange_compose(int argc, char ** argv);
@@ -69,14 +76,15 @@ int dap_cli_take_compose(int a_argc, char **a_argv);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
 typedef enum {
     STAKE_ORDER_CREATE_STAKER_OK = 0,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -1,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -2,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -3,
-    STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -4,
-    STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -5,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -6,
-    STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -7,
-    STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -8
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_PARAMS = -1,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -2,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -3,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -4,
+    STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -5,
+    STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -6,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -7,
+    STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -8,
+    STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -9
 } dap_cli_srv_stake_order_create_staker_error_t;
 json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port);
 
@@ -155,11 +163,19 @@ typedef enum {
     DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27,
     DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28
 } dap_cli_stake_invalidate_error_t;
+dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, compose_config_t *a_config);
 json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
                         const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port);
-dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, json_object *a_error_handler);
 
-json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port);
+typedef enum {
+    DAP_COMPOSE_ERROR_NONE = 0,
+    DAP_COMPOSE_ERROR_RESPONSE_NULL = -1,
+    DAP_COMPOSE_ERROR_RESULT_NOT_FOUND = -2,
+    DAP_COMPOSE_ERROR_REQUEST_INIT_FAILED = -3,
+    DAP_COMPOSE_ERROR_REQUEST_TIMEOUT = -4,
+    DAP_COMPOSE_ERROR_REQUEST_FAILED = -5
+} dap_compose_error_t;
+json_object* dap_request_command_to_rpc(const char *request, compose_config_t *a_config);
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
 
 dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer);
@@ -176,7 +192,7 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net
         dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
         uint256_t a_value_fee, const void *a_cond,
         size_t a_cond_size, const char *a_url_str, uint16_t a_port);
-bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, const char * a_url_str, uint16_t a_port);
+bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, compose_config_t *a_config);
 bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name,
                                          json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port);
 dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
@@ -196,11 +212,11 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
                               const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port);
-dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key,
+dap_chain_datum_tx_t *dap_stake_tx_create_compose(dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
-                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, json_object *l_error_handle);
+                                               dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, compose_config_t *a_config);
 
 dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
                                      dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port);
-- 
GitLab


From 9fd0eb9364220af5ab80e2f69f24c0275a475764 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Fri, 11 Apr 2025 15:42:48 +0700
Subject: [PATCH 46/53] [*] refactor order remove

---
 modules/compose/dap_chain_tx_compose.c        | 837 +++++++++---------
 .../compose/include/dap_chain_tx_compose.h    |  41 +-
 modules/net/dap_chain_net_tx.c                |   3 +-
 3 files changed, 446 insertions(+), 435 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 125c7259b3..023f896b69 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -4106,476 +4106,451 @@ json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str
     return s_compose_config_return_response_handler(l_config);
 }
 
-// int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) {
-//     int l_arg_index = 1;
-//     const char * l_order_hash_str = NULL;
-//     const char * l_fee_str = NULL;
-//     const char * l_net_str = NULL;
-//     const char * l_wallet_str = NULL;
-//     const char * l_url_str = NULL;
-//     const char * l_port_str = NULL;
-//     int l_port = 0;
-//     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
-//     if (!l_net_str) {
-//         printf("Command 'order remove' requires parameter -net\n");
-//         return -1;
-//     }
+json_object * dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) {
 
-//         if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) {
-//         l_url_str = dap_compose_get_net_url(l_net_str);
-//     }
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) {
-//         l_port = dap_compose_get_net_port(l_net_str);
-//     } else {
-//         l_port = atoi(l_port_str);
-//     }
-
-//     const char *l_wallet_path = NULL;
-//     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path);
-//     if (!l_wallet_path) {
-//         l_wallet_path =
-//         #ifdef DAP_OS_WINDOWS
-//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-//         #elif defined DAP_OS_MAC
-//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-//         #elif defined DAP_OS_UNIX
-//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-//         #endif
-//     }  
+    compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port);
+    if (!l_config) {
+        json_object *l_json_obj_ret = json_object_new_object();
+        dap_json_compose_error_add(l_json_obj_ret, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS, "Invalid arguments");
+        return l_json_obj_ret;
+    }
 
-//     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
-//     if (!l_wallet_str) {
-//         printf("Command 'order remove' requires parameter -w\n");
-//         return -3;
-//     }
-//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
-//     if (!l_wallet) {
-//         printf("Specified wallet not found\n");
-//         return -4;
-//     }
-//     const char* l_sign_str = dap_chain_wallet_check_sign(l_wallet);
-//     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str);
-//     if (!l_order_hash_str) {
-//         printf("Command 'order remove' requires parameter -order\n");
-//         return -5;
-//     }
-//     dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
-//     if (!l_fee_str) {
-//         printf("Command 'order remove' requires parameter -fee\n");
-//         return -6;
-//     }
-//     uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
-//     dap_hash_fast_t l_tx_hash = {};
-//     dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash);
-//     char *l_tx_hash_ret = NULL;
-//     dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_remove_compose(l_net_str, &l_tx_hash, l_fee, l_wallet, l_url_str, l_port);
-//     dap_chain_wallet_close(l_wallet);
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
+    if (!l_wallet) {
+        dap_json_compose_error_add(l_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_WALLET_NOT_FOUND, "Specified wallet not found");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    const char* l_sign_str = dap_chain_wallet_check_sign(l_wallet);
+    if (!l_sign_str) {
+        dap_json_compose_error_add(l_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_KEY_NOT_FOUND, "Failed to retrieve encryption key");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+    if (IS_ZERO_256(l_fee)) {
+        dap_json_compose_error_add(l_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, "Format -fee <256 bit integer>");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    dap_hash_fast_t l_tx_hash = {};
+    dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash);
+    if (dap_hash_fast_is_blank(&l_tx_hash)) {
+        dap_json_compose_error_add(l_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ORDER_HASH, "Invalid order hash");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    char *l_tx_hash_ret = NULL;
+    dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_remove_compose(&l_tx_hash, l_fee, l_wallet, l_config);
+    dap_chain_wallet_close(l_wallet);
+    if (l_tx) {
+        dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
+        DAP_DELETE(l_tx);
+    }
     
-//     return 0;
-// }
+    return s_compose_config_return_response_handler(l_config);
+}
 
-// bool process_ledger_response(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, 
-//                                                 dap_chain_hash_fast_t *a_tx_hash, const char *a_url_str, int a_port, dap_chain_hash_fast_t *a_out_hash) {
-//     *a_out_hash = *a_tx_hash;
-//     int l_prev_tx_count = 0;
-//     dap_chain_hash_fast_t l_hash = {};
-//     char data[512];
-//     snprintf(data, sizeof(data), 
-//             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-//             dap_chain_hash_fast_to_str_static(a_tx_hash), a_net_str);
+static bool s_process_ledger_response(dap_chain_tx_out_cond_subtype_t a_cond_type, 
+                                                dap_chain_hash_fast_t *a_tx_hash, dap_chain_hash_fast_t *a_out_hash, compose_config_t *a_config) {
+    *a_out_hash = *a_tx_hash;
+    int l_prev_tx_count = 0;
+    dap_chain_hash_fast_t l_hash = {};
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+            dap_chain_hash_fast_to_str_static(a_tx_hash), a_config->net_name);
     
-//     json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port);
-//     if (!response) {
-//         printf("Error: Failed to get response from remote node\n");
-//         return false;
-//     }
+    json_object *response = dap_request_command_to_rpc(data, a_config);
+    if (!response) {
+        printf("Error: Failed to get response from remote node\n");
+        return false;
+    }
     
-//     json_object *l_response_array = json_object_array_get_idx(response, 0);
-//     if (!l_response_array) {
-//         printf("Error: Can't get the first element from the response array\n");
-//         json_object_put(response);
-//         return false;
-//     }
+    json_object *l_response_array = json_object_array_get_idx(response, 0);
+    if (!l_response_array) {
+        printf("Error: Can't get the first element from the response array\n");
+        json_object_put(response);
+        return false;
+    }
 
-//     json_object *items = json_object_object_get(l_response_array, "ITEMS");
-//     if (!items) {
-//         printf("Error: No items found in response\n");
-//         return false;
-//     }
-//     bool l_found = false;
-//     int items_count = json_object_array_length(items);
-//     for (int i = 0; i < items_count; i++) {
-//         json_object *item = json_object_array_get_idx(items, i);
-//         const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
-//         if (dap_strcmp(item_type, "OUT COND") == 0) {
-//             const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
-//             if (!dap_strcmp(subtype, dap_chain_tx_out_cond_subtype_to_str(a_cond_type))) {
-//                 dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(item, "hash")), &l_hash);
-//                 l_prev_tx_count++;
-//                 l_found = true;
-//                 break;
-//             }
-//         } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) {
-//             l_prev_tx_count++;
-//         }
-//     }
-//     if (!l_found) {
-//         return false;
-//     }
-//     bool l_another_tx = false;
-//     json_object *spent_outs = json_object_object_get(l_response_array, "Spent OUTs");
-//     if (spent_outs) {
-//         int spent_outs_count = json_object_array_length(spent_outs);
-//         for (int i = 0; i < spent_outs_count; i++) {
-//             json_object *spent_out = json_object_array_get_idx(spent_outs, i);
-//             int out_index = json_object_get_int(json_object_object_get(spent_out, "OUT - "));
-//             if (out_index == l_prev_tx_count) {
-//                 dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(spent_out, "is spent by tx")), &l_hash);
-//                 l_another_tx = true;
-//                 break;
-//             }
-//         }
-//     }
-//     if (l_another_tx) {
-//         *a_out_hash = l_hash;
-//         return true;
-//     }
-//     return false;
-// }
+    json_object *items = json_object_object_get(l_response_array, "ITEMS");
+    if (!items) {
+        printf("Error: No items found in response\n");
+        return false;
+    }
+    bool l_found = false;
+    int items_count = json_object_array_length(items);
+    for (int i = 0; i < items_count; i++) {
+        json_object *item = json_object_array_get_idx(items, i);
+        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+        if (dap_strcmp(item_type, "OUT COND") == 0) {
+            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+            if (!dap_strcmp(subtype, dap_chain_tx_out_cond_subtype_to_str(a_cond_type))) {
+                dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(item, "hash")), &l_hash);
+                l_prev_tx_count++;
+                l_found = true;
+                break;
+            }
+        } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) {
+            l_prev_tx_count++;
+        }
+    }
+    if (!l_found) {
+        return false;
+    }
+    bool l_another_tx = false;
+    json_object *spent_outs = json_object_object_get(l_response_array, "Spent OUTs");
+    if (spent_outs) {
+        int spent_outs_count = json_object_array_length(spent_outs);
+        for (int i = 0; i < spent_outs_count; i++) {
+            json_object *spent_out = json_object_array_get_idx(spent_outs, i);
+            int out_index = json_object_get_int(json_object_object_get(spent_out, "OUT - "));
+            if (out_index == l_prev_tx_count) {
+                dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(spent_out, "is spent by tx")), &l_hash);
+                l_another_tx = true;
+                break;
+            }
+        }
+    }
+    if (l_another_tx) {
+        *a_out_hash = l_hash;
+        return true;
+    }
+    return false;
+}
 
-// dap_chain_hash_fast_t dap_ledger_get_final_chain_tx_hash_compose(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash, bool a_unspent_only, const char *a_url_str, int a_port)
-// {
-//     dap_chain_hash_fast_t l_hash = { };
-//     if(!a_net_str || !a_tx_hash || dap_hash_fast_is_blank(a_tx_hash))
-//         return l_hash;
-//     l_hash = *a_tx_hash;
+dap_chain_hash_fast_t dap_ledger_get_final_chain_tx_hash_compose(dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash, bool a_unspent_only, compose_config_t *a_config)
+{
+    dap_chain_hash_fast_t l_hash = { };
+    if(!a_tx_hash || dap_hash_fast_is_blank(a_tx_hash))
+        return l_hash;
+    l_hash = *a_tx_hash;
 
-//     while(process_ledger_response(a_net_str, a_cond_type, a_tx_hash, a_url_str, a_port, &l_hash));
+    while(s_process_ledger_response( a_cond_type, a_tx_hash, &l_hash, a_config));
 
-//     return l_hash;
-// }
+    return l_hash;
+}
 
-// dap_chain_net_srv_xchange_price_t *dap_chain_net_srv_xchange_price_from_order_compose(const char *a_net_str, dap_chain_tx_out_cond_t *a_cond_tx, 
-//                                                                                     dap_time_t a_ts_created, const char *a_token_ticker, dap_hash_fast_t *a_order_hash, 
-//                                                                                     uint256_t *a_fee, bool a_ret_is_invalid, const char *a_url_str, int a_port)
-// {
-//     if (!a_net_str || !*a_net_str || !a_cond_tx || !a_token_ticker || !a_order_hash || !a_url_str || !*a_url_str || a_port == 0)
-//         return NULL;
-//     dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
-//     if (!l_price)
-//         return NULL;
-//     l_price->creation_date = a_ts_created;
-//     dap_strncpy(l_price->token_buy, a_cond_tx->subtype.srv_xchange.buy_token, sizeof(l_price->token_buy) - 1);
-
-//     l_price->order_hash = *a_order_hash;
-//     strncpy(l_price->token_sell, a_token_ticker, sizeof(l_price->token_sell) - 1);
-
-//     if (a_fee)
-//         l_price->fee = *a_fee;
-
-//     l_price->datoshi_sell = a_cond_tx->header.value;
-//     l_price->creator_addr = a_cond_tx->subtype.srv_xchange.seller_addr;
-//     l_price->rate = a_cond_tx->subtype.srv_xchange.rate;
-//     dap_chain_hash_fast_t l_final_hash = dap_ledger_get_final_chain_tx_hash_compose(a_net_str,
-//                                         DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->order_hash, false, a_url_str, a_port);
-//     if ( !dap_hash_fast_is_blank(&l_final_hash) ) {
-//         l_price->tx_hash = l_final_hash;
-//         return l_price;
-//     } else {
-//         printf( "This order have no active conditional transaction");
-//         if (a_ret_is_invalid) {
-//             dap_hash_fast_t l_tx_hash_zero = {0};
-//             l_price->tx_hash = l_tx_hash_zero;
-//             return l_price;
-//         }
-//     }
+dap_chain_net_srv_xchange_price_t *dap_chain_net_srv_xchange_price_from_order_compose(dap_chain_tx_out_cond_t *a_cond_tx, 
+                                                                                    dap_time_t a_ts_created, const char *a_token_ticker, dap_hash_fast_t *a_order_hash, 
+                                                                                    uint256_t *a_fee, bool a_ret_is_invalid, compose_config_t *a_config)
+{
+    if (!a_cond_tx || !a_token_ticker || !a_order_hash || !a_config)
+        return NULL;
+    dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
+    if (!l_price)
+        return NULL;
+    l_price->creation_date = a_ts_created;
+    dap_strncpy(l_price->token_buy, a_cond_tx->subtype.srv_xchange.buy_token, sizeof(l_price->token_buy) - 1);
+
+    l_price->order_hash = *a_order_hash;
+    strncpy(l_price->token_sell, a_token_ticker, sizeof(l_price->token_sell) - 1);
+
+    if (a_fee)
+        l_price->fee = *a_fee;
+
+    l_price->datoshi_sell = a_cond_tx->header.value;
+    l_price->creator_addr = a_cond_tx->subtype.srv_xchange.seller_addr;
+    l_price->rate = a_cond_tx->subtype.srv_xchange.rate;
+    dap_chain_hash_fast_t l_final_hash = dap_ledger_get_final_chain_tx_hash_compose(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->order_hash, false, a_config);
+    if ( !dap_hash_fast_is_blank(&l_final_hash) ) {
+        l_price->tx_hash = l_final_hash;
+        return l_price;
+    } else {
+        printf( "This order have no active conditional transaction");
+        if (a_ret_is_invalid) {
+            dap_hash_fast_t l_tx_hash_zero = {0};
+            l_price->tx_hash = l_tx_hash_zero;
+            return l_price;
+        }
+    }
 
-//     return NULL;
-// }
+    return NULL;
+}
 
 
-// dap_chain_datum_tx_t* dap_xchange_tx_invalidate_compose(const char *a_net_str, dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port)
-// {
-//     char * l_ret = NULL;
+dap_chain_datum_tx_t* dap_xchange_tx_invalidate_compose( dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, compose_config_t *a_config)
+{
+    if (!a_config) {
+        return NULL;
+    }
 
-//     if (!a_price) {
-//         printf("An a_price NULL argument was passed to the s_xchange_tx_invalidate() function.");
-//         return NULL;
-//     }
-//     if (!a_wallet) {
-//         printf("An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function.");
-//         return NULL;
-//     }
-//     const char *l_native_ticker = s_get_native_ticker(a_net_str);
+    if (!a_price) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS, "An a_price NULL argument was passed to the s_xchange_tx_invalidate() function.");
+        return NULL;
+    }
+    if (!a_wallet) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS, "An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function.");
+        return NULL;
+    }
+    const char *l_native_ticker = s_get_native_ticker(a_config->net_name);
 
-//     dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str));
-//     dap_chain_addr_t l_seller_addr = *l_wallet_addr;
-//     DAP_DELETE(l_wallet_addr);
+    dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_config->net_name));
+    dap_chain_addr_t l_seller_addr = *l_wallet_addr;
+    DAP_DELETE(l_wallet_addr);
 
 
-//     dap_chain_tx_out_cond_t *l_cond_tx = NULL;
-//     char data[512];
-//     snprintf(data, sizeof(data), 
-//             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-//         dap_chain_hash_fast_to_str_static(&a_price->tx_hash), a_net_str);
+    dap_chain_tx_out_cond_t *l_cond_tx = NULL;
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+        dap_chain_hash_fast_to_str_static(&a_price->tx_hash), a_config->net_name);
     
-//     json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
-//     if (!response) {
-//         printf("Error: Failed to get response from remote node\n");
-//         return NULL;
-//     }
+    json_object *response = dap_request_command_to_rpc(data, a_config);
+    if (!response) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE, "Failed to get response from remote node");
+        return NULL;
+    }
     
-//     json_object *l_response_array = json_object_array_get_idx(response, 0);
-//     if (!l_response_array) {
-//         printf("Error: Can't get the first element from the response array\n");
-//         json_object_put(response);
-//         return NULL;
-//     }
+    json_object *l_response_array = json_object_array_get_idx(response, 0);
+    if (!l_response_array) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT, "Can't get the first element from the response array");
+        json_object_put(response);
+        return NULL;
+    }
 
-//     json_object *items = json_object_object_get(l_response_array, "ITEMS");
-//     if (!items) {
-//         printf("Error: No items found in response\n");
-//         return NULL;
-//     }
-//     int l_prev_cond_idx = 0;
-//     int items_count = json_object_array_length(items);
-//     for (int i = 0; i < items_count; i++) {
-//         json_object *item = json_object_array_get_idx(items, i);
-//         const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
-//         if (dap_strcmp(item_type, "OUT COND") == 0) {
-//             const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
-//             if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
-//                 l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
-//                 l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
-//                 l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
-//                 l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
-//                 l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
-//                 l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
-//                 strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
-//                 l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
-//                 l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
-//                 l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
-//                 break;
-//             } else if (dap_strcmp(subtype, "OUT") == 0 || dap_strcmp(subtype, "OUT COND") == 0 || dap_strcmp(subtype, "OUT OLD") == 0) {
-//                 l_prev_cond_idx++;
-//             }
-//         }
-//     }
-//     if (!l_cond_tx) {
-//         printf("Error: No transaction output condition found\n");
-//         return NULL;
-//     }
+    json_object *items = json_object_object_get(l_response_array, "ITEMS");
+    if (!items) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_ITEMS_FOUND, "No items found in response");
+        return NULL;
+    }
+    int l_prev_cond_idx = 0;
+    int items_count = json_object_array_length(items);
+    for (int i = 0; i < items_count; i++) {
+        json_object *item = json_object_array_get_idx(items, i);
+        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+        if (dap_strcmp(item_type, "OUT COND") == 0) {
+            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+            if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
+                l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+                l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+                l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+                l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
+                l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+                l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
+                strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
+                l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
+                l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
+                l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
+                break;
+            } else if (dap_strcmp(subtype, "OUT") == 0 || dap_strcmp(subtype, "OUT COND") == 0 || dap_strcmp(subtype, "OUT OLD") == 0) {
+                l_prev_cond_idx++;
+            }
+        }
+    }
+    if (!l_cond_tx) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_COND_TX, "No transaction output condition found");
+        return NULL;
+    }
 
-//     const char *l_tx_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
-//     if (!l_tx_ticker) {
-//         printf("Error: Token_ticker not found in response\n");
-//         return NULL;
-//     }
+    const char *l_tx_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
+    if (!l_tx_ticker) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TOKEN_TICKER, "Token_ticker not found in response");
+        return NULL;
+    }
 
-//     bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker);
+    bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker);
 
-//     json_object *spent_outs = json_object_object_get(l_response_array, "all OUTs yet unspent");
-//     const char *spent_outs_value = json_object_get_string(spent_outs);
-//     if (spent_outs_value && !dap_strcmp(spent_outs_value, "yes")) {
-//         printf("Error: Transaction output item already used\n");
-//         return NULL;
-//     }
+    json_object *spent_outs = json_object_object_get(l_response_array, "all OUTs yet unspent");
+    const char *spent_outs_value = json_object_get_string(spent_outs);
+    if (spent_outs_value && !dap_strcmp(spent_outs_value, "yes")) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_ALREADY_USED, "Transaction output item already used");
+        return NULL;
+    }
 
-//     if (!dap_chain_addr_compare(&l_seller_addr, &l_cond_tx->subtype.srv_xchange.seller_addr)) {
-//         printf("Only owner can invalidate exchange transaction");
-//         return NULL;
-//     }
+    if (!dap_chain_addr_compare(&l_seller_addr, &l_cond_tx->subtype.srv_xchange.seller_addr)) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_OWNER, "Only owner can invalidate exchange transaction");
+        return NULL;
+    }
 
-//     // create empty transaction
-//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-//     // add 'in' item to buy from conditional transaction
-//     dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0);
-//     uint256_t l_net_fee = {};
-//     dap_chain_addr_t* l_addr_fee = NULL;
-//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port);
-//     uint256_t l_total_fee = a_price->fee;
-//     if (l_net_fee_used)
-//         SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    // add 'in' item to buy from conditional transaction
+    dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0);
+    uint256_t l_net_fee = {};
+    dap_chain_addr_t* l_addr_fee = NULL;
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, a_config);
+    uint256_t l_total_fee = a_price->fee;
+    if (l_net_fee_used)
+        SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
 
-//     if (!l_single_channel) {
-//         json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_seller_addr, l_url_str, l_port);
-//         if (!l_outs_native) {
-//             return NULL;
-//         }
-//         int l_out_native_count = json_object_array_length(l_outs_native);
-//         uint256_t l_transfer_fee = {}, l_fee_back = {};
-//         // list of transaction with 'out' items to get net fee
-//         dap_list_t *l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
-//                                                                l_total_fee, 
-//                                                                &l_transfer_fee);
-//         if (!l_list_fee_out) {
-//             printf("Not enough funds to pay fee");
-//             json_object_put(l_outs_native);
-//             return NULL;
-//         }
+    if (!l_single_channel) {
+        json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, &l_seller_addr, a_config);
+        if (!l_outs_native) {
+            return NULL;
+        }
+        int l_out_native_count = json_object_array_length(l_outs_native);
+        uint256_t l_transfer_fee = {}, l_fee_back = {};
+        // list of transaction with 'out' items to get net fee
+        dap_list_t *l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+                                                               l_total_fee, 
+                                                               &l_transfer_fee);
+        if (!l_list_fee_out) {
+            dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INSUFFICIENT_FUNDS, "Not enough funds to pay fee");
+            json_object_put(l_outs_native);
+            return NULL;
+        }
 
 
-//         // add 'in' items to net fee
-//         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-//         dap_list_free_full(l_list_fee_out, NULL);
-//         if (!EQUAL_256(l_value_to_items, l_transfer_fee)) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Can't compose the transaction input");
-//             return NULL;
-//         }
-//         // return coins to owner
-//         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_cond_tx->header.value, l_tx_ticker) == -1) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Cant add returning coins output");
-//             return NULL;
-//         }
-//         // Network fee
-//         if (l_net_fee_used &&
-//                 dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Cant add network fee output");
-//             return NULL;
-//         }
-//         // put fee coinback
-//         SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back);
-//         if (!IS_ZERO_256(l_fee_back) &&
-//                 dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Cant add fee cachback output");
-//             return NULL;
-//         }
-//     } else {
-//         uint256_t l_coin_back = {};
-//         if (compare256(l_total_fee, l_cond_tx->header.value) >= 0) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Total fee is greater or equal than order liquidity");
-//             return NULL;
-//         }
-//         SUBTRACT_256_256(l_cond_tx->header.value, l_total_fee, &l_coin_back);
-//         // return coins to owner
-//         if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Cant add returning coins output");
-//             return NULL;
-//         }
-//         // Network fee
-//         if (l_net_fee_used &&
-//                 dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) != 1) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Cant add network fee output");
-//             return NULL;
-//         }
-//     }
-//     // Validator's fee
-//     if (!IS_ZERO_256(a_price->fee)) {
-//         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Cant add validator's fee output");
-//             return NULL;
-//         }
-//     }
-//     // // add 'sign' items
-//     // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
-//     // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
-//     //     dap_chain_datum_tx_delete(l_tx);
-//     //     dap_enc_key_delete(l_seller_key);
-//     //     log_it( L_ERROR, "Can't add sign output");
-//     //     return false;
-//     // }
-//     // dap_enc_key_delete(l_seller_key);
-//     // l_ret = s_xchange_tx_put(l_tx, a_price->net);
+        // add 'in' items to net fee
+        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+        dap_list_free_full(l_list_fee_out, NULL);
+        if (!EQUAL_256(l_value_to_items, l_transfer_fee)) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE_FAILED, "Can't compose the transaction input");
+            return NULL;
+        }
+        // return coins to owner
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_cond_tx->header.value, l_tx_ticker) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_COIN_RETURN_FAILED, "Cant add returning coins output");
+            return NULL;
+        }
+        // Network fee
+        if (l_net_fee_used &&
+                dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NET_FEE_FAILED, "Cant add network fee output");
+            return NULL;
+        }
+        // put fee coinback
+        SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back);
+        if (!IS_ZERO_256(l_fee_back) &&
+                dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_COINBACK_FAILED, "Cant add fee cachback output");
+            return NULL;
+        }
+    } else {
+        uint256_t l_coin_back = {};
+        if (compare256(l_total_fee, l_cond_tx->header.value) >= 0) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_TOO_HIGH, "Total fee is greater or equal than order liquidity");
+            return NULL;
+        }
+        SUBTRACT_256_256(l_cond_tx->header.value, l_total_fee, &l_coin_back);
+        // return coins to owner
+        if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_COIN_RETURN_FAILED, "Cant add returning coins output");
+            return NULL;
+        }
+        // Network fee
+        if (l_net_fee_used &&
+                dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NET_FEE_FAILED, "Cant add network fee output");
+            return NULL;
+        }
+    }
+    // Validator's fee
+    if (!IS_ZERO_256(a_price->fee)) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_VALIDATOR_FEE_FAILED, "Cant add validator's fee output");
+            return NULL;
+        }
+    }
+    // // add 'sign' items
+    // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
+    // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
+    //     dap_chain_datum_tx_delete(l_tx);
+    //     dap_enc_key_delete(l_seller_key);
+    //     log_it( L_ERROR, "Can't add sign output");
+    //     return false;
+    // }
+    // dap_enc_key_delete(l_seller_key);
+    // l_ret = s_xchange_tx_put(l_tx, a_price->net);
 
-//     return l_tx;
-// }
+    return l_tx;
+}
 
 
-// dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
-//                                      dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) {
-//     if (!a_net_str || !a_hash_tx || !a_wallet) {
-//         return NULL;
-//     }
-//     if(IS_ZERO_256(a_fee)){
-//         return NULL;
-//     }
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
+                                     dap_chain_wallet_t *a_wallet, compose_config_t *a_config) {
+    if (!a_hash_tx || !a_wallet || !a_config) {
+        return NULL;
+    }
+    if(IS_ZERO_256(a_fee)){
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, "Fee must be greater than 0");
+        return NULL;
+    }
 
-//     dap_time_t ts_created = 0;
+    dap_time_t ts_created = 0;
 
-//     dap_chain_tx_out_cond_t *l_cond_tx = NULL;
-//     char data[512];
-//     snprintf(data, sizeof(data), 
-//             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-//         dap_chain_hash_fast_to_str_static(a_hash_tx), a_net_str);
+    dap_chain_tx_out_cond_t *l_cond_tx = NULL;
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+        dap_chain_hash_fast_to_str_static(a_hash_tx), a_config->net_name);
     
-//     json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port);
-//     if (!response) {
-//         printf("Error: Failed to get response from remote node\n");
-//         return NULL;
-//     }
+    json_object *response = dap_request_command_to_rpc(data, a_config);
+    if (!response) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE, "Failed to get response from remote node");
+        return NULL;
+    }
     
-//     const char *items_str = json_object_get_string(response);
-//     json_object *l_response_array = json_object_array_get_idx(response, 0);
-//     if (!l_response_array) {
-//         printf("Error: Can't get the first element from the response array\n");
-//         json_object_put(response);
-//         return NULL;
-//     }
-//     json_object *items = json_object_object_get(l_response_array, "ITEMS");
-//     if (!items) {
-//         printf("Error: No items found in response\n");
-//         return NULL;
-//     }
-//     int items_count = json_object_array_length(items);
-//     for (int i = 0; i < items_count; i++) {
-//         json_object *item = json_object_array_get_idx(items, i);
-//         const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
-//         if (dap_strcmp(item_type, "OUT COND") == 0) {
-//             const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
-//             if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
-//                 l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
-//                 l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
-//                 l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
-//                 l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
-//                 l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
-//                 l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
-//                 strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
-//                 l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
-//                 l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
-//                 l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
-//                 break;
-//             }
-//         }
-//     }
-//     if (!l_cond_tx) {
-//         printf("Error: No transaction output condition found\n");
-//         return NULL;
-//     }
+    const char *items_str = json_object_get_string(response);
+    json_object *l_response_array = json_object_array_get_idx(response, 0);
+    if (!l_response_array) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT, "Can't get the first element from the response array");
+        json_object_put(response);
+        return NULL;
+    }
+    json_object *items = json_object_object_get(l_response_array, "ITEMS");
+    if (!items) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_ITEMS_FOUND, "No items found in response");
+        return NULL;
+    }
+    int items_count = json_object_array_length(items);
+    for (int i = 0; i < items_count; i++) {
+        json_object *item = json_object_array_get_idx(items, i);
+        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+        if (dap_strcmp(item_type, "OUT COND") == 0) {
+            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+            if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
+                l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+                l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+                l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+                l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
+                l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+                l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
+                strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
+                l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
+                l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
+                l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
+                break;
+            }
+        }
+    }
+    if (!l_cond_tx) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_COND_TX, "No transaction output condition found");
+        return NULL;
+    }
 
-//     const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
-//     if (!token_ticker) {
-//         printf("Error: Token_ticker not found in response\n");
-//         return NULL;
-//     }
-//     const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created"));
-//     if (ts_created_str) {
-//         ts_created = dap_time_from_str_rfc822(ts_created_str);
-//     } else {
-//         printf("Error: TS_Created not found in response\n");
-//         return NULL;
-//     }
+    const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
+    if (!token_ticker) {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TOKEN_TICKER, "Token_ticker not found in response");
+        return NULL;
+    }
+    const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created"));
+    if (ts_created_str) {
+        ts_created = dap_time_from_str_rfc822(ts_created_str);
+    } else {
+        dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TIMESTAMP, "TS_Created not found in response");
+        return NULL;
+    }
 
-//     dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(a_net_str, l_cond_tx, ts_created, token_ticker, a_hash_tx, &a_fee, false, l_url_str, l_port);
-//     if (!l_price) {
-//         return NULL;
-//     }
-//     dap_chain_datum_tx_t *l_tx = dap_xchange_tx_invalidate_compose(a_net_str, l_price, a_wallet, l_url_str, l_port);
-//     json_object * l_json_obj_ret = json_object_new_object();
-//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-//     printf("%s", json_object_to_json_string(l_json_obj_ret));
-//     json_object_put(l_json_obj_ret);
+    dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(l_cond_tx, ts_created, token_ticker, a_hash_tx, &a_fee, false, a_config);
+    if (!l_price) {
+        return NULL;
+    }
+    dap_chain_datum_tx_t *l_tx = dap_xchange_tx_invalidate_compose(a_hash_tx, a_wallet, a_config);
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
 
-//     DAP_DELETE(l_price);
-//     return l_tx;
-// }
+    DAP_DELETE(l_price);
+    return l_tx;
+}
 
 
 // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value>
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 8eca82a87f..12a262cc3c 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -88,7 +88,43 @@ typedef enum {
 } dap_cli_srv_stake_order_create_staker_error_t;
 json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port);
 
-int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv);
+typedef enum {
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_OK = 0,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_WALLET_NOT_FOUND,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_KEY_NOT_FOUND,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ORDER_HASH,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_RPC_RESPONSE,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ADDR,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TAX,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_COND_TX,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TOKEN_TICKER,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TS_CREATED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PRICE,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TX,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_ENOUGH_FUNDS,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_SIGN,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_ITEMS_FOUND,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_COND_TX,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TOKEN_TICKER,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TIMESTAMP,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INSUFFICIENT_FUNDS,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE_FAILED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_COIN_RETURN_FAILED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NET_FEE_FAILED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_COINBACK_FAILED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_TOO_HIGH,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_VALIDATOR_FEE_FAILED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_ALREADY_USED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_OWNER
+} srv_stake_order_remove_compose_error_t;
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
+                                     dap_chain_wallet_t *a_wallet, compose_config_t *a_config);
+json_object* dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port);
 
 typedef enum {
     STAKE_DELEGATE_COMPOSE_OK = 0,
@@ -218,8 +254,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(dap_enc_key_t *a_key,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
                                                dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, compose_config_t *a_config);
 
-dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
-                                     dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port);
+
 
 
 #ifdef __cplusplus
diff --git a/modules/net/dap_chain_net_tx.c b/modules/net/dap_chain_net_tx.c
index e507d20378..04ae89062d 100644
--- a/modules/net/dap_chain_net_tx.c
+++ b/modules/net/dap_chain_net_tx.c
@@ -1584,7 +1584,8 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json
             json_object_object_add(json_obj_item,"type", json_object_new_string("out_cond"));
             const char *l_coins_str, *l_value_str = dap_uint256_to_char(((dap_chain_tx_out_cond_t*)item)->header.value, &l_coins_str);
             dap_time_t l_ts_exp = ((dap_chain_tx_out_cond_t*)item)->header.ts_expires;
-            dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_ts_exp);
+            if (l_ts_exp > 0)
+                dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_ts_exp);
             json_object_object_add(json_obj_item,"ts_expires", l_ts_exp ? json_object_new_string(l_tmp_buf) : json_object_new_string("never"));
             json_object_object_add(json_obj_item,"value", json_object_new_string(l_value_str));
             sprintf(l_tmp_buff,"0x%016"DAP_UINT64_FORMAT_x"",((dap_chain_tx_out_cond_t*)item)->header.srv_uid.uint64);
-- 
GitLab


From 902262eb163572c38257407afe63306fb40c2123 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Fri, 11 Apr 2025 16:22:33 +0700
Subject: [PATCH 47/53] [*] refactor tx

---
 modules/compose/dap_chain_tx_compose.c        | 776 +++++++++---------
 .../compose/include/dap_chain_tx_compose.h    |  15 +-
 2 files changed, 381 insertions(+), 410 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 023f896b69..d8fea72ff3 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -437,50 +437,50 @@ bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t *
     return true;
 }
 
-// bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name,
-//                                          json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port) {
-//     char data[512];
-//     snprintf(data, sizeof(data), 
-//             "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
-//             dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name);
-//     json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port);
-//     if (!l_json_outs) {
-//         return false;
-//     }
+bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker,
+                                         json_object **l_outs, int *l_outputs_count, compose_config_t *a_config) {
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", 
+            dap_chain_addr_to_str(a_addr_from), a_token_ticker, a_config->net_name);
+    json_object *l_json_outs = dap_request_command_to_rpc(data, a_config);
+    if (!l_json_outs) {
+        return false;
+    }
 
-//     if (!json_object_is_type(l_json_outs, json_type_array)) {
-//         json_object_put(l_json_outs);
-//         return false;
-//     }
+    if (!json_object_is_type(l_json_outs, json_type_array)) {
+        json_object_put(l_json_outs);
+        return false;
+    }
 
-//     if (json_object_array_length(l_json_outs) == 0) {
-//         json_object_put(l_json_outs);
-//         return false;
-//     }
+    if (json_object_array_length(l_json_outs) == 0) {
+        json_object_put(l_json_outs);
+        return false;
+    }
 
-//     json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0);
-//     if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) {
-//         json_object_put(l_json_outs);
-//         return false;
-//     }
+    json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0);
+    if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) {
+        json_object_put(l_json_outs);
+        return false;
+    }
 
-//     json_object *l_first_item = json_object_array_get_idx(l_first_array, 0);
-//     if (!l_first_item) {
-//         json_object_put(l_json_outs);
-//         return false;
-//     }
+    json_object *l_first_item = json_object_array_get_idx(l_first_array, 0);
+    if (!l_first_item) {
+        json_object_put(l_json_outs);
+        return false;
+    }
 
-//     if (!json_object_object_get_ex(l_first_item, "outs", l_outs) ||
-//         !json_object_is_type(*l_outs, json_type_array)) {
-//         json_object_put(l_json_outs);
-//         return false;
-//     }
+    if (!json_object_object_get_ex(l_first_item, "outs", l_outs) ||
+        !json_object_is_type(*l_outs, json_type_array)) {
+        json_object_put(l_json_outs);
+        return false;
+    }
 
-//     *l_outputs_count = json_object_array_length(*l_outs);
-//     json_object_get(*l_outs);
-//     json_object_put(l_json_outs);
-//     return true;
-// }
+    *l_outputs_count = json_object_array_length(*l_outs);
+    json_object_get(*l_outs);
+    json_object_put(l_json_outs);
+    return true;
+}
 
 
 // int dap_tx_create_xchange_compose(int argc, char ** argv) {
@@ -591,403 +591,366 @@ bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t *
 
 
 
-// int dap_tx_create_compose(int argc, char ** argv) {
-//     int arg_index = 1;
-//     const char *addr_base58_to = NULL;
-//     const char *str_tmp = NULL;
-//     const char * l_from_wallet_name = NULL;
-//     const char * l_wallet_fee_name = NULL;
-//     const char * l_token_ticker = NULL;
-//     const char * l_net_name = NULL;
-//     const char * l_chain_name = NULL;
-//     const char * l_url_str = NULL;
-//     uint16_t l_port = 0;
-
-//     const char * l_hash_out_type = NULL;
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type);
-//     if(!l_hash_out_type)
-//         l_hash_out_type = "hex";
-//     if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) {
-//         printf("Invalid parameter -H, valid values: -H <hex | base58>");
-//         return -1;
-//     }
-
-//     const char *l_wallet_path = NULL;
-//     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
-//     if (!l_wallet_path) {
-//         l_wallet_path =
-//         #ifdef DAP_OS_WINDOWS
-//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-//         #elif defined DAP_OS_MAC
-//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-//         #elif defined DAP_OS_UNIX
-//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-//         #endif
-//     }  
-
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
-//     if (!l_net_name) {
-//         printf("tx_create requires parameter '-net'");
-//         return -1;
-//     }
-
-//     if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str)) {
-//         l_url_str = dap_compose_get_net_url(l_net_name);
-//     }
-//     const char *l_port_str = NULL;
-//     if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str)) {
-//         l_port = dap_compose_get_net_port(l_net_name);
-//     } else {
-//         l_port = atoi(l_port_str);
-//     }
-
-//     uint256_t *l_value = NULL;
-//     uint256_t l_value_fee = {};
-//     dap_chain_addr_t **l_addr_to = NULL;
-//     size_t l_addr_el_count = 0;
-//     size_t l_value_el_count = 0;
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-wallet_fee", &l_wallet_fee_name);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name);
+typedef enum {
+    TX_CREATE_COMPOSE_OK = 0,
+    TX_CREATE_COMPOSE_MEMORY_ERROR = -1,
+    TX_CREATE_COMPOSE_ADDR_ERROR = -2,
+    TX_CREATE_COMPOSE_VALUE_ERROR = -3,
+    TX_CREATE_COMPOSE_WALLET_ERROR = -4,
+    TX_CREATE_COMPOSE_INVALID_PARAMS = -5,
+    TX_CREATE_COMPOSE_FEE_ERROR = -6,
+    TX_CREATE_COMPOSE_FUNDS_ERROR = -7,
+    TX_CREATE_COMPOSE_OUT_ERROR = -8
+} tx_create_compose_error_t;
 
-//     // Validator's fee
-//     if (dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) {
-//         if (!str_tmp) {
-//             printf("tx_create requires parameter '-fee'");
-//             return -1;
-//         }
-//         l_value_fee = dap_chain_balance_scan(str_tmp);
-//     }
-//     if (IS_ZERO_256(l_value_fee) && (str_tmp && strcmp(str_tmp, "0"))) {
-//         printf("tx_create requires parameter '-fee' to be valid uint256");
-//         return -2;
-//     }
+json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) {
+    
+    compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port);
+    if (!l_config) {
+        json_object* l_json_obj_ret = json_object_new_object();
+        dap_json_compose_error_add(l_json_obj_ret, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, "Can't create compose config");
+        return l_json_obj_ret;
+    }
 
-//     if (!l_from_wallet_name) {
-//         printf("tx_create requires parameter '-from_wallet'");
-//         return -3;
-//     }
+    uint256_t *l_value = NULL;
+    uint256_t l_value_fee = {};
+    dap_chain_addr_t **l_addr_to = NULL;
+    size_t l_addr_el_count = 0;
+    size_t l_value_el_count = 0;
 
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
-//     if (!l_token_ticker) {
-//         printf("tx_create requires parameter '-token'");
-//         return -4;
-//     }
 
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp);
+    l_value_fee = dap_chain_balance_scan(l_fee_str);
+    if (IS_ZERO_256(l_value_fee) && (l_fee_str && strcmp(l_fee_str, "0"))) {
+        dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "tx_create requires parameter '-fee' to be valid uint256");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if (!str_tmp) {
-//         printf("tx_create requires parameter '-value' to be valid uint256 value");
-//         return -6;
-//     }
-//     l_value_el_count = dap_str_symbol_count(str_tmp, ',') + 1;
+    l_value_el_count = dap_str_symbol_count(l_value_str, ',') + 1;
 
-//     if (addr_base58_to)
-//         l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1;
-//     else 
-//         l_addr_el_count = l_value_el_count;
+    if (addr_base58_to)
+        l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1;
+    else 
+        l_addr_el_count = l_value_el_count;
 
-//     if (addr_base58_to && l_addr_el_count != l_value_el_count) {
-//         printf("num of '-to_addr' and '-value' should be equal");
-//         return -5;
-//     }
+    if (addr_base58_to && l_addr_el_count != l_value_el_count) {
+        dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_INVALID_PARAMS, "num of '-to_addr' and '-value' should be equal");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     l_value = DAP_NEW_Z_COUNT(uint256_t, l_value_el_count);
-//     if (!l_value) {
-//         printf("Can't allocate memory");
-//         return -6;
-//     }
-//     char **l_value_array = dap_strsplit(str_tmp, ",", l_value_el_count);
-//     if (!l_value_array) {
-//         DAP_DELETE(l_value);
-//         printf("Can't read '-to_addr' arg");
-//         return -7;
-//     }
-//     for (size_t i = 0; i < l_value_el_count; ++i) {
-//         l_value[i] = dap_chain_balance_scan(l_value_array[i]);
-//         if(IS_ZERO_256(l_value[i])) {
-//             DAP_DEL_MULTY(l_value_array, l_value);
-//             printf("tx_create requires parameter '-value' to be valid uint256 value");
-//             return -8;
-//         }
-//     }
-//     DAP_DELETE(l_value_array);
+    l_value = DAP_NEW_Z_COUNT(uint256_t, l_value_el_count);
+    if (!l_value) {
+        dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_MEMORY_ERROR, "Can't allocate memory");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    char **l_value_array = dap_strsplit(l_value_str, ",", l_value_el_count);
+    if (!l_value_array) {
+        DAP_DELETE(l_value);
+        dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_ADDR_ERROR, "Can't read '-to_addr' arg");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    for (size_t i = 0; i < l_value_el_count; ++i) {
+        l_value[i] = dap_chain_balance_scan(l_value_array[i]);
+        if(IS_ZERO_256(l_value[i])) {
+            DAP_DEL_MULTY(l_value_array, l_value);
+            dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_VALUE_ERROR, "tx_create requires parameter '-value' to be valid uint256 value");
+            return s_compose_config_return_response_handler(l_config);
+        }
+    }
+    DAP_DELETE(l_value_array);
 
-//     if (addr_base58_to) {
-//         l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count);
-//         if (!l_addr_to) {
-//             printf("Can't allocate memory");
-//             DAP_DELETE(l_value);
-//             return -9;
-//         }
-//         char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count);
-//         if (!l_addr_base58_to_array) {
-//             DAP_DEL_MULTY(l_addr_to, l_value);
-//             printf("Can't read '-to_addr' arg");
-//             return -10;
-//         }
-//         for (size_t i = 0; i < l_addr_el_count; ++i) {
-//             l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]);
-//             if(!l_addr_to[i]) {
-//                 for (size_t j = 0; j < i; ++j) {
-//                     DAP_DELETE(l_addr_to[j]);
-//                 }
-//                 DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value);
-//                 printf("destination address is invalid");
-//                 return -11;
-//             }
-//         }
-//         DAP_DELETE(l_addr_base58_to_array);
-//     }
+    if (addr_base58_to) {
+        l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count);
+        if (!l_addr_to) {
+            dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_MEMORY_ERROR, "Can't allocate memory");
+            DAP_DELETE(l_value);
+            return s_compose_config_return_response_handler(l_config);
+        }
+        char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count);
+        if (!l_addr_base58_to_array) {
+            DAP_DEL_MULTY(l_addr_to, l_value);
+            dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_ADDR_ERROR, "Can't read '-to_addr' arg");
+            return s_compose_config_return_response_handler(l_config);
+        }
+        for (size_t i = 0; i < l_addr_el_count; ++i) {
+            l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]);
+            if(!l_addr_to[i]) {
+                for (size_t j = 0; j < i; ++j) {
+                    DAP_DELETE(l_addr_to[j]);
+                }
+                DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value);
+                dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_ADDR_ERROR, "destination address is invalid");
+                return s_compose_config_return_response_handler(l_config);
+            }
+        }
+        DAP_DELETE(l_addr_base58_to_array);
+    }
     
-//     dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, l_wallet_path, NULL);
-//     if(!l_wallet) {
-//         printf("Can't open wallet %s", l_from_wallet_name);
-//         return -12;
-//     }
+    dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
+    if(!l_wallet) {
+        dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_WALLET_ERROR, "Can't open wallet %s", l_wallet_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
 
-//     dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name));
-//     for (size_t i = 0; l_addr_to && i < l_addr_el_count; ++i) {
-//         if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) {
-//             printf("The transaction cannot be directed to the same address as the source.");
-//             for (size_t j = 0; j < l_addr_el_count; ++j) {
-//                     DAP_DELETE(l_addr_to[j]);
-//             }
-//             DAP_DEL_MULTY(l_addr_to, l_value);
-//             return -13;
-//         }
-//     }
+    dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_str));
+    for (size_t i = 0; l_addr_to && i < l_addr_el_count; ++i) {
+        if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) {
+            printf("The transaction cannot be directed to the same address as the source.");
+            for (size_t j = 0; j < l_addr_el_count; ++j) {
+                    DAP_DELETE(l_addr_to[j]);
+            }
+            DAP_DEL_MULTY(l_addr_to, l_value);
+            return s_compose_config_return_response_handler(l_config);
+        }
+    }
 
 
-//     dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count, l_url_str, l_port);
+    dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose( l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count, l_config);
+    if (l_tx) {
+        dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
+        dap_chain_datum_tx_delete(l_tx);
+        DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     json_object * l_json_obj_ret = json_object_new_object();
-//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-//     printf("%s", json_object_to_json_string(l_json_obj_ret));
-//     json_object_put(l_json_obj_ret);
-//     dap_chain_datum_tx_delete(l_tx);
-//     DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from);
-//     return 0;
-// }
+    DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from);
+    return s_compose_config_return_response_handler(l_config);
+}
 
-// int dap_chain_datum_tx_add_out_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value) {
-//     if (IS_ZERO_256(a_value))
-//         return -1;
+int dap_chain_datum_tx_add_out_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value) {
+    if (IS_ZERO_256(a_value))
+        return -1;
     
-//     dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t);
-//     if (!l_item)
-//         return -1;
+    dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t);
+    if (!l_item)
+        return -1;
     
-//     l_item->header.type = TX_ITEM_TYPE_OUT;
-//     l_item->header.value = a_value;
+    l_item->header.type = TX_ITEM_TYPE_OUT;
+    l_item->header.value = a_value;
     
-//     int res = dap_chain_datum_tx_add_item(a_tx, l_item);
-//     DAP_DELETE(l_item);
+    int res = dap_chain_datum_tx_add_item(a_tx, l_item);
+    DAP_DELETE(l_item);
     
-//     return res;
-// }
+    return res;
+}
 
 
-// int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value, const char *a_token)
-// {
-//     if (!a_token || IS_ZERO_256(a_value))
-//         return -1;
+int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value, const char *a_token)
+{
+    if (!a_token || IS_ZERO_256(a_value))
+        return -1;
 
-//     dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t);
-//     if (!l_item)
-//         return -2;
-//     l_item->header.type = TX_ITEM_TYPE_OUT_EXT;
-//     l_item->header.value = a_value;
-//     dap_strncpy((char*)l_item->token, a_token, sizeof(l_item->token) - 1);
+    dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t);
+    if (!l_item)
+        return -2;
+    l_item->header.type = TX_ITEM_TYPE_OUT_EXT;
+    l_item->header.value = a_value;
+    dap_strncpy((char*)l_item->token, a_token, sizeof(l_item->token) - 1);
 
-//     int result = dap_chain_datum_tx_add_item(a_tx, l_item);
-//     DAP_DELETE(l_item);
-//     return result;
-// }
+    int result = dap_chain_datum_tx_add_item(a_tx, l_item);
+    DAP_DELETE(l_item);
+    return result;
+}
 
 
-// dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
-//         const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port)
-// {
-//     if (!a_addr_from || !a_token_ticker || !a_value) {
-//         return NULL;
-//     }
+dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
+        const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, compose_config_t *a_config)
+{
+    if (!a_config) {
+        return NULL;
+    }
+    if (!a_addr_from || !a_token_ticker || !a_value) {
+        dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_INVALID_PARAMS, "Invalid parameters");
+        return NULL;
+    }
 
-//     if (dap_chain_addr_check_sum(a_addr_from)) {
-//         return NULL;
-//     }
+    if (dap_chain_addr_check_sum(a_addr_from)) {
+        dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_ADDR_ERROR, "Invalid source address");
+        return NULL;
+    }
 
-//     for (size_t i = 0; i < a_tx_num; ++i) {
-//         // if (!a_addr_to || !a_addr_to[i]) {
-//         //     return NULL;
-//         // }
-//         if (a_addr_to && dap_chain_addr_check_sum(a_addr_to[i])) {
-//             return NULL;
-//         }
-//         if (IS_ZERO_256(a_value[i])) {
-//             return NULL;
-//         }
-//     }
-//     const char * l_native_ticker = s_get_native_ticker(l_net_name);
-//     bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker);
+    for (size_t i = 0; i < a_tx_num; ++i) {
+        // if (!a_addr_to || !a_addr_to[i]) {
+        //     return NULL;
+        // }
+        if (a_addr_to && dap_chain_addr_check_sum(a_addr_to[i])) {
+            dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_ADDR_ERROR, "Invalid destination address");
+            return NULL;
+        }
+        if (IS_ZERO_256(a_value[i])) {
+            dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_VALUE_ERROR, "Invalid value");
+            return NULL;
+        }
+    }
+    const char * l_native_ticker = s_get_native_ticker(a_config->net_name);
+    bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker);
 
-//     uint256_t l_value_transfer = {}; // how many coins to transfer
-//     uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {};
-//     for (size_t i = 0; i < a_tx_num; ++i) {
-//         SUM_256_256(l_value_total, a_value[i], &l_value_total);
-//     }
-//     uint256_t l_value_need = l_value_total;
+    uint256_t l_value_transfer = {}; // how many coins to transfer
+    uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {};
+    for (size_t i = 0; i < a_tx_num; ++i) {
+        SUM_256_256(l_value_total, a_value[i], &l_value_total);
+    }
+    uint256_t l_value_need = l_value_total;
 
-//     dap_list_t *l_list_fee_out = NULL;
-//     uint256_t l_net_fee = {};
-//     dap_chain_addr_t *l_addr_fee = NULL;
-//     if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port)) {
-//         return NULL;
-//     }
+    dap_list_t *l_list_fee_out = NULL;
+    uint256_t l_net_fee = {};
+    dap_chain_addr_t *l_addr_fee = NULL;
+    if (!dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, a_config)) {
+        return NULL;
+    }
 
-//     bool l_net_fee_used = !IS_ZERO_256(l_net_fee);
-//     SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
-//     json_object *l_outs = NULL;
-//     int l_outputs_count = 0;
-//     if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) {
-//         return NULL;
-//     }
+    bool l_net_fee_used = !IS_ZERO_256(l_net_fee);
+    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
+    json_object *l_outs = NULL;
+    int l_outputs_count = 0;
+    if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, &l_outs, &l_outputs_count, a_config)) {
+        return NULL;
+    }
 
-//     if (l_single_channel)
-//         SUM_256_256(l_value_need, l_total_fee, &l_value_need);
-//     else if (!IS_ZERO_256(l_total_fee)) {
-//         l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
-//                                                                l_total_fee, 
-//                                                                &l_fee_transfer);
-//         if (!l_list_fee_out) {
-//             printf("Not enough funds to pay fee");
-//             json_object_put(l_outs);
-//             return NULL;
-//         }
-//     }
-//     dap_list_t *l_list_used_out = NULL;
-//     l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
-//                                                             l_value_need,
-//                                                             &l_value_transfer);
-//     json_object_put(l_outs);
-//     if (!l_list_used_out) {
-//         printf("Not enough funds to transfer");
-//         return NULL;
-//     }
-//     // create empty transaction
-//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-//     // add 'in' items
-//     {
-//         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-//         assert(EQUAL_256(l_value_to_items, l_value_transfer));
-//         dap_list_free_full(l_list_used_out, NULL);
-//         if (l_list_fee_out) {
-//             uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-//             assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
-//             dap_list_free_full(l_list_fee_out, NULL);
-//         }
+    if (l_single_channel)
+        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+    else if (!IS_ZERO_256(l_total_fee)) {
+        l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                               l_total_fee, 
+                                                               &l_fee_transfer);
+        if (!l_list_fee_out) {
+            dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Not enough funds to pay fee");
+            json_object_put(l_outs);
+            return NULL;
+        }
+    }
+    dap_list_t *l_list_used_out = NULL;
+    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                            l_value_need,
+                                                            &l_value_transfer);
+    json_object_put(l_outs);
+    if (!l_list_used_out) {
+        dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Not enough funds to transfer");
+        return NULL;
+    }
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    // add 'in' items
+    {
+        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+        assert(EQUAL_256(l_value_to_items, l_value_transfer));
+        dap_list_free_full(l_list_used_out, NULL);
+        if (l_list_fee_out) {
+            uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+            assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+            dap_list_free_full(l_list_fee_out, NULL);
+        }
 
-//     }
-//     if (a_tx_num > 1) {
-//         uint32_t l_tx_num = a_tx_num;
-//         dap_chain_tx_tsd_t *l_out_count = dap_chain_datum_tx_item_tsd_create(&l_tx_num, DAP_CHAIN_DATUM_TRANSFER_TSD_TYPE_OUT_COUNT, sizeof(uint32_t));
-//         dap_chain_datum_tx_add_item(&l_tx, l_out_count);
-//     }
+    }
+    if (a_tx_num > 1) {
+        uint32_t l_tx_num = a_tx_num;
+        dap_chain_tx_tsd_t *l_out_count = dap_chain_datum_tx_item_tsd_create(&l_tx_num, DAP_CHAIN_DATUM_TRANSFER_TSD_TYPE_OUT_COUNT, sizeof(uint32_t));
+        dap_chain_datum_tx_add_item(&l_tx, l_out_count);
+    }
     
-//     if (l_single_channel) { // add 'out' items
-//         uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
-//         for (size_t i = 0; i < a_tx_num; ++i) {
-//             if (a_addr_to) {
-//                 if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) != 1) {
-//                     dap_chain_datum_tx_delete(l_tx);
-//                     return NULL;
-//                 }
-//             } else {
-//                 if (dap_chain_datum_tx_add_out_without_addr(&l_tx, a_value[i]) != 1) {
-//                     dap_chain_datum_tx_delete(l_tx);
-//                     return NULL;
-//                 }
-//             }
-//                 SUM_256_256(l_value_pack, a_value[i], &l_value_pack);
-//         }
-//         // Network fee
-//         if (l_net_fee_used) {
-//             if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
-//                 SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-//             else {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 return NULL;
-//             }
-//         }
-//         // Validator's fee
-//         if (!IS_ZERO_256(a_value_fee)) {
-//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
-//                 SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
-//             else {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 return NULL;
-//             }
-//         }
-//         // coin back
-//         uint256_t l_value_back;
-//         SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-//         if(!IS_ZERO_256(l_value_back)) {
-//             if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 return NULL;
-//             }
-//         }
-//     } else { // add 'out_ext' items
-//         for (size_t i = 0; i < a_tx_num; ++i) {
-//             if (a_addr_to) {
-//                 if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) {
-//                     dap_chain_datum_tx_delete(l_tx);
-//                     return NULL;
-//                 }
-//             } else {
-//                 if (dap_chain_datum_tx_add_out_ext_item_without_addr(&l_tx, a_value[i], a_token_ticker) != 1) {
-//                     dap_chain_datum_tx_delete(l_tx);
-//                     return NULL;
-//                 }
-//             }
-//         }
-//         // coin back
-//         uint256_t l_value_back;
-//         SUBTRACT_256_256(l_value_transfer, l_value_total, &l_value_back);
-//         if(!IS_ZERO_256(l_value_back)) {
-//             if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 return NULL;
-//             }
-//         }
-//         // Network fee
-//         if (l_net_fee_used) {
-//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 return NULL;
-//             }
-//         }
-//         // Validator's fee
-//         if (!IS_ZERO_256(a_value_fee)) {
-//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 return NULL;
-//             }
-//         }
-//         // fee coin back
-//         SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back);
-//         if(!IS_ZERO_256(l_value_back)) {
-//             if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 return NULL;
-//             }
-//         }
-//     }
-//     DAP_DELETE(l_addr_fee);
-//     return l_tx;
-// }
+    if (l_single_channel) { // add 'out' items
+        uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
+        for (size_t i = 0; i < a_tx_num; ++i) {
+            if (a_addr_to) {
+                if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'out' item");
+                    return NULL;
+                }
+            } else {
+                if (dap_chain_datum_tx_add_out_without_addr(&l_tx, a_value[i]) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'out' without address");
+                    return NULL;
+                }
+            }
+                SUM_256_256(l_value_pack, a_value[i], &l_value_pack);
+        }
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
+                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Can't add network 'fee' item");
+                return NULL;
+            }
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Can't add validator's 'fee' item");
+                return NULL;
+            }
+        }
+        // coin back
+        uint256_t l_value_back;
+        SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+        if(!IS_ZERO_256(l_value_back)) {
+            if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'coin back' item");
+                return NULL;
+            }
+        }
+    } else { // add 'out_ext' items
+        for (size_t i = 0; i < a_tx_num; ++i) {
+            if (a_addr_to) {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'out_ext' item");
+                    return NULL;
+                }
+            } else {
+                if (dap_chain_datum_tx_add_out_ext_item_without_addr(&l_tx, a_value[i], a_token_ticker) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'out_ext' without address");
+                    return NULL;
+                }
+            }
+        }
+        // coin back
+        uint256_t l_value_back;
+        SUBTRACT_256_256(l_value_transfer, l_value_total, &l_value_back);
+        if(!IS_ZERO_256(l_value_back)) {
+            if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'coin back' item");
+                return NULL;
+            }
+        }
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add network 'fee' item");
+                return NULL;
+            }
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Can't add validator's 'fee' item");
+                return NULL;
+            }
+        }
+        // fee coin back
+        SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back);
+        if(!IS_ZERO_256(l_value_back)) {
+            if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'coin back' item");
+                return NULL;
+            }
+        }
+    }
+    DAP_DELETE(l_addr_fee);
+    return l_tx;
+}
 
 dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer)
 {
@@ -3062,10 +3025,17 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
 
 
 json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
-                        const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port)
+                        const char *a_wallet_path, const char *a_cert_str, const char *a_fee_str, const char *a_url_str, uint16_t a_port)
 {
     compose_config_t* l_config = s_compose_config_init(a_net_str, a_url_str, a_port);
     dap_hash_fast_t l_tx_hash = {};
+
+    uint256_t l_fee = dap_chain_balance_scan(a_fee_str);
+    if (IS_ZERO_256(l_fee)) {
+        dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_FEE_ERROR, "Unrecognized number in '-fee' param");
+        return s_compose_config_return_response_handler(l_config);
+    }
+
     if (a_tx_hash_str) {
         dap_chain_hash_fast_from_str(a_tx_hash_str, &l_tx_hash);
     } else {
@@ -3210,7 +3180,7 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c
         return s_compose_config_return_response_handler(l_config);
     }
     dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0);
-    dap_chain_datum_tx_t *l_tx = dap_stake_tx_invalidate_compose(&l_tx_hash, a_fee, l_enc_key, l_config);
+    dap_chain_datum_tx_t *l_tx = dap_stake_tx_invalidate_compose(&l_tx_hash, l_fee, l_enc_key, l_config);
     if (l_tx) {
         dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
         DAP_DELETE(l_tx);
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 12a262cc3c..7c6203532d 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -68,7 +68,7 @@ extern "C" {
 const char* dap_compose_get_net_url(const char* name);
 uint16_t dap_compose_get_net_port(const char* name);
 
-int dap_tx_create_compose(int argc, char ** argv);
+json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port);
 int dap_tx_create_xchange_compose(int argc, char ** argv);
 int dap_tx_cond_create_compose(int argc, char ** argv);
 int dap_cli_hold_compose(int a_argc, char **a_argv);
@@ -197,11 +197,12 @@ typedef enum {
     DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR = -25,
     DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR = -26,
     DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28,
+    DAP_CLI_STAKE_INVALIDATE_FEE_ERROR = -29
 } dap_cli_stake_invalidate_error_t;
 dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, compose_config_t *a_config);
 json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
-                        const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port);
+                        const char *a_wallet_path, const char *a_cert_str, const char *a_fee_str, const char *a_url_str, uint16_t a_port);
 
 typedef enum {
     DAP_COMPOSE_ERROR_NONE = 0,
@@ -215,8 +216,8 @@ json_object* dap_request_command_to_rpc(const char *request, compose_config_t *a
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
 
 dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer);
-dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
-        const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port);
+dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
+        const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, compose_config_t *a_config);
 dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, const char *a_token_sell, uint256_t a_datoshi_sell,
                                      uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port);
 dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
@@ -229,8 +230,8 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net
         uint256_t a_value_fee, const void *a_cond,
         size_t a_cond_size, const char *a_url_str, uint16_t a_port);
 bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, compose_config_t *a_config);
-bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name,
-                                         json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port);
+bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker,
+                                         json_object **l_outs, int *l_outputs_count, compose_config_t *a_config);
 dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
                                                     const char *a_main_ticker,
                                                     uint256_t a_value, uint256_t a_value_fee,
-- 
GitLab


From 89e0057f9b8fe6c5a72f31e726f9515395813cf7 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Fri, 11 Apr 2025 16:50:47 +0700
Subject: [PATCH 48/53] [*] refactor xchange

---
 modules/compose/dap_chain_tx_compose.c        | 713 +++++++++---------
 .../compose/include/dap_chain_tx_compose.h    |  14 +-
 2 files changed, 355 insertions(+), 372 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index d8fea72ff3..2349aa5e5d 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -483,111 +483,7 @@ bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const c
 }
 
 
-// int dap_tx_create_xchange_compose(int argc, char ** argv) {
-//     int arg_index = 1;
-//     const char *l_net_name = NULL;
-//     const char *l_token_sell = NULL;
-//     const char *l_token_buy = NULL;
-//     const char *l_wallet_name = NULL;
-//     const char *l_value_str = NULL;
-//     const char *l_rate_str = NULL;
-//     const char *l_fee_str = NULL;
-//     const char *l_url_str = NULL;
-//     const char *l_port_str = NULL;
-//     uint16_t l_port = 0;
-
-//     const char *l_wallet_path = NULL;
-//     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
-//     if (!l_wallet_path) {
-//         l_wallet_path =
-//         #ifdef DAP_OS_WINDOWS
-//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-//         #elif defined DAP_OS_MAC
-//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-//         #elif defined DAP_OS_UNIX
-//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-//         #endif
-//     }
-
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_sell", &l_token_sell);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_buy", &l_token_buy);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-rate", &l_rate_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str);
-
-//     if (!l_net_name) {
-//         printf("xchange_create requires parameter '-net'");
-//         return -1;
-//     }
-
-//     if (!l_url_str) {
-//         l_url_str = dap_compose_get_net_url(l_net_name);
-//     }
-
-//     if (!l_port_str) {
-//         l_port = dap_compose_get_net_port(l_net_name);
-//     } else {
-//         l_port = atoi(l_port_str);
-//     }
-
-//     if (!l_token_buy) {
-//         printf("xchange_create requires parameter '-token_buy'");
-//         return -1;
-//     }
-
-//     if (!l_token_sell) {
-//         printf("xchange_create requires parameter '-token_sell'");
-//         return -1;
-//     }
-
-//     if (!l_wallet_name) {
-//         printf("xchange_create requires parameter '-w'");
-//         return -1;
-//     }
-
-//     if (!l_value_str) {
-//         printf("xchange_create requires parameter '-value'");
-//         return -1;
-//     }
 
-//     if (!l_rate_str) {
-//         printf("xchange_create requires parameter '-rate'");
-//         return -1;
-//     }
-
-//     if (!l_fee_str) {
-//         printf("xchange_create requires parameter '-fee'");
-//         return -1;
-//     }
-
-//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL);
-//     if(!l_wallet) {
-//         printf("wallet %s does not exist", l_wallet_name);
-//         return -1;
-//     }
-
-
-//     uint256_t l_value = dap_chain_balance_scan(l_value_str);
-//     uint256_t l_rate = dap_chain_balance_scan(l_rate_str);
-//     uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
-//     if (IS_ZERO_256(l_value) || IS_ZERO_256(l_rate) || IS_ZERO_256(l_fee)) {
-//         printf("Invalid parameter value, rate or fee is 0, use required format 1.0e+18 ot in datoshi");
-//         return -1;
-//     }
-
-//     dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_net_name, l_token_buy,
-//                                      l_token_sell, l_value, l_rate, l_fee, l_wallet, l_url_str, l_port);
-//     json_object *l_ret = json_object_new_object();
-//     dap_chain_net_tx_to_json(l_tx, l_ret);
-//     printf("%s", json_object_to_json_string(l_ret));
-//     json_object_put(l_ret);
-//     dap_chain_datum_tx_delete(l_tx);
-//     return 0;
-// }
 
 
 
@@ -603,7 +499,7 @@ typedef enum {
     TX_CREATE_COMPOSE_OUT_ERROR = -8
 } tx_create_compose_error_t;
 
-json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) {
+json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) {
     
     compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port);
     if (!l_config) {
@@ -1015,127 +911,6 @@ dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array,
     }
 }
 
-// uint256_t get_balance_from_json(json_object *l_json_outs, const char *a_token_sell) {
-//     uint256_t l_value = {};
-//     if (l_json_outs && json_object_is_type(l_json_outs, json_type_array)) {
-//         for (size_t i = 0; i < json_object_array_length(l_json_outs); i++) {
-//             json_object *outer_array = json_object_array_get_idx(l_json_outs, i);
-//             if (json_object_is_type(outer_array, json_type_array)) {
-//                 for (size_t j = 0; j < json_object_array_length(outer_array); j++) {
-//                     json_object *addr_obj = json_object_array_get_idx(outer_array, j);
-//                     if (json_object_is_type(addr_obj, json_type_object)) {
-//                         json_object *tokens = NULL;
-//                         if (json_object_object_get_ex(addr_obj, "tokens", &tokens) && json_object_is_type(tokens, json_type_array)) {
-//                             for (size_t k = 0; k < json_object_array_length(tokens); k++) {
-//                                 json_object *token_obj = json_object_array_get_idx(tokens, k);
-//                                 json_object *token = NULL;
-//                                 if (json_object_object_get_ex(token_obj, "token", &token) && json_object_is_type(token, json_type_object)) {
-//                                     json_object *ticker = NULL;
-//                                     if (json_object_object_get_ex(token, "ticker", &ticker) && json_object_is_type(ticker, json_type_string)) {
-//                                         const char *ticker_str = json_object_get_string(ticker);
-//                                         if (strcmp(ticker_str, a_token_sell) == 0) {
-//                                             json_object *datoshi = NULL;
-//                                             if (json_object_object_get_ex(token_obj, "datoshi", &datoshi) && json_object_is_type(datoshi, json_type_string)) {
-//                                                 const char *datoshi_str = json_object_get_string(datoshi);
-//                                                 l_value = dap_uint256_scan_uninteger(datoshi_str);
-//                                                 break;
-//                                             }
-//                                         }
-//                                     }
-//                                 }
-//                             }
-//                         }
-//                     }
-//                 }
-//             }
-//         }
-//     }
-//     return l_value;
-// }
-
-// bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) {
-//     if (json_object_is_type(l_json_coins, json_type_array)) {
-//         for (size_t i = 0; i < json_object_array_length(l_json_coins); i++) {
-//             json_object *token_array = json_object_array_get_idx(l_json_coins, i);
-//             if (json_object_is_type(token_array, json_type_array)) {
-//                 for (size_t j = 0; j < json_object_array_length(token_array); j++) {
-//                     json_object *token_obj = json_object_array_get_idx(token_array, j);
-//                     json_object *token_name = NULL;
-//                     if (json_object_object_get_ex(token_obj, "-->Token name", &token_name) && json_object_is_type(token_name, json_type_string)) {
-//                         const char *token_name_str = json_object_get_string(token_name);
-//                         if (strcmp(token_name_str, a_token) == 0) {
-//                             return true;
-//                         }
-//                     }
-//                 }
-//             }
-//         }
-//     }
-//     return false;
-// }
-
-// dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,
-//                                      const char *a_token_sell, uint256_t a_datoshi_sell,
-//                                      uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port){
-//     if (!a_net_name || !a_token_buy || !a_token_sell || !a_wallet) {
-//         return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMEN
-//     }
-//     if (IS_ZERO_256(a_rate)) {
-//         return NULL; // XCHANGE_CREATE_ERROR_RATE_IS_ZERO
-//     }
-//     if (IS_ZERO_256(a_fee)) {
-//         return NULL; // XCHANGE_CREATE_ERROR_FEE_IS_ZERO
-//     }
-//     if (IS_ZERO_256(a_datoshi_sell)) {
-//         return NULL; // XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO
-//     }
-//     char data[512];
-//     snprintf(data, sizeof(data), 
-//             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name);
-//     json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
-//     if (!l_json_coins) {
-//         return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS
-//     }
-//     if (!check_token_in_ledger(l_json_coins, a_token_sell) || !check_token_in_ledger(l_json_coins, a_token_buy)) {
-//         json_object_put(l_json_coins);
-//         return NULL; // XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER
-//     }
-//     json_object_put(l_json_coins);
-//     dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name));
-//     snprintf(data, sizeof(data), 
-//             "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
-//             dap_chain_addr_to_str(l_wallet_addr), a_net_name);
-//     DAP_DEL_Z(l_wallet_addr);
-//     json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port);
-//     uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell);
-
-//     uint256_t l_value_sell = a_datoshi_sell;
-//     if (!dap_strcmp(s_get_native_ticker(a_net_name), a_token_sell)) {
-//         if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) {
-//             return NULL; // XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE
-//         }
-//     } else { // sell non-native ticker
-//         uint256_t l_fee_value = get_balance_from_json(l_json_outs, s_get_native_ticker(a_net_name));
-//         if (compare256(l_fee_value, a_fee) == -1) {
-//             return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET
-//         }
-//     }
-//     if (compare256(l_value, l_value_sell) == -1) {
-//         return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET
-//     }
-//     // Create the price
-//     dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
-//     if (!l_price) {
-//         return NULL; // XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED
-//     }
-//     dap_stpcpy(l_price->token_sell, a_token_sell);
-//     dap_stpcpy(l_price->token_buy, a_token_buy);
-//     l_price->datoshi_sell = a_datoshi_sell;
-//     l_price->rate = a_rate;
-//     l_price->fee = a_fee;
-//     dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name, a_url_str, a_port);
-//     return l_tx;
-// }
 
 json_object *dap_get_remote_tx_outs(const char *a_token_ticker,  dap_chain_addr_t * a_addr, compose_config_t *a_config) { 
     char data[512];
@@ -1186,151 +961,359 @@ json_object *dap_get_remote_tx_outs(const char *a_token_ticker,  dap_chain_addr_
     return l_outs;
 }
 
+uint256_t get_balance_from_json(json_object *l_json_outs, const char *a_token_sell) {
+    uint256_t l_value = {};
+    if (l_json_outs && json_object_is_type(l_json_outs, json_type_array)) {
+        for (size_t i = 0; i < json_object_array_length(l_json_outs); i++) {
+            json_object *outer_array = json_object_array_get_idx(l_json_outs, i);
+            if (json_object_is_type(outer_array, json_type_array)) {
+                for (size_t j = 0; j < json_object_array_length(outer_array); j++) {
+                    json_object *addr_obj = json_object_array_get_idx(outer_array, j);
+                    if (json_object_is_type(addr_obj, json_type_object)) {
+                        json_object *tokens = NULL;
+                        if (json_object_object_get_ex(addr_obj, "tokens", &tokens) && json_object_is_type(tokens, json_type_array)) {
+                            for (size_t k = 0; k < json_object_array_length(tokens); k++) {
+                                json_object *token_obj = json_object_array_get_idx(tokens, k);
+                                json_object *token = NULL;
+                                if (json_object_object_get_ex(token_obj, "token", &token) && json_object_is_type(token, json_type_object)) {
+                                    json_object *ticker = NULL;
+                                    if (json_object_object_get_ex(token, "ticker", &ticker) && json_object_is_type(ticker, json_type_string)) {
+                                        const char *ticker_str = json_object_get_string(ticker);
+                                        if (strcmp(ticker_str, a_token_sell) == 0) {
+                                            json_object *datoshi = NULL;
+                                            if (json_object_object_get_ex(token_obj, "datoshi", &datoshi) && json_object_is_type(datoshi, json_type_string)) {
+                                                const char *datoshi_str = json_object_get_string(datoshi);
+                                                l_value = dap_uint256_scan_uninteger(datoshi_str);
+                                                break;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return l_value;
+}
 
-// dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
-//                                                                  const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port)
-// {
-//     if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) {
-//         return NULL;
-//     }
-//     const char *l_native_ticker = s_get_native_ticker(a_net_name);
-//     bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker);
-//     // find the transactions from which to take away coins
-//     uint256_t l_value_transfer; // how many coins to transfer
-//     uint256_t l_value_need = a_price->datoshi_sell,
-//               l_net_fee,
-//               l_total_fee = a_price->fee,
-//               l_fee_transfer;
-//     dap_chain_addr_t * l_addr_net_fee = NULL;
-//     dap_list_t *l_list_fee_out = NULL;
+bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) {
+    if (json_object_is_type(l_json_coins, json_type_array)) {
+        for (size_t i = 0; i < json_object_array_length(l_json_coins); i++) {
+            json_object *token_array = json_object_array_get_idx(l_json_coins, i);
+            if (json_object_is_type(token_array, json_type_array)) {
+                for (size_t j = 0; j < json_object_array_length(token_array); j++) {
+                    json_object *token_obj = json_object_array_get_idx(token_array, j);
+                    json_object *token_name = NULL;
+                    if (json_object_object_get_ex(token_obj, "-->Token name", &token_name) && json_object_is_type(token_name, json_type_string)) {
+                        const char *token_name_str = json_object_get_string(token_name);
+                        if (strcmp(token_name_str, a_token) == 0) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return false;
+}
 
-//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee, a_url_str, a_port);
-//     if (l_net_fee_used)
-//         SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
 
-//     dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name));
-//     dap_chain_addr_t l_seller_addr = *l_wallet_addr;
-//     json_object *l_outs_native = dap_get_remote_tx_outs(a_native_ticker, a_net_name, l_wallet_addr, a_url_str, a_port);
-//     if (!l_outs_native) {
-//         return NULL;
-//     }
+typedef enum dap_xchange_compose_error {
+    DAP_XCHANGE_COMPOSE_ERROR_NONE = 0,
+    DAP_XCHANGE_COMPOSE_ERROR_INVALID_ARGUMENT,
+    DAP_XCHANGE_COMPOSE_ERROR_RATE_IS_ZERO,
+    DAP_XCHANGE_COMPOSE_ERROR_FEE_IS_ZERO,
+    DAP_XCHANGE_COMPOSE_ERROR_VALUE_SELL_IS_ZERO,
+    DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_GET_TX_OUTS,
+    DAP_XCHANGE_COMPOSE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER,
+    DAP_XCHANGE_COMPOSE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE,
+    DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET,
+    DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET,
+    DAP_XCHANGE_COMPOSE_ERROR_MEMORY_ALLOCATED,
+    DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS_TO_PAY_FEE,
+    DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS_TO_TRANSFER,
+    DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_COMPOSE_THE_TRANSACTION_INPUT,
+    DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_COMPOSE_THE_TRANSACTION_CONDITIONAL_OUTPUT,
+    DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_NETWORK_FEE_OUTPUT,
+    DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_VALIDATOR_FEE_OUTPUT,
+    DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_COIN_BACK_OUTPUT,
+    DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_FEE_BACK_OUTPUT,
+    DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE
+} dap_xchange_compose_error_t;
+
+json_object* dap_tx_create_xchange_compose(const char *l_net_name, const char *l_token_buy, const char *l_token_sell, const char *l_wallet_name, const char *l_wallet_path, const char *l_value_str, const char *l_rate_str, const char *l_fee_str, const char *l_url_str, uint16_t l_port){
+    compose_config_t *l_config = s_compose_config_init(l_net_name, l_url_str, l_port);
+    if (!l_config) {
+        json_object* l_json_obj_ret = json_object_new_object();
+        dap_json_compose_error_add(l_json_obj_ret, DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE, "Can't create compose config");
+        return l_json_obj_ret;
+    }
 
-//     json_object *l_outs = NULL;
-//     if (!dap_strcmp(a_price->token_sell, a_native_ticker)) {
-//         l_outs = l_outs_native;
-//     } else {
-//         l_outs = dap_get_remote_tx_outs(a_price->token_sell, a_net_name, l_wallet_addr, a_url_str, a_port);
-//     }
-//     DAP_DELETE(l_wallet_addr);
-//     int l_out_native_count = json_object_array_length(l_outs_native);
-//     int l_out_count = json_object_array_length(l_outs);
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL);
+    if(!l_wallet) {
+        dap_json_compose_error_add(l_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE, "wallet %s does not exist", l_wallet_name);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if (l_single_channel)
-//         SUM_256_256(l_value_need, l_total_fee, &l_value_need);
-//     else if (!IS_ZERO_256(l_total_fee)) {
-//         l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
-//                                                                l_total_fee, 
-//                                                                &l_fee_transfer);
-//         if (!l_list_fee_out) {
-//             printf("Not enough funds to pay fee");
-//             json_object_put(l_outs_native);
-//             json_object_put(l_outs);
-//             return NULL;
-//         }
-//     }
-//     dap_list_t *l_list_used_out = NULL;
-//     l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_out_count,
-//                                                             l_value_need,
-//                                                             &l_value_transfer);
-//     if (!l_list_used_out) {
-//         printf("Not enough funds to transfer");
-//         json_object_put(l_outs_native);
-//         json_object_put(l_outs);
-//         return NULL;
-//     }
 
-//     // create empty transaction
-//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-//     // add 'in' items to sell
-//     uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-//     dap_list_free_full(l_list_used_out, NULL);
-//     if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) {
-//         dap_chain_datum_tx_delete(l_tx);
-//         printf("Can't compose the transaction input\n");
-//         return NULL;
-//     }
-//     if (!l_single_channel) {
-//         // add 'in' items to fee
-//         uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-//         if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Can't compose the transaction input\n");
-//             return NULL;
-//         }
-//     }
+    uint256_t l_value = dap_chain_balance_scan(l_value_str);
+    if (IS_ZERO_256(l_value)) {
+        dap_json_compose_error_add(l_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE, "Invalid parameter value, rate or fee is 0, use required format 1.0e+18 ot in datoshi");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    uint256_t l_rate = dap_chain_balance_scan(l_rate_str);
+    if (IS_ZERO_256(l_rate)) {
+        dap_json_compose_error_add(l_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE, "Invalid parameter rate");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+    if (IS_ZERO_256(l_fee)) {
+        dap_json_compose_error_add(l_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE, "Invalid parameter fee");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     // add 'out_cond' & 'out' items
+    dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_token_buy,
+                                     l_token_sell, l_value, l_rate, l_fee, l_wallet, l_config);
+    if (l_tx) {
+        dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
+        dap_chain_datum_tx_delete(l_tx);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     {
-//         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, s_get_net_id(a_net_name), a_price->datoshi_sell,
-//                                                                                                 s_get_net_id(a_net_name), a_price->token_buy, a_price->rate,
-//                                                                                                 &l_seller_addr, NULL, 0);
-//         if (!l_tx_out) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Can't compose the transaction conditional output\n");
-//             return NULL;
-//         }
-//         dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
-//         DAP_DELETE(l_tx_out);
-//         // Network fee
-//         if (l_net_fee_used) {
-//             if ((l_single_channel &&
-//                         dap_chain_datum_tx_add_out_item(&l_tx, l_addr_net_fee, l_net_fee) != 1) ||
-//                     (!l_single_channel &&
-//                         dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Cant add network fee output\n");
-//                 return NULL;
-//             }
-//         }
-//         DAP_DELETE(l_addr_net_fee);
-//         // Validator's fee
-//         if (!IS_ZERO_256(a_price->fee)) {
-//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Cant add validator's fee output\n");
-//                 return NULL;
-//             }
-//         }
-//         // coin back
-//         uint256_t l_value_back = {};
-//         SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back);
-//         if (!IS_ZERO_256(l_value_back)) {
-//             if ((l_single_channel &&
-//                         dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) ||
-//                     (!l_single_channel &&
-//                         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);
-//                 printf("Cant add coin back output\n");
-//                 return NULL;
-//             }
-//         }
-//         // Fee coinback
-//         if (!l_single_channel) {
-//             uint256_t l_fee_coinback = {};
-//             SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback);
-//             if (!IS_ZERO_256(l_fee_coinback)) {
-//                 if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) {
-//                     dap_chain_datum_tx_delete(l_tx);
-//                     printf("Cant add fee back output\n");
-//                     return NULL;
-//                 }
-//             }
-//         }
-//     }
-//     return l_tx;
-// }
+    return s_compose_config_return_response_handler(l_config);
+}
+
+
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_token_buy,
+                                     const char *a_token_sell, uint256_t a_datoshi_sell,
+                                     uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, compose_config_t *a_config){
+    if (!a_config) {
+        return NULL;
+    }
+    if ( !a_token_buy || !a_token_sell || !a_wallet) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_ARGUMENT, "Invalid parameter");
+        return NULL;
+    }
+    if (IS_ZERO_256(a_rate)) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_RATE_IS_ZERO, "Invalid parameter rate");
+        return NULL;
+    }
+    if (IS_ZERO_256(a_fee)) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_FEE_IS_ZERO, "Invalid parameter fee");
+        return NULL;
+    }
+    if (IS_ZERO_256(a_datoshi_sell)) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_VALUE_SELL_IS_ZERO, "Invalid parameter value sell");
+        return NULL;
+    }
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_config->net_name);
+    json_object *l_json_coins = dap_request_command_to_rpc(data, a_config);
+    if (!l_json_coins) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_GET_TX_OUTS, "Can't get tx outs");
+        return NULL;
+    }
+    if (!check_token_in_ledger(l_json_coins, a_token_sell) || !check_token_in_ledger(l_json_coins, a_token_buy)) {
+        json_object_put(l_json_coins);
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER, "Token ticker sell or buy is not found in ledger");
+        return NULL;
+    }
+    json_object_put(l_json_coins);
+    dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_config->net_name));
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
+            dap_chain_addr_to_str(l_wallet_addr), a_config->net_name);
+    DAP_DEL_Z(l_wallet_addr);
+    json_object *l_json_outs = dap_request_command_to_rpc(data, a_config);
+    uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell);
+
+    uint256_t l_value_sell = a_datoshi_sell;
+    if (!dap_strcmp(s_get_native_ticker(a_config->net_name), a_token_sell)) {
+        if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) {
+            dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE, "Integer overflow with sum of value and fee");
+            return NULL;
+        }
+    } else { // sell non-native ticker
+        uint256_t l_fee_value = get_balance_from_json(l_json_outs, s_get_native_ticker(a_config->net_name));
+        if (compare256(l_fee_value, a_fee) == -1) {
+            dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET, "Not enough cash for fee in specified wallet");
+            return NULL;
+        }
+    }
+    if (compare256(l_value, l_value_sell) == -1) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET, "Not enough cash in specified wallet");
+        return NULL;
+    }
+    // Create the price
+    dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
+    if (!l_price) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_MEMORY_ALLOCATED, "Memory allocated");
+        return NULL;
+    }
+    dap_stpcpy(l_price->token_sell, a_token_sell);
+    dap_stpcpy(l_price->token_buy, a_token_buy);
+    l_price->datoshi_sell = a_datoshi_sell;
+    l_price->rate = a_rate;
+    l_price->fee = a_fee;
+    dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_config->net_name), a_config);
+    return l_tx;
+}
+
+
+
+dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
+                                                                 const char *a_native_ticker, compose_config_t *a_config)
+{
+    if (!a_config) {
+        return NULL;
+    }
+    if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_ARGUMENT, "Invalid parameter");
+        return NULL;
+    }
+    const char *l_native_ticker = s_get_native_ticker(a_config->net_name);
+    bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker);
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer; // how many coins to transfer
+    uint256_t l_value_need = a_price->datoshi_sell,
+              l_net_fee,
+              l_total_fee = a_price->fee,
+              l_fee_transfer;
+    dap_chain_addr_t * l_addr_net_fee = NULL;
+    dap_list_t *l_list_fee_out = NULL;
+
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_net_fee, a_config);
+    if (l_net_fee_used)
+        SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
+
+    dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_config->net_name));
+    dap_chain_addr_t l_seller_addr = *l_wallet_addr;
+    json_object *l_outs_native = dap_get_remote_tx_outs(a_native_ticker, l_wallet_addr, a_config);
+    if (!l_outs_native) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_GET_TX_OUTS, "Can't get tx outs");
+        return NULL;
+    }
+
+    json_object *l_outs = NULL;
+    if (!dap_strcmp(a_price->token_sell, a_native_ticker)) {
+        l_outs = l_outs_native;
+    } else {
+        l_outs = dap_get_remote_tx_outs(a_price->token_sell, l_wallet_addr, a_config);
+    }
+    DAP_DELETE(l_wallet_addr);
+    int l_out_native_count = json_object_array_length(l_outs_native);
+    int l_out_count = json_object_array_length(l_outs);
+
+    if (l_single_channel)
+        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+    else if (!IS_ZERO_256(l_total_fee)) {
+        l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+                                                               l_total_fee, 
+                                                               &l_fee_transfer);
+        if (!l_list_fee_out) {
+            dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS_TO_PAY_FEE, "Not enough funds to pay fee");
+            json_object_put(l_outs_native);
+            json_object_put(l_outs);
+            return NULL;
+        }
+    }
+    dap_list_t *l_list_used_out = NULL;
+    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_out_count,
+                                                            l_value_need,
+                                                            &l_value_transfer);
+    if (!l_list_used_out) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS_TO_TRANSFER, "Not enough funds to transfer");
+        json_object_put(l_outs_native);
+        json_object_put(l_outs);
+        return NULL;
+    }
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    // add 'in' items to sell
+    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+    dap_list_free_full(l_list_used_out, NULL);
+    if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) {
+        dap_chain_datum_tx_delete(l_tx);
+        dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_COMPOSE_THE_TRANSACTION_INPUT, "Can't compose the transaction input");
+        return NULL;
+    }
+    if (!l_single_channel) {
+        // add 'in' items to fee
+        uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+        if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_COMPOSE_THE_TRANSACTION_INPUT, "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, s_get_net_id(a_config->net_name), a_price->datoshi_sell,
+                                                                                                s_get_net_id(a_config->net_name), a_price->token_buy, a_price->rate,
+                                                                                                &l_seller_addr, NULL, 0);
+        if (!l_tx_out) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_COMPOSE_THE_TRANSACTION_CONDITIONAL_OUTPUT, "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);
+        // Network fee
+        if (l_net_fee_used) {
+            if ((l_single_channel &&
+                        dap_chain_datum_tx_add_out_item(&l_tx, l_addr_net_fee, l_net_fee) != 1) ||
+                    (!l_single_channel &&
+                        dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_NETWORK_FEE_OUTPUT, "Can't add network fee output");
+                return NULL;
+            }
+        }
+        DAP_DELETE(l_addr_net_fee);
+        // Validator's fee
+        if (!IS_ZERO_256(a_price->fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_VALIDATOR_FEE_OUTPUT, "Can't add validator's fee output");
+                return NULL;
+            }
+        }
+        // coin back
+        uint256_t l_value_back = {};
+        SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back);
+        if (!IS_ZERO_256(l_value_back)) {
+            if ((l_single_channel &&
+                        dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) ||
+                    (!l_single_channel &&
+                        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_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_COIN_BACK_OUTPUT, "Can't add coin back output");
+                return NULL;
+            }
+        }
+        // Fee coinback
+        if (!l_single_channel) {
+            uint256_t l_fee_coinback = {};
+            SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback);
+            if (!IS_ZERO_256(l_fee_coinback)) {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_FEE_BACK_OUTPUT, "Can't add fee back output");
+                    return NULL;
+                }
+            }
+        }
+    }
+    return l_tx;
+}
 
 // // tx_cond_create -net <net_name> -token <token_ticker> -w <wallet_name> -cert <pub_cert_name> -value <value_datoshi> -fee <value> -unit {B | SEC} -srv_uid <numeric_uid>
 // int dap_tx_cond_create_compose(int argc, char ** argv)
@@ -4013,7 +3996,7 @@ static dap_chain_datum_tx_t *dap_order_tx_create_compose(dap_enc_key_t *a_key,
 }
 
 
-json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) {
+json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) {
     compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port);
     if (!l_config) {
         json_object *l_json_obj_ret = json_object_new_object();
@@ -4076,7 +4059,7 @@ json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str
     return s_compose_config_return_response_handler(l_config);
 }
 
-json_object * dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) {
+json_object * dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) {
 
     compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port);
     if (!l_config) {
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 7c6203532d..fcca731a13 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -68,8 +68,8 @@ extern "C" {
 const char* dap_compose_get_net_url(const char* name);
 uint16_t dap_compose_get_net_port(const char* name);
 
-json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port);
-int dap_tx_create_xchange_compose(int argc, char ** argv);
+json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port);
+json_object* dap_tx_create_xchange_compose(const char *l_net_str, const char *l_token_sell, const char *l_token_buy, const char *l_wallet_str, const char *l_wallet_path, const char *l_value_str, const char *l_rate_str, const char *l_fee_str, const char *l_url_str, uint16_t l_port);
 int dap_tx_cond_create_compose(int argc, char ** argv);
 int dap_cli_hold_compose(int a_argc, char **a_argv);
 int dap_cli_take_compose(int a_argc, char **a_argv);
@@ -86,7 +86,7 @@ typedef enum {
     STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -8,
     STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -9
 } dap_cli_srv_stake_order_create_staker_error_t;
-json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port);
+json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port);
 
 typedef enum {
     SRV_STAKE_ORDER_REMOVE_COMPOSE_OK = 0,
@@ -124,7 +124,7 @@ typedef enum {
 } srv_stake_order_remove_compose_error_t;
 dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
                                      dap_chain_wallet_t *a_wallet, compose_config_t *a_config);
-json_object* dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port);
+json_object* dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port);
 
 typedef enum {
     STAKE_DELEGATE_COMPOSE_OK = 0,
@@ -218,10 +218,10 @@ int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
 dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer);
 dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to,
         const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, compose_config_t *a_config);
-dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, const char *a_token_sell, uint256_t a_datoshi_sell,
-                                     uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port);
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_token_buy, const char *a_token_sell, uint256_t a_datoshi_sell,
+                                     uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, compose_config_t *a_config);
 dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
-                                                                const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port);
+                                                                 const char *a_native_ticker, compose_config_t *a_config);
 dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name,
         dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
         const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-- 
GitLab


From b52a5e93f425309f3a5b9cd38a4bafa78fe437a4 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Mon, 14 Apr 2025 14:47:25 +0700
Subject: [PATCH 49/53] [*] hold tx_cond

---
 modules/compose/dap_chain_tx_compose.c        | 1045 ++++++++---------
 .../compose/include/dap_chain_tx_compose.h    |   30 +-
 2 files changed, 488 insertions(+), 587 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 2349aa5e5d..ad09be62ec 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -1315,640 +1315,525 @@ dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xc
     return l_tx;
 }
 
-// // tx_cond_create -net <net_name> -token <token_ticker> -w <wallet_name> -cert <pub_cert_name> -value <value_datoshi> -fee <value> -unit {B | SEC} -srv_uid <numeric_uid>
-// int dap_tx_cond_create_compose(int argc, char ** argv)
-// {
-//     int arg_index = 1;
-//     const char * l_token_ticker = NULL;
-//     const char * l_wallet_str = NULL;
-//     const char * l_cert_str = NULL;
-//     const char * l_value_datoshi_str = NULL;
-//     const char * l_value_fee_str = NULL;
-//     const char * l_net_name = NULL;
-//     const char * l_unit_str = NULL;
-//     const char * l_srv_uid_str = NULL;
-//     uint256_t l_value_datoshi = {};    
-//     uint256_t l_value_fee = {};
-//     const char * l_url_str = NULL;
-//     const char * l_port_str = NULL;
-//     uint16_t l_port = 0;
-
-//     const char *l_wallet_path = NULL;
-//     dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path);
-//     if (!l_wallet_path) {
-//         l_wallet_path =
-//         #ifdef DAP_OS_WINDOWS
-//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-//         #elif defined DAP_OS_MAC
-//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-//         #elif defined DAP_OS_UNIX
-//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-//         #endif
-//     }  
-
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_datoshi_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_value_fee_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str);
 
-//     if(!l_token_ticker) {
-//         printf("tx_cond_create requires parameter '-token'\n");
-//         return -2;
-//     }
-//     if (!l_wallet_str) {
-//         printf("tx_cond_create requires parameter '-w'\n");
-//         return -3;
-//     }
-//     if (!l_cert_str) {
-//         printf("tx_cond_create requires parameter '-cert'\n");
-//         return -4;
-//     }
-//     if(!l_value_datoshi_str) {
-//         printf("tx_cond_create requires parameter '-value'\n");
-//         return -5;
-//     }
-//     if(!l_value_fee_str){
-//         printf("tx_cond_create requires parameter '-fee'\n");
-//         return -6;
-//     }
-//     if(!l_net_name) {
-//         printf("tx_cond_create requires parameter '-net'\n");
-//         return -7;
-//     }
-//     if(!l_url_str) {
-//         l_url_str = dap_compose_get_net_url(l_net_name);
-//     }
-//     if(!l_port_str) {
-//         l_port = dap_compose_get_net_port(l_net_name);
-//     } else {
-//         l_port = atoi(l_port_str);
-//     }
-//     if(!l_unit_str) {
-//         printf("tx_cond_create requires parameter '-unit'\n");
-//         return -8;
-//     }
-
-//     if(!l_srv_uid_str) {
-//         printf("tx_cond_create requires parameter '-srv_uid'\n");
-//         return -9;
-//     }
-//     dap_chain_net_srv_uid_t l_srv_uid = {};
-//     l_srv_uid.uint64 = strtoll(l_srv_uid_str, NULL, 10);
-//     if (!l_srv_uid.uint64) {
-//         printf("Can't find service UID %s\n", l_srv_uid_str);
-//         return -10;
-//     }
-
-//     dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)l_unit_str)};
-
-//     if(l_price_unit.enm == SERV_UNIT_UNDEFINED) {
-//         printf("Can't recognize unit '%s'. Unit must look like { B | SEC }\n", l_unit_str);
-//         return -11;
-//     }
-
-//     l_value_datoshi = dap_chain_balance_scan(l_value_datoshi_str);
-//     if(IS_ZERO_256(l_value_datoshi)) {
-//         printf("Can't recognize value '%s' as a number\n", l_value_datoshi_str);
-//         return -12;
-//     }
-
-//     l_value_fee = dap_chain_balance_scan(l_value_fee_str);
-//     if(IS_ZERO_256(l_value_fee)) {
-//         printf("Can't recognize value '%s' as a number\n", l_value_fee_str);
-//         return -13;
-//     }
-
-//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
-//     if(!l_wallet) {
-//         printf("Can't open wallet '%s'\n", l_wallet_str);
-//         return -15;
-//     }
-
-//     dap_cert_t *l_cert_cond = dap_cert_find_by_name(l_cert_str);
-//     if(!l_cert_cond) {
-//         dap_chain_wallet_close(l_wallet);
-//         printf("Can't find cert '%s'\n", l_cert_str);
-//         return -16;
-//     }
-
-//     dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
-//     dap_pkey_t *l_key_cond = dap_pkey_from_enc_key(l_cert_cond->enc_key);
-//     if (!l_key_cond) {
-//         dap_chain_wallet_close(l_wallet);
-//         dap_enc_key_delete(l_key_from);
-//         printf("Cert '%s' doesn't contain a valid public key\n", l_cert_str);
-//         return -17;
-//     }
-
-//     uint256_t l_value_per_unit_max = {};
-//     dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker,
-//                                                         l_value_datoshi, l_value_per_unit_max, l_price_unit,
-//                                                         l_srv_uid, l_value_fee, NULL, 0, l_url_str, l_port);
+json_object* dap_tx_cond_create_compose(const char *a_net_name, const char *a_token_ticker, const char *a_wallet_str, const char *a_wallet_path,
+                                        const char *a_cert_str, const char *a_value_datoshi_str, const char *a_value_fee_str, const char *a_unit_str, 
+                                        const char *a_srv_uid_str, const char *a_url_str, uint16_t a_port) {    
+    compose_config_t *l_config = s_compose_config_init(a_net_name, a_url_str, a_port);
+    if (!l_config) {
+        json_object* l_json_obj_ret = json_object_new_object();
+        dap_json_compose_error_add(l_json_obj_ret, TX_COND_CREATE_COMPOSE_ERROR_INVALID_FEE, "Can't create compose config");
+        return l_json_obj_ret;
+    }
     
-//     json_object * l_json_obj_ret = json_object_new_object();
-//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-//     printf("%s", json_object_to_json_string(l_json_obj_ret));
-//     json_object_put(l_json_obj_ret);
-//     dap_chain_datum_tx_delete(l_tx);
-//     dap_chain_wallet_close(l_wallet);
-//     dap_enc_key_delete(l_key_from);
-//     DAP_DELETE(l_key_cond);
-//     return 0;
-// }
+    uint256_t l_value_datoshi = {};    
+    uint256_t l_value_fee = {};
+    dap_chain_net_srv_uid_t l_srv_uid = {};
+    l_srv_uid.uint64 = strtoll(a_srv_uid_str, NULL, 10);
+    if (!l_srv_uid.uint64) {
+        dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_INVALID_SERVICE_UID, "Can't find service UID %s", a_srv_uid_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
+    dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)a_unit_str)};
 
-// dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name,
-//         dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
-//         const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-//         uint256_t a_value, uint256_t a_value_per_unit_max,
-//         dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
-//         uint256_t a_value_fee, const void *a_cond,
-//         size_t a_cond_size, const char *a_url_str, uint16_t a_port)
-// {
-//     // check valid param
-//     if (!a_net_name || !*a_net_name || !a_key_from || !a_key_cond ||
-//             !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value) || !a_url_str || !*a_url_str || a_port == 0)
-//         return NULL;
+    if(l_price_unit.enm == SERV_UNIT_UNDEFINED) {
+        dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_INVALID_UNIT, "Can't recognize unit '%s'. Unit must look like { B | SEC }\n", a_unit_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if (dap_strcmp(s_get_native_ticker(a_net_name), a_token_ticker)) {
-//         printf("Pay for service should be only in native token ticker\n");
-//         return NULL;
-//     }
+    l_value_datoshi = dap_chain_balance_scan(a_value_datoshi_str);
+    if(IS_ZERO_256(l_value_datoshi)) {
+        dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_INVALID_VALUE, "Can't recognize value '%s' as a number\n", a_value_datoshi_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     uint256_t l_net_fee = {};
-//     dap_chain_addr_t* l_addr_fee = NULL;
-//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port);
-//     // find the transactions from which to take away coins
-//     uint256_t l_value_transfer = {}; // how many coins to transfer
-//     uint256_t l_value_need = {};
-//     SUM_256_256(a_value, a_value_fee, &l_value_need);
-//     if (l_net_fee_used) {
-//         SUM_256_256(l_value_need, l_net_fee, &l_value_need);
-//     }
-//     // where to take coins for service
-//     dap_chain_addr_t l_addr_from;
-//     dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, s_get_net_id(a_net_name));
-//     // list of transaction with 'out' items
-//     json_object *l_outs = NULL;
-//     int l_outputs_count = 0;
-//     if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) {
-//         return NULL;
-//     }
-//     dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
-//                                                             l_value_need,
-//                                                             &l_value_transfer);
-//     json_object_put(l_outs);
-//     if(!l_list_used_out) {
-//         printf("Nothing to transfer (not enough funds)\n");
-//         return NULL;
-//     }
+    l_value_fee = dap_chain_balance_scan(a_value_fee_str);
+    if(IS_ZERO_256(l_value_fee)) {
+        dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_INVALID_VALUE, "Can't recognize value '%s' as a number\n", a_value_fee_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     // create empty transaction
-//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-//     // add 'in' items
-//     {
-//         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-//         assert(EQUAL_256(l_value_to_items, l_value_transfer));
-//         dap_list_free_full(l_list_used_out, NULL);
-//     }
-//     // add 'out_cond' and 'out' items
-//     {
-//         uint256_t l_value_pack = {}; // how much coin add to 'out' items
-//         if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond,
-//                 a_cond_size) == 1) {
-//             SUM_256_256(l_value_pack, a_value, &l_value_pack);
-//         } else {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Cant add conditional output\n");
-//             return NULL;
-//         }
-//         // Network fee
-//         if (l_net_fee_used) {
-//             if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
-//                 SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-//             else {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 return NULL;
-//             }
-//         }
-//         // Validator's fee
-//         if (!IS_ZERO_256(a_value_fee)) {
-//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
-//                 SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
-//             else {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 return NULL;
-//             }
-//         }
-//         // coin back
-//         uint256_t l_value_back = {};
-//         SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-//         if (!IS_ZERO_256(l_value_back)) {
-//             if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Cant add coin back output\n");
-//                 return NULL;
-//             }
-//         }
-//     }
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path, NULL);
+    if(!l_wallet) {
+        dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_WALLET_OPEN_FAILED, "Can't open wallet '%s'\n", a_wallet_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     return l_tx;
-// }
+    dap_cert_t *l_cert_cond = dap_cert_find_by_name(a_cert_str);
+    if(!l_cert_cond) {
+        dap_chain_wallet_close(l_wallet);
+        dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_CERT_NOT_FOUND, "Can't find cert '%s'\n", a_cert_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-// // stake_lock hold -net <net_name> -w <wallet_name> -time_staking <YYMMDD> -token <ticker> -value <value> -fee <value>[-chain <chain_name>] [-reinvest <percentage>]
-// int  dap_cli_hold_compose(int a_argc, char **a_argv)
-// {
-//     int arg_index = 1;
-//     const char *l_net_name = NULL, *l_ticker_str = NULL, *l_coins_str = NULL,
-//             *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL,
-//             *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL;
-
-//     char 	l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
-//     dap_time_t              			l_time_staking		=	0;
-//     uint256_t						    l_reinvest_percent	=	{};
-//     uint256_t							l_value_delegated	=	{};
-//     uint256_t                           l_value_fee     	=	{};
-//     uint256_t 							l_value;
-//     dap_enc_key_t						*l_key_from;
-//     dap_chain_wallet_t					*l_wallet;
-//     dap_chain_addr_t					*l_addr_holder;
-//     const char                          *l_url_str = NULL;
-//     uint16_t                            l_port = 0;
+    dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
+    dap_pkey_t *l_key_cond = dap_pkey_from_enc_key(l_cert_cond->enc_key);
+    if (!l_key_cond) {
+        dap_chain_wallet_close(l_wallet);
+        dap_enc_key_delete(l_key_from);
+        dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_INVALID_CERT_KEY, "Cert '%s' doesn't contain a valid public key\n", a_cert_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     const char *l_wallet_path = NULL;
-//     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
-//     if (!l_wallet_path) {
-//         l_wallet_path =
-//         #ifdef DAP_OS_WINDOWS
-//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-//         #elif defined DAP_OS_MAC
-//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-//         #elif defined DAP_OS_UNIX
-//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-//         #endif
-//     }  
+    uint256_t l_value_per_unit_max = {};
+    dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_key_from, l_key_cond, a_token_ticker,
+                                                        l_value_datoshi, l_value_per_unit_max, l_price_unit,
+                                                        l_srv_uid, l_value_fee, NULL, 0, l_config);
+    if (l_tx) {
+        dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
+        dap_chain_datum_tx_delete(l_tx);
+    }
+    dap_chain_wallet_close(l_wallet);
+    dap_enc_key_delete(l_key_from);
+    DAP_DELETE(l_key_cond);
+    return s_compose_config_return_response_handler(l_config);
+}
 
 
-//     const char *l_hash_out_type = NULL;
-//     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
-//     if(!l_hash_out_type)
-//         l_hash_out_type = "hex";
-//     if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type, "base58")) {
-//         printf("Error: Invalid hash type argument\n");
-//         return -1;
-//     }
+dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
+        const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+        uint256_t a_value, uint256_t a_value_per_unit_max,
+        dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
+        uint256_t a_value_fee, const void *a_cond,
+        size_t a_cond_size, compose_config_t *a_config)
+{
+    // check valid param
+    if (!a_config->net_name || !*a_config->net_name || !a_key_from || !a_key_cond ||
+            !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value) || !a_config->url_str || !*a_config->url_str || a_config->port == 0)
+        return NULL;
 
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_name) || NULL == l_net_name) {
-//         printf("Error: Missing or invalid network argument\n");
-//         return -2;
-//     }
+    if (dap_strcmp(s_get_native_ticker(a_config->net_name), a_token_ticker)) {
+        dap_json_compose_error_add(a_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_NATIVE_TOKEN_REQUIRED, "Pay for service should be only in native token ticker\n");
+        return NULL;
+    }
 
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_ticker_str) || NULL == l_ticker_str || dap_strlen(l_ticker_str) > 8) {
-//         printf("Error: Missing or invalid token argument\n");
-//         return -3;
-//     }
+    uint256_t l_net_fee = {};
+    dap_chain_addr_t* l_addr_fee = NULL;
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, a_config);
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer = {}; // how many coins to transfer
+    uint256_t l_value_need = {};
+    SUM_256_256(a_value, a_value_fee, &l_value_need);
+    if (l_net_fee_used) {
+        SUM_256_256(l_value_need, l_net_fee, &l_value_need);
+    }
+    // where to take coins for service
+    dap_chain_addr_t l_addr_from;
+    dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, s_get_net_id(a_config->net_name));
+    // list of transaction with 'out' items
+    json_object *l_outs = NULL;
+    int l_outputs_count = 0;
+    if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, &l_outs, &l_outputs_count, a_config)) {
+        return NULL;
+    }
+    dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                            l_value_need,
+                                                            &l_value_transfer);
+    json_object_put(l_outs);
+    if(!l_list_used_out) {
+        dap_json_compose_error_add(a_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS, "Nothing to transfer (not enough funds)\n");
+        return NULL;
+    }
 
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) {
-//         l_url_str = dap_compose_get_net_url(l_net_name);
-//     }
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    // add 'in' items
+    {
+        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+        assert(EQUAL_256(l_value_to_items, l_value_transfer));
+        dap_list_free_full(l_list_used_out, NULL);
+    }
+    // add 'out_cond' and 'out' items
+    {
+        uint256_t l_value_pack = {}; // how much coin add to 'out' items
+        if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond,
+                a_cond_size) == 1) {
+            SUM_256_256(l_value_pack, a_value, &l_value_pack);
+        } else {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_COND_OUTPUT_FAILED, "Cant add conditional output\n");
+            return NULL;
+        }
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
+                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // coin back
+        uint256_t l_value_back = {};
+        SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+        if (!IS_ZERO_256(l_value_back)) {
+            if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_COIN_BACK_FAILED, "Cant add coin back output\n");
+                return NULL;
+            }
+        }
+    }
 
-//     const char *l_port_str = NULL;
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) {
-//         l_port = dap_compose_get_net_port(l_net_name);
-//     } else {
-//         l_port = atoi(l_port_str);
-//     }
+    return l_tx;
+}
 
-//     char data[512];
-//     snprintf(data, sizeof(data), 
-//             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name);
-//     json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
-//     if (!l_json_coins) {
-//         return -4;
-//     }
-//     if (!check_token_in_ledger(l_json_coins, l_ticker_str)) {
-//         printf("Error: Invalid token '%s'\n", l_ticker_str);
-//         return -4;
-//     }
+enum cli_hold_compose_error {
+    CLI_HOLD_COMPOSE_ERROR_INVALID_CONFIG = -1,
+    CLI_HOLD_COMPOSE_ERROR_INVALID_TOKEN = -2,
+    CLI_HOLD_COMPOSE_ERROR_INVALID_COINS = -3,
+    CLI_HOLD_COMPOSE_ERROR_NO_DELEGATED_TOKEN = -4,
+    CLI_HOLD_COMPOSE_ERROR_INVALID_EMISSION_RATE = -5,
+    CLI_HOLD_COMPOSE_ERROR_INVALID_COINS_FORMAT = -6,
+    CLI_HOLD_COMPOSE_ERROR_INVALID_FEE = -7,
+    CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING = -8,
+    CLI_HOLD_COMPOSE_ERROR_INVALID_REINVEST_PERCENTAGE = -9,
+    CLI_HOLD_COMPOSE_ERROR_UNABLE_TO_OPEN_WALLET = -10,
+    CLI_HOLD_COMPOSE_ERROR_UNABLE_TO_GET_WALLET_ADDRESS = -11,
+    CLI_HOLD_COMPOSE_ERROR_INSUFFICIENT_FUNDS = -12
+};
 
-//     if ((!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-coins", &l_coins_str) || NULL == l_coins_str) &&
-//             (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-value", &l_coins_str) || NULL == l_coins_str)) {
-//         printf("Error: Missing coins or value argument\n");
-//         return -5;
-//     }
+json_object * dap_cli_hold_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_ticker_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_coins_str, const char *a_time_staking_str,
+                                    const char *a_cert_str, const char *a_value_fee_str, const char *a_reinvest_percent_str, const char *a_url_str, uint16_t a_port) {
+    
+    compose_config_t *l_config = s_compose_config_init(a_net_name, a_url_str, a_port);
+    if (!l_config) {
+        json_object* l_json_obj_ret = json_object_new_object();
+        dap_json_compose_error_add(l_json_obj_ret, CLI_HOLD_COMPOSE_ERROR_INVALID_CONFIG, "Can't create compose config");
+        return l_json_obj_ret;
+    }
+    
+    char 	l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
+    dap_enc_key_t						*l_key_from;
+    dap_chain_wallet_t					*l_wallet;
+    dap_chain_addr_t					*l_addr_holder;
+    dap_time_t              			l_time_staking		=	0;
+    uint256_t						    l_reinvest_percent	=	{};
+    uint256_t							l_value_delegated	=	{};
+    uint256_t                           l_value_fee     	=	{};
+    uint256_t 							l_value             =   {};
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_config->net_name);
+    json_object *l_json_coins = dap_request_command_to_rpc(data, l_config);
+    if (!l_json_coins) {
+        return s_compose_config_return_response_handler(l_config);
+    }
+    if (!check_token_in_ledger(l_json_coins, a_ticker_str)) {
+        json_object_put(l_json_coins);
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TOKEN, "Invalid token '%s'\n", a_ticker_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if (IS_ZERO_256((l_value = dap_chain_balance_scan(l_coins_str)))) {
-//         printf("Error: Invalid coins format\n");
-//         return -6;
-//     }
 
-//     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str);
+    if (IS_ZERO_256((l_value = dap_chain_balance_scan(a_coins_str)))) {
+        json_object_put(l_json_coins);
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_COINS, "Invalid coins format\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
+
+    dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, a_ticker_str);
 
-//     if (!check_token_in_ledger(l_json_coins, l_delegated_ticker_str)) {
-//         printf("Error: No delegated token found\n");
-//         return -7;
-//     }
-//     json_object_put(l_json_coins);
+    if (!check_token_in_ledger(l_json_coins, l_delegated_ticker_str)) {
+        json_object_put(l_json_coins);
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_NO_DELEGATED_TOKEN, "No delegated token found\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    json_object_put(l_json_coins);
 
-//     uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001");  // TODO 16126
-//     // uint256_t l_emission_rate = dap_ledger_token_get_emission_rate(l_ledger, l_delegated_ticker_str);
-//     // if (IS_ZERO_256(l_emission_rate)) {
-//     //     printf("Error: Invalid token emission rate\n");
-//     //     return -8;
-//     // }
+    uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001");  // TODO 16126
+    // uint256_t l_emission_rate = dap_ledger_token_get_emission_rate(l_ledger, l_delegated_ticker_str);
+    // if (IS_ZERO_256(l_emission_rate)) {
+    //     printf("Error: Invalid token emission rate\n");
+    //     return -8;
+    // }
 
-//     if (MULT_256_COIN(l_value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) {
-//         printf("Error: Invalid coins format\n");
-//         return -9;
-//     }
+    if (MULT_256_COIN(l_value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_EMISSION_RATE, "Invalid coins format\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str);
-//     if (!l_chain_id_str) {
-//         printf("Error: Missing or invalid chain_id argument\n");
-//         return -10;
-//     }
 
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) {
-//         printf("Error: Missing wallet argument\n");
-//         return -11;
-//     }
+    if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(a_value_fee_str)))) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_FEE, "Invalid fee format\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) {
-//         printf("Error: Missing fee argument\n");
-//         return -12;
-//     }
+    // Read time staking
 
-//     if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) {
-//         printf("Error: Invalid fee format\n");
-//         return -13;
-//     }
 
-//     // Read time staking
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-time_staking", &l_time_staking_str) || !l_time_staking_str) {
-//         printf("Error: Missing time staking argument\n");
-//         return -14;
-//     }
+    if (dap_strlen(a_time_staking_str) != 6) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING, "Invalid time staking format\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if (dap_strlen(l_time_staking_str) != 6) {
-//         printf("Error: Invalid time staking format\n");
-//         return -15;
-//     }
+    char l_time_staking_month_str[3] = {a_time_staking_str[2], a_time_staking_str[3], 0};
+    int l_time_staking_month = atoi(l_time_staking_month_str);
+    if (l_time_staking_month < 1 || l_time_staking_month > 12) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING, "Invalid time staking month\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     char l_time_staking_month_str[3] = {l_time_staking_str[2], l_time_staking_str[3], 0};
-//     int l_time_staking_month = atoi(l_time_staking_month_str);
-//     if (l_time_staking_month < 1 || l_time_staking_month > 12) {
-//         printf("Error: Invalid time staking month\n");
-//         return -16;
-//     }
+    char l_time_staking_day_str[3] = {a_time_staking_str[4], a_time_staking_str[5], 0};
+    int l_time_staking_day = atoi(l_time_staking_day_str);
+    if (l_time_staking_day < 1 || l_time_staking_day > 31) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING, "Invalid time staking day\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     char l_time_staking_day_str[3] = {l_time_staking_str[4], l_time_staking_str[5], 0};
-//     int l_time_staking_day = atoi(l_time_staking_day_str);
-//     if (l_time_staking_day < 1 || l_time_staking_day > 31) {
-//         printf("Error: Invalid time staking day\n");
-//         return -17;
-//     }
+    l_time_staking = dap_time_from_str_simplified(a_time_staking_str);
+    if (0 == l_time_staking) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING, "Invalid time staking\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    dap_time_t l_time_now = dap_time_now();
+    if (l_time_staking < l_time_now) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING, "Time staking is in the past\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    l_time_staking -= l_time_now;
 
-//     l_time_staking = dap_time_from_str_simplified(l_time_staking_str);
-//     if (0 == l_time_staking) {
-//         printf("Error: Invalid time staking\n");
-//         return -18;
-//     }
-//     dap_time_t l_time_now = dap_time_now();
-//     if (l_time_staking < l_time_now) {
-//         printf("Error: Time staking is in the past\n");
-//         return -19;
-//     }
-//     l_time_staking -= l_time_now;
+    if ( NULL != a_reinvest_percent_str) {
+        l_reinvest_percent = dap_chain_coins_to_balance(a_reinvest_percent_str);
+        if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1) {
+            dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_REINVEST_PERCENTAGE, "Invalid reinvest percentage\n");
+            return s_compose_config_return_response_handler(l_config);
+        }
+        if (IS_ZERO_256(l_reinvest_percent)) {
+            int l_reinvest_percent_int = atoi(a_reinvest_percent_str);
+            if (l_reinvest_percent_int < 0 || l_reinvest_percent_int > 100) {
+                dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_REINVEST_PERCENTAGE, "Invalid reinvest percentage\n");
+                return s_compose_config_return_response_handler(l_config);
+            }
+            l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int);
+            MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent);
+        }
+    }
 
-//     if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-reinvest", &l_reinvest_percent_str) && NULL != l_reinvest_percent_str) {
-//         l_reinvest_percent = dap_chain_coins_to_balance(l_reinvest_percent_str);
-//         if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1) {
-//             printf("Error: Invalid reinvest percentage\n");
-//             return -20;
-//         }
-//         if (IS_ZERO_256(l_reinvest_percent)) {
-//             int l_reinvest_percent_int = atoi(l_reinvest_percent_str);
-//             if (l_reinvest_percent_int < 0 || l_reinvest_percent_int > 100) {
-//                 printf("Error: Invalid reinvest percentage\n");
-//                 return -21;
-//             }
-//             l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int);
-//             MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent);
-//         }
-//     }
+    if(NULL == (l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path, NULL))) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_UNABLE_TO_OPEN_WALLET, "Unable to open wallet '%s'\n", a_wallet_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) {
-//         printf("Error: Unable to open wallet '%s'\n", l_wallet_str);
-//         return -22;
-//     }
 
+    if (NULL == (l_addr_holder = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(a_net_name)))) {
+        dap_chain_wallet_close(l_wallet);
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_UNABLE_TO_GET_WALLET_ADDRESS, "Unable to get wallet address for '%s'\n", a_wallet_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if (NULL == (l_addr_holder = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)))) {
-//         dap_chain_wallet_close(l_wallet);
-//         printf("Error: Unable to get wallet address for '%s'\n", l_wallet_str);
-//         return -24;
-//     }
+    snprintf(data, sizeof(data), 
+        "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
+        dap_chain_addr_to_str(l_addr_holder), l_config->net_name);
+    DAP_DEL_Z(l_addr_holder);
 
-//     snprintf(data, sizeof(data), 
-//         "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", 
-//         dap_chain_addr_to_str(l_addr_holder), l_net_name);
-//     DAP_DEL_Z(l_addr_holder);
-
-//     json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port);
-//     uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str);
-//     json_object_put(l_json_outs);
-//     if (compare256(l_value_balance, l_value) == -1) {
-//         dap_chain_wallet_close(l_wallet);
-//         printf("Error: Insufficient funds in wallet\n");
-//         return -23;
-//     }
+    json_object *l_json_outs = dap_request_command_to_rpc(data, l_config);
+    uint256_t l_value_balance = get_balance_from_json(l_json_outs, a_ticker_str);
+    json_object_put(l_json_outs);
+    if (compare256(l_value_balance, l_value) == -1) {
+        dap_chain_wallet_close(l_wallet);
+        dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INSUFFICIENT_FUNDS, "Insufficient funds in wallet\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
+    l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
 
-//     // Make transfer transaction
-//     dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_net_name, l_key_from,
-//                                                            l_ticker_str, l_value, l_value_fee,
-//                                                            l_time_staking, l_reinvest_percent,
-//                                                            l_delegated_ticker_str, l_value_delegated, l_chain_id_str, l_url_str, l_port);
+    // Make transfer transaction
+    dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_key_from,
+                                                           a_ticker_str, l_value, l_value_fee,
+                                                           l_time_staking, l_reinvest_percent,
+                                                           l_delegated_ticker_str, l_value_delegated, a_chain_id_str, l_config);
 
-//     json_object * l_json_obj_ret = json_object_new_object();
-//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-//     printf("%s", json_object_to_json_string(l_json_obj_ret));
-//     json_object_put(l_json_obj_ret);
-//     dap_chain_datum_tx_delete(l_tx);
+    dap_chain_wallet_close(l_wallet);
+    dap_enc_key_delete(l_key_from);
+    if (l_tx) {
+        dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
+        dap_chain_datum_tx_delete(l_tx);
+    }
 
-//     dap_chain_wallet_close(l_wallet);
-//     dap_enc_key_delete(l_key_from);
-    
-//     return 0;
-// }
+    return s_compose_config_return_response_handler(l_config);
+}
 
+typedef enum {
+    STAKE_LOCK_DATUM_CREATE_ERROR_NOT_ENOUGH_FUNDS_TO_PAY_FEE = -1,
+    STAKE_LOCK_DATUM_CREATE_ERROR_NOT_ENOUGH_FUNDS_TO_TRANSFER = -2,
+    STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_CONDITIONAL_OUTPUT = -3,
+    STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_NETWORK_FEE_OUTPUT = -4,
+    STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_VALIDATOR_FEE_OUTPUT = -5,
+    STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_COIN_BACK_OUTPUT_FOR_MAIN_TICKER = -6,
+    STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_COIN_BACK_OUTPUT_FOR_NATIVE_TICKER = -7,
+    STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_DELEGATED_TOKEN_EMISSION_OUTPUT = -8
+} stake_lock_datum_create_error_t;
+
+dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(dap_enc_key_t *a_key_from,
+                                                    const char *a_main_ticker,
+                                                    uint256_t a_value, uint256_t a_value_fee,
+                                                    dap_time_t a_time_staking, uint256_t a_reinvest_percent,
+                                                    const char *a_delegated_ticker_str, uint256_t a_delegated_value,
+                                                    const char * a_chain_id_str, compose_config_t *a_config)
+{
+    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
+    // check valid param
+    if (!a_config->net_name || !a_key_from ||
+        !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value))
+        return NULL;
 
-// dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
-//                                                     const char *a_main_ticker,
-//                                                     uint256_t a_value, uint256_t a_value_fee,
-//                                                     dap_time_t a_time_staking, uint256_t a_reinvest_percent,
-//                                                     const char *a_delegated_ticker_str, uint256_t a_delegated_value,
-//                                                     const char * l_chain_id_str, const char *l_url_str, uint16_t l_port)
-// {
-//     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
-//     // check valid param
-//     if (!a_net_name || !a_key_from ||
-//         !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value))
-//         return NULL;
+    const char *l_native_ticker = s_get_native_ticker(a_config->net_name);
+    bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker);
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer = {}; // how many coins to transfer
+    uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
+    dap_chain_addr_t * l_addr_fee = NULL;
+    dap_chain_addr_t l_addr = {};
 
-//     const char *l_native_ticker = s_get_native_ticker(a_net_name);
-//     bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker);
-//     // find the transactions from which to take away coins
-//     uint256_t l_value_transfer = {}; // how many coins to transfer
-//     uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
-//     dap_chain_addr_t * l_addr_fee = NULL;
-//     dap_chain_addr_t l_addr = {};
+    dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_config->net_name));
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address( &l_net_fee, &l_addr_fee, a_config);
+    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
 
-//     dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name));
-//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port);
-//     SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
+    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, &l_addr, a_config);
+    if (!l_outs_native) {
+        return NULL;
+    }
 
-//     json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port);
-//     if (!l_outs_native) {
-//         return NULL;
-//     }
+    json_object *l_outs_main = NULL;
+    if (!dap_strcmp(a_main_ticker, l_native_ticker)) {
+        l_outs_main = l_outs_native;
+    } else {
+        l_outs_main = dap_get_remote_tx_outs(a_main_ticker, &l_addr, a_config);
+    }
+    int l_out_native_count = json_object_array_length(l_outs_native);
+    int l_out_main_count = json_object_array_length(l_outs_main);
 
-//     json_object *l_outs_main = NULL;
-//     if (!dap_strcmp(a_main_ticker, l_native_ticker)) {
-//         l_outs_main = l_outs_native;
-//     } else {
-//         l_outs_main = dap_get_remote_tx_outs(a_main_ticker, a_net_name, &l_addr, l_url_str, l_port);
-//     }
-//     int l_out_native_count = json_object_array_length(l_outs_native);
-//     int l_out_main_count = json_object_array_length(l_outs_main);
-
-//     dap_list_t *l_list_fee_out = NULL;
-//     if (l_main_native)
-//         SUM_256_256(l_value_need, l_total_fee, &l_value_need);
-//     else if (!IS_ZERO_256(l_total_fee)) {
-//         l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
-//                                                                l_total_fee, 
-//                                                                &l_fee_transfer);
-//         if (!l_list_fee_out) {
-//             printf("Not enough funds to pay fee");
-//             json_object_put(l_outs_native);
-//             json_object_put(l_outs_main);
-//             return NULL;
-//         }
-//     }
-//     // list of transaction with 'out' items
-//     dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_main, l_out_main_count,
-//                                                             l_value_need,
-//                                                             &l_value_transfer);
-//     if (!l_list_used_out) {
-//         printf("Not enough funds to transfer");
-//         json_object_put(l_outs_native);
-//         json_object_put(l_outs_main);
-//         return NULL;
-//     }
+    dap_list_t *l_list_fee_out = NULL;
+    if (l_main_native)
+        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+    else if (!IS_ZERO_256(l_total_fee)) {
+        l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+                                                               l_total_fee, 
+                                                               &l_fee_transfer);
+        if (!l_list_fee_out) {
+            dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_NOT_ENOUGH_FUNDS_TO_PAY_FEE, "Not enough funds to pay fee");
+            json_object_put(l_outs_native);
+            json_object_put(l_outs_main);
+            return NULL;
+        }
+    }
+    // list of transaction with 'out' items
+    dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_main, l_out_main_count,
+                                                            l_value_need,
+                                                            &l_value_transfer);
+    if (!l_list_used_out) {
+        dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_NOT_ENOUGH_FUNDS_TO_TRANSFER, "Not enough funds to transfer");
+        json_object_put(l_outs_native);
+        json_object_put(l_outs_main);
+        return NULL;
+    }
 
-//     // create empty transaction
-//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
-//     // add 'in' items
-//     {
-//         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-//         assert(EQUAL_256(l_value_to_items, l_value_transfer));
-//         dap_list_free_full(l_list_used_out, NULL);
-//         if (l_list_fee_out) {
-//             uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-//             assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
-//             dap_list_free_full(l_list_fee_out, NULL);
-//         }
-//     }
+    // add 'in' items
+    {
+        uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+        assert(EQUAL_256(l_value_to_items, l_value_transfer));
+        dap_list_free_full(l_list_used_out, NULL);
+        if (l_list_fee_out) {
+            uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+            assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+            dap_list_free_full(l_list_fee_out, NULL);
+        }
+    }
 
-//     // add 'in_ems' item
-//     {
-//         dap_chain_id_t l_chain_id = { };
-//         dap_chain_id_parse(l_chain_id_str, &l_chain_id);
-//         dap_hash_fast_t l_blank_hash = {};
-//         dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(l_chain_id, &l_blank_hash, a_delegated_ticker_str);
-//         dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems);
-//     }
+    // add 'in_ems' item
+    {
+        dap_chain_id_t l_chain_id = { };
+        dap_chain_id_parse(a_chain_id_str, &l_chain_id);
+        dap_hash_fast_t l_blank_hash = {};
+        dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(l_chain_id, &l_blank_hash, a_delegated_ticker_str);
+        dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems);
+    }
 
-//     // add 'out_cond' and 'out_ext' items
-//     {
-//         uint256_t l_value_pack = {}, l_native_pack = {}; // how much coin add to 'out_ext' items
-//         dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock(
-//                                                         l_uid, a_value, a_time_staking, a_reinvest_percent);
-//         if (l_tx_out_cond) {
-//             SUM_256_256(l_value_pack, a_value, &l_value_pack);
-//             dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond);
-//             DAP_DEL_Z(l_tx_out_cond);
-//         } else {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Error: Cant add conditional output\n");
-//             return NULL;
-//         }
+    // add 'out_cond' and 'out_ext' items
+    {
+        uint256_t l_value_pack = {}, l_native_pack = {}; // how much coin add to 'out_ext' items
+        dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock(
+                                                        l_uid, a_value, a_time_staking, a_reinvest_percent);
+        if (l_tx_out_cond) {
+            SUM_256_256(l_value_pack, a_value, &l_value_pack);
+            dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond);
+            DAP_DEL_Z(l_tx_out_cond);
+        } else {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_CONDITIONAL_OUTPUT, "Cant add conditional output\n");
+            return NULL;
+        }
 
-//         uint256_t l_value_back = {};
-//         // Network fee
-//         if (l_net_fee_used) {
-//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Error: Cant add network fee output\n");
-//                 return NULL;
-//             }
-//             if (l_main_native)
-//                 SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-//             else
-//                 SUM_256_256(l_native_pack, l_net_fee, &l_native_pack);
-//         }
-//         // Validator's fee
-//         if (!IS_ZERO_256(a_value_fee)) {
-//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Error: Cant add validator's fee output\n");
-//                 return NULL;
-//             }
-//             if (l_main_native)
-//                 SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
-//             else
-//                 SUM_256_256(l_native_pack, a_value_fee, &l_native_pack);
-//         }
-//         // coin back
-//         SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-//         if (!IS_ZERO_256(l_value_back)) {
-//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Error: Cant add coin back output for main ticker\n");
-//                 return NULL;
-//             }
-//         }
-//         // fee coin back
-//         if (!IS_ZERO_256(l_fee_transfer)) {
-//             SUBTRACT_256_256(l_fee_transfer, l_native_pack, &l_value_back);
-//             if (!IS_ZERO_256(l_value_back)) {
-//                 if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker) != 1) {
-//                     dap_chain_datum_tx_delete(l_tx);
-//                     printf("Error: Cant add coin back output for native ticker\n");
-//                     return NULL;
-//                 }
-//             }
-//         }
-//     }
+        uint256_t l_value_back = {};
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_NETWORK_FEE_OUTPUT, "Cant add network fee output\n");
+                return NULL;
+            }
+            if (l_main_native)
+                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            else
+                SUM_256_256(l_native_pack, l_net_fee, &l_native_pack);
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_VALIDATOR_FEE_OUTPUT, "Cant add validator's fee output\n");
+                return NULL;
+            }
+            if (l_main_native)
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            else
+                SUM_256_256(l_native_pack, a_value_fee, &l_native_pack);
+        }
+        // coin back
+        SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+        if (!IS_ZERO_256(l_value_back)) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_COIN_BACK_OUTPUT_FOR_MAIN_TICKER, "Cant add coin back output for main ticker\n");
+                return NULL;
+            }
+        }
+        // fee coin back
+        if (!IS_ZERO_256(l_fee_transfer)) {
+            SUBTRACT_256_256(l_fee_transfer, l_native_pack, &l_value_back);
+            if (!IS_ZERO_256(l_value_back)) {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_COIN_BACK_OUTPUT_FOR_NATIVE_TICKER, "Cant add coin back output for native ticker\n");
+                    return NULL;
+                }
+            }
+        }
+    }
 
-//     // add delegated token emission 'out_ext'
-//     if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_delegated_value, a_delegated_ticker_str) != 1) {
-//         dap_chain_datum_tx_delete(l_tx);
-//         printf("Error: Cant add delegated token emission output\n");
-//         return NULL;
-//     }
+    // add delegated token emission 'out_ext'
+    if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_delegated_value, a_delegated_ticker_str) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_DELEGATED_TOKEN_EMISSION_OUTPUT, "Cant add delegated token emission output\n");
+        return NULL;
+    }
 
-//     return l_tx;
-// }
+    return l_tx;
+}
 
 
 // int dap_cli_take_compose(int a_argc, char **a_argv)
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index fcca731a13..2328c76e0b 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -70,8 +70,25 @@ uint16_t dap_compose_get_net_port(const char* name);
 
 json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port);
 json_object* dap_tx_create_xchange_compose(const char *l_net_str, const char *l_token_sell, const char *l_token_buy, const char *l_wallet_str, const char *l_wallet_path, const char *l_value_str, const char *l_rate_str, const char *l_fee_str, const char *l_url_str, uint16_t l_port);
-int dap_tx_cond_create_compose(int argc, char ** argv);
-int dap_cli_hold_compose(int a_argc, char **a_argv);
+typedef enum dap_tx_cond_create_compose_error {
+    TX_COND_CREATE_COMPOSE_ERROR_INVALID_FEE = 1,
+    TX_COND_CREATE_COMPOSE_ERROR_INVALID_SERVICE_UID,
+    TX_COND_CREATE_COMPOSE_ERROR_INVALID_UNIT,
+    TX_COND_CREATE_COMPOSE_ERROR_INVALID_VALUE,
+    TX_COND_CREATE_COMPOSE_ERROR_WALLET_OPEN_FAILED,
+    TX_COND_CREATE_COMPOSE_ERROR_CERT_NOT_FOUND,
+    TX_COND_CREATE_COMPOSE_ERROR_INVALID_CERT_KEY,
+    TX_COND_CREATE_COMPOSE_ERROR_NATIVE_TOKEN_REQUIRED,
+    TX_COND_CREATE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS,
+    TX_COND_CREATE_COMPOSE_ERROR_COND_OUTPUT_FAILED,
+    TX_COND_CREATE_COMPOSE_ERROR_COIN_BACK_FAILED
+} dap_tx_cond_create_compose_error_t;
+json_object* dap_tx_cond_create_compose(const char *a_net_name, const char *a_token_ticker, const char *a_wallet_str, const char *a_wallet_path,
+                                        const char *a_cert_str, const char *a_value_datoshi_str, const char *a_value_fee_str, const char *a_unit_str, 
+                                        const char *a_srv_uid_str, const char *a_url_str, uint16_t a_port);
+
+json_object * dap_cli_hold_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_ticker_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_coins_str, const char *a_time_staking_str,
+                                    const char *a_cert_str, const char *a_value_fee_str, const char *a_reinvest_percent_str, const char *a_url_str, uint16_t a_port);
 int dap_cli_take_compose(int a_argc, char **a_argv);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
 typedef enum {
@@ -222,22 +239,21 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_tok
                                      uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, compose_config_t *a_config);
 dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet,
                                                                  const char *a_native_ticker, compose_config_t *a_config);
-dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name,
-        dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
+dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
         const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
         uint256_t a_value, uint256_t a_value_per_unit_max,
         dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid,
         uint256_t a_value_fee, const void *a_cond,
-        size_t a_cond_size, const char *a_url_str, uint16_t a_port);
+        size_t a_cond_size, compose_config_t *a_config);
 bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, compose_config_t *a_config);
 bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker,
                                          json_object **l_outs, int *l_outputs_count, compose_config_t *a_config);
-dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
+dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(dap_enc_key_t *a_key_from,
                                                     const char *a_main_ticker,
                                                     uint256_t a_value, uint256_t a_value_fee,
                                                     dap_time_t a_time_staking, uint256_t a_reinvest_percent,
                                                     const char *a_delegated_ticker_str, uint256_t a_delegated_value,
-                                                    const char * l_chain_id_str, const char *l_url_str, uint16_t l_port);
+                                                    const char * a_chain_id_str, compose_config_t *a_config);
 bool check_token_in_ledger(json_object *l_json_coins, const char *a_token);
 dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
                                                dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
-- 
GitLab


From 68b6bc2f77c6c7a565a77ec59749b65f835f72ef Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Mon, 14 Apr 2025 16:02:15 +0700
Subject: [PATCH 50/53] [*] cli take

---
 modules/compose/dap_chain_tx_compose.c        | 657 +++++++++---------
 .../compose/include/dap_chain_tx_compose.h    |   7 +-
 2 files changed, 329 insertions(+), 335 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index ad09be62ec..7c60204231 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -1836,368 +1836,361 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(dap_enc_key_t *a_key_
 }
 
 
-// int dap_cli_take_compose(int a_argc, char **a_argv)
-// {
-//     int arg_index = 1;
-//     const char *l_net_str, *l_ticker_str, *l_wallet_str, *l_tx_str, *l_tx_burning_str, *l_chain_id_str, *l_value_fee_str;
-//     l_net_str = l_ticker_str = l_wallet_str = l_tx_str = l_tx_burning_str = l_chain_id_str = l_value_fee_str = NULL;
-//     char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
-//     int									l_prev_cond_idx		=	0;
-//     uint256_t							l_value_delegated	= 	{};
-//     uint256_t                           l_value_fee     	=	{};
-//     dap_chain_wallet_t					*l_wallet;
-//     dap_hash_fast_t						l_tx_hash;
-//     dap_chain_tx_out_cond_t				*l_cond_tx = NULL;
-//     dap_enc_key_t						*l_owner_key;
-//     const char                          *l_url_str = NULL;
-//     uint16_t                            l_port = 0;
-
-
-//     const char *l_wallet_path = NULL;
-//     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
-//     if (!l_wallet_path) {
-//         l_wallet_path =
-//         #ifdef DAP_OS_WINDOWS
-//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-//         #elif defined DAP_OS_MAC
-//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-//         #elif defined DAP_OS_UNIX
-//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-//         #endif
-//     }  
-
-
-//     const char *l_hash_out_type = NULL;
-//     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type);
-//     if (!l_hash_out_type)
-//         l_hash_out_type = "hex";
-//     if (dap_strcmp(l_hash_out_type, "hex") && dap_strcmp(l_hash_out_type, "base58")) {
-//         printf("Error: Invalid hash type argument\n");
-//         return -1;
-//     }
-
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str) || NULL == l_net_str) {
-//         printf("Error: Missing or invalid network argument\n");
-//         return -2;
-//     }
-
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) {
-//         l_url_str = dap_compose_get_net_url(l_net_str);
-//     }
-
-//     const char *l_port_str = NULL;
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) {
-//         l_port = dap_compose_get_net_port(l_net_str);
-//     } else {
-//         l_port = atoi(l_port_str);
-//     }
-
-//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str);
-//     if (!l_chain_id_str) {
-//         printf("Error: Missing or invalid chain_id argument\n");
-//         return -10;
-//     }
-
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_str) || NULL == l_tx_str) {
-//         printf("Error: Missing or invalid transaction argument\n");
-//         return -5;
-//     }
+typedef enum {
+    CLI_TAKE_COMPOSE_OK = 0,
+    CLI_TAKE_COMPOSE_ERROR_UNABLE_TO_INIT_CONFIG = -1,
+    CLI_TAKE_COMPOSE_ERROR_INVALID_TRANSACTION_HASH = -2,
+    CLI_TAKE_COMPOSE_ERROR_FAILED_TO_GET_RESPONSE = -3,
+    CLI_TAKE_COMPOSE_ERROR_NO_ITEMS_FOUND = -4,
+    CLI_TAKE_COMPOSE_ERROR_NO_TX_OUT_CONDITION = -5,
+    CLI_TAKE_COMPOSE_ERROR_TX_OUT_ALREADY_USED = -6,
+    CLI_TAKE_COMPOSE_ERROR_FAILED_GET_ITEMS_ARRAY = -7,
+    CLI_TAKE_COMPOSE_ERROR_TOKEN_TICKER_NOT_FOUND = -8,
+    CLI_TAKE_COMPOSE_ERROR_INVALID_COINS_FORMAT = -9,
+    CLI_TAKE_COMPOSE_ERROR_INVALID_FEE_FORMAT = -10,
+    CLI_TAKE_COMPOSE_ERROR_UNABLE_TO_OPEN_WALLET = -11,
+    CLI_TAKE_COMPOSE_ERROR_OWNER_KEY_NOT_FOUND = -12,
+    CLI_TAKE_COMPOSE_ERROR_NOT_ENOUGH_TIME_PASSED = -13
+} cli_take_compose_error_t;
+
+json_object* dap_cli_take_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_tx_str, const char *a_tx_burning_str,
+                                    const char *a_value_fee_str, const char *a_url_str, uint16_t a_port){
+
+    compose_config_t * l_config = s_compose_config_init(a_net_name, a_url_str, a_port);
+    if (!l_config) {
+        json_object * l_json_obj_ret = json_object_new_object();
+        dap_json_compose_error_add(l_json_obj_ret, CLI_TAKE_COMPOSE_ERROR_UNABLE_TO_INIT_CONFIG, "Unable to init config\n");
+        return l_json_obj_ret;
+    }
 
-//     if (dap_chain_hash_fast_from_str(l_tx_str, &l_tx_hash)) {
-//         printf("Error: Invalid transaction hash\n");
-//         return -6;
-//     }
+    char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{};
+    int									l_prev_cond_idx		=	0;
+    uint256_t							l_value_delegated	= 	{};
+    uint256_t                           l_value_fee     	=	{};
+    dap_chain_wallet_t					*l_wallet;
+    dap_hash_fast_t						l_tx_hash;
+    dap_chain_tx_out_cond_t				*l_cond_tx = NULL;
+    dap_enc_key_t						*l_owner_key;
+    const char *l_ticker_str = NULL;
+    if (dap_chain_hash_fast_from_str(a_tx_str, &l_tx_hash)) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_INVALID_TRANSACTION_HASH, "Invalid transaction hash\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     char data[512];
-//     snprintf(data, sizeof(data), 
-//             "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
-//             l_tx_str, l_net_str);
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+            a_tx_str, a_net_name);
     
-//     json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
-//     if (!response) {
-//         printf("Error: Failed to get response from remote node\n");
-//         return -15;
-//     }
+    json_object *response = dap_request_command_to_rpc(data, l_config);
+    if (!response) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_FAILED_TO_GET_RESPONSE, "Failed to get response from remote node\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
     
-//     json_object *items = NULL;
-//     json_object *items_array = json_object_array_get_idx(response, 0);
-//     if (items_array) {
-//         items = json_object_object_get(items_array, "ITEMS");
-//     }
-//     if (!items) {
-//         printf("Error: No items found in response\n");
-//         return -16;
-//     }
-//     int items_count = json_object_array_length(items);
-//     for (int i = 0; i < items_count; i++) {
-//         json_object *item = json_object_array_get_idx(items, i);
-//         const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
-//         if (dap_strcmp(item_type, "OUT COND") == 0) {
-//             const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
-//             if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK")) {
-//                 l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
-//                 l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
-//                 l_cond_tx->header.value =  dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
-//                 l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK;
-//                 l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
-//                 l_cond_tx->subtype.srv_stake_lock.time_unlock =  dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "time_unlock")));
-//                 break;
-//             }
-//         }
-//     }
-//     if (!l_cond_tx) {
-//         printf("Error: No transaction output condition found\n");
-//         return -7;
-//     }
+    json_object *items = NULL;
+    json_object *items_array = json_object_array_get_idx(response, 0);
+    if (items_array) {
+        items = json_object_object_get(items_array, "ITEMS");
+    }
+    if (!items) {
+        json_object_put(response);
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_NO_ITEMS_FOUND, "No items found in response\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    int items_count = json_object_array_length(items);
+    for (int i = 0; i < items_count; i++) {
+        json_object *item = json_object_array_get_idx(items, i);
+        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+        if (dap_strcmp(item_type, "OUT COND") == 0) {
+            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+            if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK")) {
+                l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+                l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+                l_cond_tx->header.value =  dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+                l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK;
+                l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+                l_cond_tx->subtype.srv_stake_lock.time_unlock =  dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "time_unlock")));
+                break;
+            }
+        }
+    }
+    if (!l_cond_tx) {
+        json_object_put(response);
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_NO_TX_OUT_CONDITION, "No transaction output condition found\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
 
-//     json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
-//     const char *spent_outs_value = json_object_get_string(spent_outs);
-//     if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
-//         printf("Error: Transaction output item already used\n");
-//         return -9;
-//     }
+    json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent");
+    const char *spent_outs_value = json_object_get_string(spent_outs);
+    if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) {
+        json_object_put(response);
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_TX_OUT_ALREADY_USED, "Transaction output item already used\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     json_object *response_header_array = json_object_array_get_idx(response, 0);
-//     if (!response_header_array) {
-//         printf("Error: Failed to get items array from response\n");
-//         return -10;
-//     }
+    json_object *response_header_array = json_object_array_get_idx(response, 0);
+    if (!response_header_array) {
+        json_object_put(response);
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_FAILED_GET_ITEMS_ARRAY, "Failed to get items array from response\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     json_object *token_ticker_obj = json_object_object_get(response_header_array, "token ticker");
-//     if (!token_ticker_obj) {
-//         printf("Error: Token ticker not found in response\n");
-//         return -11;
-//     }
-//     l_ticker_str = json_object_get_string(token_ticker_obj);
+    json_object *token_ticker_obj = json_object_object_get(response_header_array, "token ticker");
+    if (!token_ticker_obj) {
+        json_object_put(response);
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_TOKEN_TICKER_NOT_FOUND, "Token ticker not found in response\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    l_ticker_str = json_object_get_string(token_ticker_obj);
 
 
 
-//     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str);
+    dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str);
 
-//     uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001");
+    uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001");
 
-//     if (IS_ZERO_256(l_emission_rate) ||
-//         MULT_256_COIN(l_cond_tx->header.value, l_emission_rate, &l_value_delegated) ||
-//         IS_ZERO_256(l_value_delegated)) {
-//         printf("Error: Invalid coins format\n");
-//         return -12;
-//     }
+    if (IS_ZERO_256(l_emission_rate) ||
+        MULT_256_COIN(l_cond_tx->header.value, l_emission_rate, &l_value_delegated) ||
+        IS_ZERO_256(l_value_delegated)) {
+        json_object_put(response);
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_INVALID_COINS_FORMAT, "Invalid coins format\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
+    if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(a_value_fee_str)))) {
+        json_object_put(response);
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_INVALID_FEE_FORMAT, "Invalid fee format\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    json_object_put(response);
 
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) {
-//         printf("Error: Missing or invalid wallet argument\n");
-//         return -13;
-//     }
+    if (NULL == (l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path, NULL))) {
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_UNABLE_TO_OPEN_WALLET, "Unable to open wallet\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) {
-//         printf("Error: Missing or invalid fee argument\n");
-//         return -14;
-//     }
+    if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) {
+        dap_chain_wallet_close(l_wallet);
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_OWNER_KEY_NOT_FOUND, "Owner key not found\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) {
-//         printf("Error: Invalid fee format\n");
-//         return -15;
-//     }
+    if (l_cond_tx->subtype.srv_stake_lock.time_unlock > dap_time_now()) {
+        dap_chain_wallet_close(l_wallet);
+        dap_enc_key_delete(l_owner_key);
+        dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_NOT_ENOUGH_TIME_PASSED, "Not enough time has passed for unlocking\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_owner_key, &l_tx_hash, l_prev_cond_idx,
+                                          l_ticker_str, l_cond_tx->header.value, l_value_fee,
+                                          l_delegated_ticker_str, l_value_delegated, l_config);
 
-//     if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) {
-//         printf("Error: Unable to open wallet\n");
-//         return -16;
-//     }
+    json_object * l_json_obj_ret = json_object_new_object();
+    dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
+    printf("%s", json_object_to_json_string(l_json_obj_ret));
+    json_object_put(l_json_obj_ret);
 
-//     if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) {
-//         dap_chain_wallet_close(l_wallet);
-//         printf("Error: Owner key not found\n");
-//         return -17;
-//     }
 
-//     if (l_cond_tx->subtype.srv_stake_lock.time_unlock > dap_time_now()) {
-//         dap_chain_wallet_close(l_wallet);
-//         dap_enc_key_delete(l_owner_key);
-//         printf("Error: Not enough time has passed for unlocking\n");
-//         return -19;
-//     }
-//     dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_net_str, l_owner_key, &l_tx_hash, l_prev_cond_idx,
-//                                           l_ticker_str, l_cond_tx->header.value, l_value_fee,
-//                                           l_delegated_ticker_str, l_value_delegated, l_url_str, l_port);
+    dap_chain_datum_tx_delete(l_tx);
+    dap_enc_key_delete(l_owner_key);
 
-//     json_object * l_json_obj_ret = json_object_new_object();
-//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-//     printf("%s", json_object_to_json_string(l_json_obj_ret));
-//     json_object_put(l_json_obj_ret);
+    return 0;
+}
 
 
-//     dap_chain_datum_tx_delete(l_tx);
-//     dap_enc_key_delete(l_owner_key);
+typedef enum {
+    TX_STAKE_UNLOCK_COMPOSE_OK = 0,
+    TX_STAKE_UNLOCK_COMPOSE_INVALID_PARAMS = -1,
+    TX_STAKE_UNLOCK_COMPOSE_NOT_ENOUGH_FUNDS = -2,
+    TX_STAKE_UNLOCK_COMPOSE_TOTAL_FEE_MORE_THAN_STAKE = -3,
+    TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_NETWORK_FEE_OUTPUT = -4,
+    TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_VALIDATOR_FEE_OUTPUT = -5,
+    TX_STAKE_UNLOCK_COMPOSE_CANT_SUBTRACT_VALUE_PACK = -6,
+    TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_MAIN = -7,
+    TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_NATIVE = -8,
+    TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_BURNING_OUTPUT = -9,
+    TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_DELEGATED = -10
+} tx_stake_unlock_compose_error_t;
+
+dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(dap_enc_key_t *a_key_from,
+                                               dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
+                                               const char *a_main_ticker, uint256_t a_value,
+                                               uint256_t a_value_fee,
+                                               const char *a_delegated_ticker_str, uint256_t a_delegated_value,
+                                               compose_config_t *a_config)
+{
+    // check valid param
+    if (!a_config || !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) {
+        dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_INVALID_PARAMS, "Invalid parameters\n");
+        return NULL;
+    }
 
-//     return 0;
-// }
+    const char *l_native_ticker = s_get_native_ticker(a_config->net_name);
+    bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker);
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer = {}; // how many coins to transfer
+    uint256_t l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
+    dap_chain_addr_t* l_addr_fee = NULL;
+    dap_chain_addr_t l_addr = {};
 
-// dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
-//                                                dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
-//                                                const char *a_main_ticker, uint256_t a_value,
-//                                                uint256_t a_value_fee,
-//                                                const char *a_delegated_ticker_str, uint256_t a_delegated_value,
-//                                                const char *l_url_str, uint16_t l_port)
-// {
-//     // check valid param
-//     if (!a_net_name | !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) {
-//         printf("Error: Invalid parameters\n");
-//         return NULL;
-//     }
+    dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_config->net_name));
+    dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL;
 
-//     const char *l_native_ticker = s_get_native_ticker(a_net_name);
-//     bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker);
-//     // find the transactions from which to take away coins
-//     uint256_t l_value_transfer = {}; // how many coins to transfer
-//     uint256_t l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
-//     dap_chain_addr_t* l_addr_fee = NULL;
-//     dap_chain_addr_t l_addr = {};
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, a_config);
 
-//     dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name));
-//     dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL;
+    json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, &l_addr, a_config);
+    if (!l_outs_native) {
+        return NULL;
+    }
 
-//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port);
+    json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, &l_addr, a_config);
+    if (!l_outs_delegated) {
+        return NULL;
+    }
 
-//     json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port);
-//     if (!l_outs_native) {
-//         return NULL;
-//     }
+    int l_out_native_count = json_object_array_length(l_outs_native);
+    int l_out_delegated_count = json_object_array_length(l_outs_delegated);
 
-//     json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, a_net_name, &l_addr, l_url_str, l_port);
-//     if (!l_outs_delegated) {
-//         return NULL;
-//     }
+    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
+    if (!IS_ZERO_256(l_total_fee)) {
+        if (!l_main_native) {
+            l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
+                                                                l_total_fee, 
+                                                                &l_fee_transfer);
+            if (!l_list_fee_out) {
+                dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_NOT_ENOUGH_FUNDS, "Not enough funds to pay fee");
+                json_object_put(l_outs_native);
+                json_object_put(l_outs_delegated);
+                return NULL;
+            }
+        } else if (compare256(a_value, l_total_fee) == -1) {
+            dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_TOTAL_FEE_MORE_THAN_STAKE, "Total fee more than stake\n");
+            json_object_put(l_outs_native);
+            json_object_put(l_outs_delegated);
+            return NULL;
+        }
+    }
+    if (!IS_ZERO_256(a_delegated_value)) {
+        l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count,
+                                                               a_delegated_value, 
+                                                               &l_value_transfer);
+        if (!l_list_used_out) {
+            dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_NOT_ENOUGH_FUNDS, "Not enough funds to pay fee");
+            json_object_put(l_outs_native);
+            json_object_put(l_outs_delegated);
+            return NULL;
+        }
+    }
 
-//     int l_out_native_count = json_object_array_length(l_outs_native);
-//     int l_out_delegated_count = json_object_array_length(l_outs_delegated);
-
-//     SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
-//     if (!IS_ZERO_256(l_total_fee)) {
-//         if (!l_main_native) {
-//             l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count,
-//                                                                 l_total_fee, 
-//                                                                 &l_fee_transfer);
-//             if (!l_list_fee_out) {
-//                 printf("Not enough funds to pay fee");
-//                 json_object_put(l_outs_native);
-//                 json_object_put(l_outs_delegated);
-//                 return NULL;
-//             }
-//         } else if (compare256(a_value, l_total_fee) == -1) {
-//             printf("Error: Total fee more than stake\n");
-//             return NULL;
-//         }
-//     }
-//     if (!IS_ZERO_256(a_delegated_value)) {
-//         l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count,
-//                                                                a_delegated_value, 
-//                                                                &l_value_transfer);
-//         if (!l_list_used_out) {
-//             printf("Not enough funds to pay fee");
-//             json_object_put(l_outs_native);
-//             json_object_put(l_outs_delegated);
-//             return NULL;
-//         }
-//     }
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
-//     // create empty transaction
-//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    // add 'in_cond' & 'in' items
+    {
+        dap_chain_datum_tx_add_in_cond_item(&l_tx, a_stake_tx_hash, a_prev_cond_idx, 0);
+        if (l_list_used_out) {
+            uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+            assert(EQUAL_256(l_value_to_items, l_value_transfer));
+            dap_list_free_full(l_list_used_out, NULL);
+        }
+        if (l_list_fee_out) {
+            uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+            assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+            dap_list_free_full(l_list_fee_out, NULL);
+        }
+    }
 
-//     // add 'in_cond' & 'in' items
-//     {
-//         dap_chain_datum_tx_add_in_cond_item(&l_tx, a_stake_tx_hash, a_prev_cond_idx, 0);
-//         if (l_list_used_out) {
-//             uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-//             assert(EQUAL_256(l_value_to_items, l_value_transfer));
-//             dap_list_free_full(l_list_used_out, NULL);
-//         }
-//         if (l_list_fee_out) {
-//             uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
-//             assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
-//             dap_list_free_full(l_list_fee_out, NULL);
-//         }
-//     }
+    // add 'out_ext' items
+    uint256_t l_value_back;
+    {
+        uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
+        // Network fee
+        if(l_net_fee_used){
+            if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker)){
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_NETWORK_FEE_OUTPUT, "Can't add network fee output\n");
+                return NULL;
+            }
+            SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+            {
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            }
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_VALIDATOR_FEE_OUTPUT, "Can't add validator's fee output\n");
+                return NULL;
+            }
+        }
+        // coin back
+        //SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back);
+        if(l_main_native){
+            if (SUBTRACT_256_256(a_value, l_value_pack, &l_value_back)) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_SUBTRACT_VALUE_PACK, "Can't subtract value pack from value\n");
+                return NULL;
+            }
+            if(!IS_ZERO_256(l_value_back)) {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker)!=1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_MAIN, "Can't add coin back output for main ticker\n");
+                    return NULL;
+                }
+            }
+        } else {
+            SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back);
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_value, a_main_ticker)!=1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_MAIN, "Can't add coin back output for main ticker\n");
+                return NULL;
+            }
+            else
+            {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker)!=1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_NATIVE, "Can't add coin back output for native ticker\n");
+                    return NULL;
+                }
+            }
+        }
+    }
 
-//     // add 'out_ext' items
-//     uint256_t l_value_back;
-//     {
-//         uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
-//         // Network fee
-//         if(l_net_fee_used){
-//             if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker)){
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Error: Can't add network fee output\n");
-//                 return NULL;
-//             }
-//             SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-//         }
-//         // Validator's fee
-//         if (!IS_ZERO_256(a_value_fee)) {
-//             if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
-//             {
-//                 SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
-//             }
-//             else {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Error: Can't add validator's fee output\n");
-//                 return NULL;
-//             }
-//         }
-//         // coin back
-//         //SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back);
-//         if(l_main_native){
-//             if (SUBTRACT_256_256(a_value, l_value_pack, &l_value_back)) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Error: Can't subtract value pack from value\n");
-//                 return NULL;
-//             }
-//             if(!IS_ZERO_256(l_value_back)) {
-//                 if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker)!=1) {
-//                     dap_chain_datum_tx_delete(l_tx);
-//                     printf("Error: Can't add coin back output for main ticker\n");
-//                     return NULL;
-//                 }
-//             }
-//         } else {
-//             SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back);
-//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_value, a_main_ticker)!=1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Error: Can't add coin back output for main ticker\n");
-//                 return NULL;
-//             }
-//             else
-//             {
-//                 if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker)!=1) {
-//                     dap_chain_datum_tx_delete(l_tx);
-//                     printf("Error: Can't add coin back output for native ticker\n");
-//                     return NULL;
-//                 }
-//             }
-//         }
-//     }
+    // add burning 'out_ext'
+    if (!IS_ZERO_256(a_delegated_value)) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &c_dap_chain_addr_blank,
+                                               a_delegated_value, a_delegated_ticker_str) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_BURNING_OUTPUT, "Can't add burning output for delegated value\n");
+            return NULL;
+        }
+        // delegated token coin back
+        SUBTRACT_256_256(l_value_transfer, a_delegated_value, &l_value_back);
+        if (!IS_ZERO_256(l_value_back)) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_delegated_ticker_str) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_DELEGATED, "Can't add coin back output for delegated ticker\n");
+                return NULL;
+            }
+        }
+    }
 
-//     // add burning 'out_ext'
-//     if (!IS_ZERO_256(a_delegated_value)) {
-//         if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &c_dap_chain_addr_blank,
-//                                                a_delegated_value, a_delegated_ticker_str) != 1) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             printf("Error: Can't add burning output for delegated value\n");
-//             return NULL;
-//         }
-//         // delegated token coin back
-//         SUBTRACT_256_256(l_value_transfer, a_delegated_value, &l_value_back);
-//         if (!IS_ZERO_256(l_value_back)) {
-//             if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_delegated_ticker_str) != 1) {
-//                 dap_chain_datum_tx_delete(l_tx);
-//                 printf("Error: Can't add coin back output for delegated ticker\n");
-//                 return NULL;
-//             }
-//         }
-//     }
+    return l_tx;
+}
 
-//     return l_tx;
-// }
+typedef enum {
+    GET_KEY_DELEGATING_MIN_VALUE_OK = 0,
+    GET_KEY_DELEGATING_MIN_VALUE_FAILED_TO_GET_RESPONSE = -1,
+    GET_KEY_DELEGATING_MIN_VALUE_INVALID_RESPONSE_FORMAT = -2,
+    GET_KEY_DELEGATING_MIN_VALUE_SUMMARY_NOT_FOUND = -3,
+    GET_KEY_DELEGATING_MIN_VALUE_MIN_VALUE_NOT_FOUND = -4,
+    GET_KEY_DELEGATING_MIN_VALUE_INVALID_VALUE_FORMAT = -5,
+    GET_KEY_DELEGATING_MIN_VALUE_UNRECOGNIZED_NUMBER = -6
+} get_key_delegating_min_value_error_t;
 
 uint256_t s_get_key_delegating_min_value(compose_config_t *a_config){
     uint256_t l_key_delegating_min_value = uint256_0;
@@ -2208,37 +2201,37 @@ uint256_t s_get_key_delegating_min_value(compose_config_t *a_config){
     
     json_object *response = dap_request_command_to_rpc(data, a_config);
     if (!response) {
-        printf("Error: Failed to get response from remote node\n");
+        dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_FAILED_TO_GET_RESPONSE, "Failed to get response from remote node\n");
         return l_key_delegating_min_value;
     }
 
     json_object *response_array = json_object_array_get_idx(response, 0);
     if (!response_array) {
-        printf("Error: Invalid response format\n");
+        dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_INVALID_RESPONSE_FORMAT, "Invalid response format\n");
         return l_key_delegating_min_value;
     }
 
     json_object *summary_obj = json_object_array_get_idx(response_array, json_object_array_length(response_array) - 1);
     if (!summary_obj) {
-        printf("Error: Summary object not found in response\n");
+        dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_SUMMARY_NOT_FOUND, "Summary object not found in response\n");
         return l_key_delegating_min_value;
     }
 
     json_object *key_delegating_min_value_obj = json_object_object_get(summary_obj, "key_delegating_min_value");
     if (!key_delegating_min_value_obj) {
-        printf("Error: key_delegating_min_value not found in summary\n");
+        dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_MIN_VALUE_NOT_FOUND, "Key delegating min value not found in summary\n");
         return l_key_delegating_min_value;
     }
 
     const char *key_delegating_min_value_str = json_object_get_string(key_delegating_min_value_obj);
     if (!key_delegating_min_value_str) {
-        printf("Error: Invalid key_delegating_min_value format\n");
+        dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_INVALID_VALUE_FORMAT, "Invalid key_delegating_min_value format\n");
         return l_key_delegating_min_value;
     }
 
     l_key_delegating_min_value = dap_chain_balance_scan(key_delegating_min_value_str);
     if (IS_ZERO_256(l_key_delegating_min_value)) {
-        printf("Error: Unrecognized number in key_delegating_min_value\n");
+        dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_UNRECOGNIZED_NUMBER, "Unrecognized number in key_delegating_min_value\n");
         return l_key_delegating_min_value;
     }
 
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 2328c76e0b..7d42deaa98 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -89,7 +89,8 @@ json_object* dap_tx_cond_create_compose(const char *a_net_name, const char *a_to
 
 json_object * dap_cli_hold_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_ticker_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_coins_str, const char *a_time_staking_str,
                                     const char *a_cert_str, const char *a_value_fee_str, const char *a_reinvest_percent_str, const char *a_url_str, uint16_t a_port);
-int dap_cli_take_compose(int a_argc, char **a_argv);
+json_object* dap_cli_take_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_tx_str, const char *a_tx_burning_str,
+                                    const char *a_value_fee_str, const char *a_url_str, uint16_t a_port);
 int dap_cli_voting_compose(int a_argc, char **a_argv);
 typedef enum {
     STAKE_ORDER_CREATE_STAKER_OK = 0,
@@ -255,12 +256,12 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(dap_enc_key_t *a_key_
                                                     const char *a_delegated_ticker_str, uint256_t a_delegated_value,
                                                     const char * a_chain_id_str, compose_config_t *a_config);
 bool check_token_in_ledger(json_object *l_json_coins, const char *a_token);
-dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from,
+dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(dap_enc_key_t *a_key_from,
                                                dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx,
                                                const char *a_main_ticker, uint256_t a_value,
                                                uint256_t a_value_fee,
                                                const char *a_delegated_ticker_str, uint256_t a_delegated_value,
-                                               const char *l_url_str, uint16_t l_port);
+                                               compose_config_t *a_config);
 dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
-- 
GitLab


From 5d2bdc4318108b7d4fe74c842c54126e1c15bf4f Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Mon, 14 Apr 2025 16:50:16 +0700
Subject: [PATCH 51/53] [*] voting

---
 modules/compose/dap_chain_tx_compose.c        | 680 ++++++++++--------
 .../compose/include/dap_chain_tx_compose.h    | 149 +---
 2 files changed, 405 insertions(+), 424 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 7c60204231..01a0815284 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -309,7 +309,14 @@ static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_ob
     return ret;
 }
 
-
+typedef enum {
+    DAP_COMPOSE_ERROR_NONE = 0,
+    DAP_COMPOSE_ERROR_RESPONSE_NULL = -1,
+    DAP_COMPOSE_ERROR_RESULT_NOT_FOUND = -2,
+    DAP_COMPOSE_ERROR_REQUEST_INIT_FAILED = -3,
+    DAP_COMPOSE_ERROR_REQUEST_TIMEOUT = -4,
+    DAP_COMPOSE_ERROR_REQUEST_FAILED = -5
+} dap_compose_error_t;
 static json_object* s_request_command_to_rpc(const char *request, compose_config_t *a_config) {
     json_object * l_response = NULL;
     size_t l_response_size = 0;
@@ -373,6 +380,7 @@ static json_object* s_request_command_parse(json_object *l_response, compose_con
     return l_result;
 }
 
+
 json_object* dap_request_command_to_rpc(const char *request, compose_config_t *a_config) {
     json_object * l_response = s_request_command_to_rpc(request, a_config);
     if (!l_response) {
@@ -496,7 +504,8 @@ typedef enum {
     TX_CREATE_COMPOSE_INVALID_PARAMS = -5,
     TX_CREATE_COMPOSE_FEE_ERROR = -6,
     TX_CREATE_COMPOSE_FUNDS_ERROR = -7,
-    TX_CREATE_COMPOSE_OUT_ERROR = -8
+    TX_CREATE_COMPOSE_OUT_ERROR = -8,
+    TX_CREATE_COMPOSE_INVALID_CONFIG = -9
 } tx_create_compose_error_t;
 
 json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) {
@@ -504,7 +513,7 @@ json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ti
     compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port);
     if (!l_config) {
         json_object* l_json_obj_ret = json_object_new_object();
-        dap_json_compose_error_add(l_json_obj_ret, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, "Can't create compose config");
+        dap_json_compose_error_add(l_json_obj_ret, TX_CREATE_COMPOSE_INVALID_CONFIG, "Can't create compose config");
         return l_json_obj_ret;
     }
 
@@ -1316,6 +1325,19 @@ dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xc
 }
 
 
+typedef enum dap_tx_cond_create_compose_error {
+    TX_COND_CREATE_COMPOSE_ERROR_INVALID_FEE = 1,
+    TX_COND_CREATE_COMPOSE_ERROR_INVALID_SERVICE_UID,
+    TX_COND_CREATE_COMPOSE_ERROR_INVALID_UNIT,
+    TX_COND_CREATE_COMPOSE_ERROR_INVALID_VALUE,
+    TX_COND_CREATE_COMPOSE_ERROR_WALLET_OPEN_FAILED,
+    TX_COND_CREATE_COMPOSE_ERROR_CERT_NOT_FOUND,
+    TX_COND_CREATE_COMPOSE_ERROR_INVALID_CERT_KEY,
+    TX_COND_CREATE_COMPOSE_ERROR_NATIVE_TOKEN_REQUIRED,
+    TX_COND_CREATE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS,
+    TX_COND_CREATE_COMPOSE_ERROR_COND_OUTPUT_FAILED,
+    TX_COND_CREATE_COMPOSE_ERROR_COIN_BACK_FAILED
+} dap_tx_cond_create_compose_error_t;
 json_object* dap_tx_cond_create_compose(const char *a_net_name, const char *a_token_ticker, const char *a_wallet_str, const char *a_wallet_path,
                                         const char *a_cert_str, const char *a_value_datoshi_str, const char *a_value_fee_str, const char *a_unit_str, 
                                         const char *a_srv_uid_str, const char *a_url_str, uint16_t a_port) {    
@@ -2239,320 +2261,292 @@ uint256_t s_get_key_delegating_min_value(compose_config_t *a_config){
 }
 
 
-// int dap_cli_voting_compose(int a_argc, char **a_argv)
-// {
-//     int arg_index = 1;
-//     const char* l_question_str = NULL;
-//     const char* l_options_list_str = NULL;
-//     const char* l_voting_expire_str = NULL;
-//     const char* l_max_votes_count_str = NULL;
-//     const char* l_fee_str = NULL;
-//     const char* l_wallet_str = NULL;
-//     const char* l_net_str = NULL;
-//     const char* l_token_str = NULL;
-//     const char* l_url_str = NULL;
-//     uint16_t l_port = 0;
-//     const char *l_wallet_path = NULL;
-//     dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path);
-//     if (!l_wallet_path) {
-//         l_wallet_path =
-//         #ifdef DAP_OS_WINDOWS
-//                     dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath());
-//         #elif defined DAP_OS_MAC
-//                     dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets");
-//         #elif defined DAP_OS_UNIX
-//                     dap_strdup_printf("/opt/CellframeNode/var/lib/wallets");
-//         #endif
-//     }  
-    
-//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
-//     // Select chain network
-//     if(!l_net_str) {
-//         printf("Voting requires parameter '-net' to be valid.\n");
-//         return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING;
-//     }
-
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-url", &l_url_str)) {
-//         l_url_str = dap_compose_get_net_url(l_net_str);
-//     }
-
-//     const char *l_port_str = NULL;
-//     if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str)) {
-//         l_port = dap_compose_get_net_port(l_net_str);
-//     } else {
-//         l_port = atoi(l_port_str);
-//     }
 
-//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str);
-//     if (!l_question_str){
-//         printf("Voting requires a question parameter to be valid.\n");
-//         return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_PARAM_MISSING;
-//     }
-
-//     if (strlen(l_question_str) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
-//         printf("The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH);
-//         return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_CONTAIN_MAX_CHARACTERS;
-//     }
+json_object* dap_cli_voting_compose(const char *a_net_name, const char *a_question_str, const char *a_options_list_str, 
+                                    const char *a_voting_expire_str, const char *a_max_votes_count_str, const char *a_fee_str, 
+                                    bool a_is_delegated_key, bool a_is_vote_changing_allowed, const char *a_wallet_str, const char *a_wallet_path, 
+                                    const char *a_token_str, const char *a_url_str, uint16_t a_port) {
+    
+    compose_config_t * l_config = s_compose_config_init(a_net_name, a_url_str, a_port);
+    if (!l_config) {
+        json_object * l_json_obj_ret = json_object_new_object();
+        dap_json_compose_error_add(l_json_obj_ret, CLI_TAKE_COMPOSE_ERROR_UNABLE_TO_INIT_CONFIG, "Unable to init config\n");
+        return l_json_obj_ret;
+    }
+    
+    if (strlen(a_question_str) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
+        dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH, "The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     dap_list_t *l_options_list = NULL;
-//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-options", &l_options_list_str);
-//     if (!l_options_list_str){
-//         printf("Voting requires a question parameter to be valid.\n");
-//         return -DAP_CHAIN_NET_VOTE_CREATE_OPTION_PARAM_MISSING;
-//     }
-//     // Parse options list
-//     l_options_list = dap_get_options_list_from_str(l_options_list_str);
-//     if(!l_options_list || dap_list_length(l_options_list) < 2){
-//         printf("Number of options must be 2 or greater.\n");
-//         return -DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR;
-//     }
+    dap_list_t *l_options_list = NULL;
+    // Parse options list
+    l_options_list = dap_get_options_list_from_str(a_options_list_str);
+    if(!l_options_list || dap_list_length(l_options_list) < 2){
+        dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR, "Number of options must be 2 or greater.\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     if(dap_list_length(l_options_list)>DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){
-//         printf("The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT);            
-//         return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS;
-//     }
+    if(dap_list_length(l_options_list)>DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){
+        dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS, "The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT);            
+        return s_compose_config_return_response_handler(l_config);
+    }
+    uint256_t l_value_fee = dap_chain_balance_scan(a_fee_str);
 
-//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str);
-//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str);
-//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str);
-//     if (!l_fee_str){
-//         printf("Voting requires parameter -fee to be valid.\n");
-//         return -DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID;
-//     }
-//     uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str);
 
-//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str);
-//     if (!l_wallet_str){
-//         printf("Voting requires parameter -w to be valid.\n");
-//         return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID;
-//     }
+    dap_time_t l_time_expire = 0;
+    if (a_voting_expire_str)
+        l_time_expire = dap_time_from_str_rfc822(a_voting_expire_str);
+    if (a_voting_expire_str && !l_time_expire){
+        dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT, "Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    uint64_t l_max_count = 0;
+    if (a_max_votes_count_str)
+        l_max_count = strtoul(a_max_votes_count_str, NULL, 10);
 
-//     dap_time_t l_time_expire = 0;
-//     if (l_voting_expire_str)
-//         l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str);
-//     if (l_voting_expire_str && !l_time_expire){
-//         printf("Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"\n");
-//         return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT;
-//     }
-//     uint64_t l_max_count = 0;
-//     if (l_max_votes_count_str)
-//         l_max_count = strtoul(l_max_votes_count_str, NULL, 10);
-
-//     bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false;
-//     bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false;
-//     dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL);
-//     if (!l_wallet_fee) {
-//         printf("Wallet %s does not exist\n", l_wallet_str);
-//         return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
-//     }
+    dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(a_wallet_str, a_wallet_path, NULL);
+    if (!l_wallet_fee) {
+        dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST, "Wallet %s does not exist\n", a_wallet_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-//     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str);
-//     if (!l_token_str) {
-//         printf("Command required -token argument");
-//         return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST;
-//     }
         
-//     char data[512];
-//     snprintf(data, sizeof(data), 
-//             "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str);
-//     json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port);
-//     if (!l_json_coins) {
-//         printf("Error: Can't get ledger coins list\n");
-//         return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
-//     }
-//     if (!check_token_in_ledger(l_json_coins, l_token_str)) {
-//         json_object_put(l_json_coins);
-//         printf("Token %s does not exist\n", l_token_str);
-//         return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN;
-//     }
-//     json_object_put(l_json_coins);
-
-//     dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count,
-//                                                                 l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, 
-//                                                                 l_wallet_fee, l_net_str, l_token_str, l_url_str, l_port);
-//     dap_list_free(l_options_list);
-//     dap_chain_wallet_close(l_wallet_fee);
-//     json_object * l_json_obj_ret = json_object_new_object();
-//     dap_chain_net_tx_to_json(l_tx, l_json_obj_ret);
-//     printf("%s", json_object_to_json_string(l_json_obj_ret));
-//     json_object_put(l_json_obj_ret);
-//     return 0;
-// }
-
-
-// dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
-//                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
-//                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
-//                               const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port) {
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name);
+    json_object *l_json_coins = dap_request_command_to_rpc(data, l_config);
+    if (!l_json_coins) {
+        dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS, "Can't get ledger coins list\n");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    if (!check_token_in_ledger(l_json_coins, a_token_str)) {
+        json_object_put(l_json_coins);
+        dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN, "Token %s does not exist\n", a_token_str);
+        return s_compose_config_return_response_handler(l_config);
+    }
+    json_object_put(l_json_coins);
 
-//     if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
-//         return NULL;
-//     }
+    dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(a_question_str, l_options_list, l_time_expire, l_max_count,
+                                                                l_value_fee, a_is_delegated_key, a_is_vote_changing_allowed, 
+                                                                l_wallet_fee, a_token_str, l_config);
+    dap_list_free(l_options_list);
+    dap_chain_wallet_close(l_wallet_fee);
+    if (l_tx) {
+        dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
+        dap_chain_datum_tx_delete(l_tx);
+    }
+    return s_compose_config_return_response_handler(l_config);
+}
 
-//     // Parse options list
+typedef enum {
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_OK = 0,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_INVALID_CONFIG,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_QUESTION_TOO_LONG,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_TOO_MANY_OPTIONS,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_ZERO_FEE,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_WALLET_NOT_FOUND,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_OPTION_TOO_LONG,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_OPTION_CREATE_FAILED,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_INVALID_EXPIRE_TIME,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_EXPIRE_CREATE_FAILED,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_MAX_VOTES_CREATE_FAILED,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_DELEGATED_KEY_CREATE_FAILED,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_VOTE_CHANGING_CREATE_FAILED,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_TOKEN_CREATE_FAILED,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_FEE_OUTPUT_FAILED,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_COINBACK_FAILED,
+    DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_NOT_ENOUGH_FUNDS
+} dap_chain_net_vote_create_compose_error_t;
+
+dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
+                              uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
+                              bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
+                              const char *a_token_ticker, compose_config_t *a_config) {
+    if (!a_config) {
+        return NULL;
+    }
 
-//     if(dap_list_length(a_options) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){
-//         return NULL;
-//     }
+    if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_QUESTION_TOO_LONG, "The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH);
+        return NULL;
+    }
 
-//     if (IS_ZERO_256(a_fee)) {
-//         return NULL;
-//     }
+    // Parse options list
 
-//     dap_chain_addr_t *l_addr_from =  dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str));
+    if(dap_list_length(a_options) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_TOO_MANY_OPTIONS, "The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT);
+        return NULL;
+    }
 
-//     if(!l_addr_from) {
-//         return NULL;
-//     }
+    if (IS_ZERO_256(a_fee)) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_ZERO_FEE, "Fee must be greater than 0\n");
+        return NULL;
+    }
 
-//     const char *l_native_ticker = s_get_native_ticker(a_net_str);
-//     uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer;
-//     dap_chain_addr_t *l_addr_fee = NULL;
-//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port);
-//     SUM_256_256(l_net_fee, a_fee, &l_total_fee);
+    dap_chain_addr_t *l_addr_from =  dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_config->net_name));
+    if(!l_addr_from) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_WALLET_NOT_FOUND, "Wallet does not exist\n");
+        return NULL;
+    }
 
-//     json_object *l_outs = NULL;
-//     int l_outputs_count = 0;
-//     if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count, l_url_str, l_port)) {
-//         return NULL;
-//     }
+    const char *l_native_ticker = s_get_native_ticker(a_config->net_name);
+    uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer;
+    dap_chain_addr_t *l_addr_fee = NULL;
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, a_config);
+    SUM_256_256(l_net_fee, a_fee, &l_total_fee);
 
-//     dap_list_t *l_list_used_out = NULL;
-//     l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
-//                                                             l_total_fee,
-//                                                             &l_value_transfer);
+    json_object *l_outs = NULL;
+    int l_outputs_count = 0;
+    if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, &l_outs, &l_outputs_count, a_config)) {
+        return NULL;
+    }
 
-//     json_object_put(l_outs);
-//     if (!l_list_used_out) {
-//         printf("Not enough funds to transfer");
-//         return NULL;
-//     }
+    dap_list_t *l_list_used_out = NULL;
+    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                            l_total_fee,
+                                                            &l_value_transfer);
 
+    json_object_put(l_outs);
+    if (!l_list_used_out) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_NOT_ENOUGH_FUNDS, "Not enough funds to transfer");
+        return NULL;
+    }
 
-//     // create empty transaction
-//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
-//     // Add Voting item
-//     dap_chain_tx_voting_t* l_voting_item = dap_chain_datum_tx_item_voting_create();
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
-//     dap_chain_datum_tx_add_item(&l_tx, l_voting_item);
-//     DAP_DELETE(l_voting_item);
+    // Add Voting item
+    dap_chain_tx_voting_t* l_voting_item = dap_chain_datum_tx_item_voting_create();
 
-//     // Add question to tsd data
-//     dap_chain_tx_tsd_t* l_question_tsd = dap_chain_datum_voting_question_tsd_create(a_question, strlen(a_question));
-//     dap_chain_datum_tx_add_item(&l_tx, l_question_tsd);
+    dap_chain_datum_tx_add_item(&l_tx, l_voting_item);
+    DAP_DELETE(l_voting_item);
 
-//     // Add options to tsd
-//     dap_list_t *l_temp = a_options;
-//     while(l_temp){
-//         if(strlen((char*)l_temp->data) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH){
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
-//         dap_chain_tx_tsd_t* l_option = dap_chain_datum_voting_answer_tsd_create((char*)l_temp->data, strlen((char*)l_temp->data));
-//         if(!l_option){
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
-//         dap_chain_datum_tx_add_item(&l_tx, l_option);
-//         DAP_DEL_Z(l_option);
+    // Add question to tsd data
+    dap_chain_tx_tsd_t* l_question_tsd = dap_chain_datum_voting_question_tsd_create(a_question, strlen(a_question));
+    dap_chain_datum_tx_add_item(&l_tx, l_question_tsd);
 
-//         l_temp = l_temp->next;
-//     }
+    // Add options to tsd
+    dap_list_t *l_temp = a_options;
+    while(l_temp){
+        if(strlen((char*)l_temp->data) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH){
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_OPTION_TOO_LONG, "The option must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH);
+            return NULL;
+        }
+        dap_chain_tx_tsd_t* l_option = dap_chain_datum_voting_answer_tsd_create((char*)l_temp->data, strlen((char*)l_temp->data));
+        if(!l_option){
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_OPTION_CREATE_FAILED, "Failed to create option\n");
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_option);
+        DAP_DEL_Z(l_option);
 
-//     // add voting expire time if needed
-//     if(a_expire_vote != 0){
-//         dap_time_t l_expired_vote = a_expire_vote;
-//         if (l_expired_vote < dap_time_now()){
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
+        l_temp = l_temp->next;
+    }
 
-//         dap_chain_tx_tsd_t* l_expired_item = dap_chain_datum_voting_expire_tsd_create(l_expired_vote);
-//         if(!l_expired_item){
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
-//         dap_chain_datum_tx_add_item(&l_tx, l_expired_item);
-//         DAP_DEL_Z(l_expired_item);
-//     }
+    // add voting expire time if needed
+    if(a_expire_vote != 0){
+        dap_time_t l_expired_vote = a_expire_vote;
+        if (l_expired_vote < dap_time_now()){
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_INVALID_EXPIRE_TIME, "Expire time must be in the future\n");
+            return NULL;
+        }
 
-//     // Add vote max count if needed
-//     if (a_max_vote != 0) {
-//         dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote);
-//         if(!l_max_votes_item){
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
-//         dap_chain_datum_tx_add_item(&l_tx, l_max_votes_item);
-//         DAP_DEL_Z(l_max_votes_item);
-//     }
+        dap_chain_tx_tsd_t* l_expired_item = dap_chain_datum_voting_expire_tsd_create(l_expired_vote);
+        if(!l_expired_item){
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_EXPIRE_CREATE_FAILED, "Failed to create expire time item\n");
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_expired_item);
+        DAP_DEL_Z(l_expired_item);
+    }
 
-//     if (a_delegated_key_required) {
-//         dap_chain_tx_tsd_t* l_delegated_key_req_item = dap_chain_datum_voting_delegated_key_required_tsd_create(true);
-//         if(!l_delegated_key_req_item){
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
-//         dap_chain_datum_tx_add_item(&l_tx, l_delegated_key_req_item);
-//         DAP_DEL_Z(l_delegated_key_req_item);
-//     }
+    // Add vote max count if needed
+    if (a_max_vote != 0) {
+        dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote);
+        if(!l_max_votes_item){
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_MAX_VOTES_CREATE_FAILED, "Failed to create max votes item\n");
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_max_votes_item);
+        DAP_DEL_Z(l_max_votes_item);
+    }
 
-//     if(a_vote_changing_allowed){
-//         dap_chain_tx_tsd_t* l_vote_changing_item = dap_chain_datum_voting_vote_changing_allowed_tsd_create(true);
-//         if(!l_vote_changing_item){
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
-//         dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item);
-//         DAP_DEL_Z(l_vote_changing_item);
-//     }
-//     if (a_token_ticker) {
-//         dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker);
-//         if (!l_voting_token_item) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
-//         dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item);
-//         DAP_DEL_Z(l_voting_token_item);
-//     }
+    if (a_delegated_key_required) {
+        dap_chain_tx_tsd_t* l_delegated_key_req_item = dap_chain_datum_voting_delegated_key_required_tsd_create(true);
+        if(!l_delegated_key_req_item){
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_DELEGATED_KEY_CREATE_FAILED, "Failed to create delegated key requirement item\n");
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_delegated_key_req_item);
+        DAP_DEL_Z(l_delegated_key_req_item);
+    }
 
-//     // add 'in' items
-//     uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-//     assert(EQUAL_256(l_value_to_items, l_value_transfer));
-//     dap_list_free_full(l_list_used_out, NULL);
-//     uint256_t l_value_pack = {};
-//     // Network fee
-//     if (l_net_fee_used) {
-//         if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
-//             SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
-//         else {
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
-//     }
-//     // Validator's fee
-//     if (!IS_ZERO_256(a_fee)) {
-//         if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1)
-//             SUM_256_256(l_value_pack, a_fee, &l_value_pack);
-//         else {
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
-//     }
-//     // coin back
-//     uint256_t l_value_back;
-//     SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-//     if(!IS_ZERO_256(l_value_back)) {
-//         if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) {
-//             dap_chain_datum_tx_delete(l_tx);
-//             return NULL;
-//         }
-//     }
+    if(a_vote_changing_allowed){
+        dap_chain_tx_tsd_t* l_vote_changing_item = dap_chain_datum_voting_vote_changing_allowed_tsd_create(true);
+        if(!l_vote_changing_item){
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_VOTE_CHANGING_CREATE_FAILED, "Failed to create vote changing item\n");
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item);
+        DAP_DEL_Z(l_vote_changing_item);
+    }
+    if (a_token_ticker) {
+        dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker);
+        if (!l_voting_token_item) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_TOKEN_CREATE_FAILED, "Failed to create token item\n");
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item);
+        DAP_DEL_Z(l_voting_token_item);
+    }
 
+    // add 'in' items
+    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+    assert(EQUAL_256(l_value_to_items, l_value_transfer));
+    dap_list_free_full(l_list_used_out, NULL);
+    uint256_t l_value_pack = {};
+    // Network fee
+    if (l_net_fee_used) {
+        if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1)
+            SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+        else {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+    }
+    // Validator's fee
+    if (!IS_ZERO_256(a_fee)) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1)
+            SUM_256_256(l_value_pack, a_fee, &l_value_pack);
+        else {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_FEE_OUTPUT_FAILED, "Can't add fee output in tx");
+            return NULL;
+        }
+    }
+    // coin back
+    uint256_t l_value_back;
+    SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+    if(!IS_ZERO_256(l_value_back)) {
+        if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_COINBACK_FAILED, "Can't add coin back in tx");
+            return NULL;
+        }
+    }
 
-//     return l_tx;
-// }
+    return l_tx;
+}
 
 /**
 int dap_cli_vote_compose(int a_argc, char **a_argv){
@@ -2885,6 +2879,38 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c
 
 
 
+typedef enum {
+    DAP_CLI_STAKE_INVALIDATE_OK = 0,
+    DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND = -1,
+    DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING = -2,
+    DAP_CLI_STAKE_INVALIDATE_WRONG_CERT = -3,
+    DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR = -4,
+    DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH = -5,
+    DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED = -6,
+    DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT = -7,
+    DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND = -8,
+    DAP_CLI_STAKE_INVALIDATE_TX_EXISTS = -9,
+    DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND = -10,
+    DAP_CLI_STAKE_INVALIDATE_COMPOSE_ERROR = -11,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR = -12,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND = -13,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT = -14,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND = -15,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR = -16,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND = -17,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND = -18,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR = -19,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER = -20,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND = -21,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND = -22,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS = -23,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR = -24,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR = -25,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR = -26,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27,
+    DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28,
+    DAP_CLI_STAKE_INVALIDATE_FEE_ERROR = -29
+} dap_cli_stake_invalidate_error_t;
 json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
                         const char *a_wallet_path, const char *a_cert_str, const char *a_fee_str, const char *a_url_str, uint16_t a_port)
 {
@@ -3429,6 +3455,45 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_order_hash_str, compose_
 
 
 
+typedef enum {
+    STAKE_DELEGATE_COMPOSE_OK = 0,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE = -1,
+    STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND = -2,
+    STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND = -3,
+    STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG = -4,
+    STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE = -5,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY = -6,
+    STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED = -7,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR = -8,
+    STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND = -9,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE = -10,
+    STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED = -11,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED = -12,
+    STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER = -13,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT = -14,
+    STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE = -15,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE = -16,
+    STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS = -17,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR = -18,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR = -19,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR = -20,
+    STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER = -21,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW = -22,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH = -23,
+    STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER = -24,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER = -25,
+    STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX = -26,
+    STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN = -27,
+    DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS = -28,
+    DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE = -29,
+    DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE = -30,
+    DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR = -31,
+    DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR = -32,
+    DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR = -33,
+    DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR = -34,
+    DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -35,
+    DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -36
+} stake_delegate_error_t;
 json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
                                         const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, 
                                         const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path) {
@@ -3874,6 +3939,18 @@ static dap_chain_datum_tx_t *dap_order_tx_create_compose(dap_enc_key_t *a_key,
 }
 
 
+typedef enum {
+    STAKE_ORDER_CREATE_STAKER_OK = 0,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_PARAMS = -1,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -2,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -3,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -4,
+    STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -5,
+    STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -6,
+    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -7,
+    STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -8,
+    STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -9
+} dap_cli_srv_stake_order_create_staker_error_t;
 json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) {
     compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port);
     if (!l_config) {
@@ -3937,6 +4014,41 @@ json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str
     return s_compose_config_return_response_handler(l_config);
 }
 
+
+typedef enum {
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_OK = 0,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_WALLET_NOT_FOUND,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_KEY_NOT_FOUND,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ORDER_HASH,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_RPC_RESPONSE,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ADDR,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TAX,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_COND_TX,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TOKEN_TICKER,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TS_CREATED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PRICE,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TX,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_ENOUGH_FUNDS,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_SIGN,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_ITEMS_FOUND,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_COND_TX,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TOKEN_TICKER,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TIMESTAMP,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INSUFFICIENT_FUNDS,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE_FAILED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_COIN_RETURN_FAILED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NET_FEE_FAILED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_COINBACK_FAILED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_TOO_HIGH,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_VALIDATOR_FEE_FAILED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_ALREADY_USED,
+    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_OWNER
+} srv_stake_order_remove_compose_error_t;
 json_object * dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) {
 
     compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port);
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index 7d42deaa98..e70baec8da 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -70,19 +70,7 @@ uint16_t dap_compose_get_net_port(const char* name);
 
 json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port);
 json_object* dap_tx_create_xchange_compose(const char *l_net_str, const char *l_token_sell, const char *l_token_buy, const char *l_wallet_str, const char *l_wallet_path, const char *l_value_str, const char *l_rate_str, const char *l_fee_str, const char *l_url_str, uint16_t l_port);
-typedef enum dap_tx_cond_create_compose_error {
-    TX_COND_CREATE_COMPOSE_ERROR_INVALID_FEE = 1,
-    TX_COND_CREATE_COMPOSE_ERROR_INVALID_SERVICE_UID,
-    TX_COND_CREATE_COMPOSE_ERROR_INVALID_UNIT,
-    TX_COND_CREATE_COMPOSE_ERROR_INVALID_VALUE,
-    TX_COND_CREATE_COMPOSE_ERROR_WALLET_OPEN_FAILED,
-    TX_COND_CREATE_COMPOSE_ERROR_CERT_NOT_FOUND,
-    TX_COND_CREATE_COMPOSE_ERROR_INVALID_CERT_KEY,
-    TX_COND_CREATE_COMPOSE_ERROR_NATIVE_TOKEN_REQUIRED,
-    TX_COND_CREATE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS,
-    TX_COND_CREATE_COMPOSE_ERROR_COND_OUTPUT_FAILED,
-    TX_COND_CREATE_COMPOSE_ERROR_COIN_BACK_FAILED
-} dap_tx_cond_create_compose_error_t;
+
 json_object* dap_tx_cond_create_compose(const char *a_net_name, const char *a_token_ticker, const char *a_wallet_str, const char *a_wallet_path,
                                         const char *a_cert_str, const char *a_value_datoshi_str, const char *a_value_fee_str, const char *a_unit_str, 
                                         const char *a_srv_uid_str, const char *a_url_str, uint16_t a_port);
@@ -91,145 +79,26 @@ json_object * dap_cli_hold_compose(const char *a_net_name, const char *a_chain_i
                                     const char *a_cert_str, const char *a_value_fee_str, const char *a_reinvest_percent_str, const char *a_url_str, uint16_t a_port);
 json_object* dap_cli_take_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_tx_str, const char *a_tx_burning_str,
                                     const char *a_value_fee_str, const char *a_url_str, uint16_t a_port);
-int dap_cli_voting_compose(int a_argc, char **a_argv);
-typedef enum {
-    STAKE_ORDER_CREATE_STAKER_OK = 0,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_PARAMS = -1,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -2,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -3,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -4,
-    STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -5,
-    STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -6,
-    STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -7,
-    STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -8,
-    STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -9
-} dap_cli_srv_stake_order_create_staker_error_t;
+json_object* dap_cli_voting_compose(const char *a_net_name, const char *a_question_str, const char *a_options_list_str, 
+                                    const char *a_voting_expire_str, const char *a_max_votes_count_str, const char *a_fee_str, 
+                                    bool a_is_delegated_key, bool a_is_vote_changing_allowed, const char *a_wallet_str, const char *a_wallet_path, 
+                                    const char *a_token_str, const char *a_url_str, uint16_t a_port);
+
 json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port);
 
-typedef enum {
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_OK = 0,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_WALLET_NOT_FOUND,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_KEY_NOT_FOUND,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ORDER_HASH,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_RPC_RESPONSE,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ADDR,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TAX,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_COND_TX,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TOKEN_TICKER,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TS_CREATED,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PRICE,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TX,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_ENOUGH_FUNDS,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_SIGN,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_ITEMS_FOUND,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_COND_TX,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TOKEN_TICKER,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TIMESTAMP,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INSUFFICIENT_FUNDS,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE_FAILED,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_COIN_RETURN_FAILED,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NET_FEE_FAILED,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_COINBACK_FAILED,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_TOO_HIGH,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_VALIDATOR_FEE_FAILED,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_ALREADY_USED,
-    SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_OWNER
-} srv_stake_order_remove_compose_error_t;
 dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(dap_hash_fast_t *a_hash_tx, uint256_t a_fee,
                                      dap_chain_wallet_t *a_wallet, compose_config_t *a_config);
 json_object* dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port);
 
-typedef enum {
-    STAKE_DELEGATE_COMPOSE_OK = 0,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE = -1,
-    STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND = -2,
-    STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND = -3,
-    STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG = -4,
-    STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE = -5,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY = -6,
-    STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED = -7,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR = -8,
-    STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND = -9,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE = -10,
-    STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED = -11,
-    STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED = -12,
-    STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER = -13,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT = -14,
-    STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE = -15,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE = -16,
-    STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS = -17,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR = -18,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR = -19,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR = -20,
-    STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER = -21,
-    STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW = -22,
-    STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH = -23,
-    STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER = -24,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER = -25,
-    STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX = -26,
-    STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN = -27,
-    DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS = -28,
-    DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE = -29,
-    DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE = -30,
-    DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR = -31,
-    DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR = -32,
-    DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR = -33,
-    DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR = -34,
-    DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -35,
-    DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -36
-} stake_delegate_error_t;
 json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, 
                                         const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, 
                                         const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path);
-typedef enum {
-    DAP_CLI_STAKE_INVALIDATE_OK = 0,
-    DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND = -1,
-    DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING = -2,
-    DAP_CLI_STAKE_INVALIDATE_WRONG_CERT = -3,
-    DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR = -4,
-    DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH = -5,
-    DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED = -6,
-    DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT = -7,
-    DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND = -8,
-    DAP_CLI_STAKE_INVALIDATE_TX_EXISTS = -9,
-    DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND = -10,
-    DAP_CLI_STAKE_INVALIDATE_COMPOSE_ERROR = -11,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR = -12,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND = -13,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT = -14,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND = -15,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR = -16,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND = -17,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND = -18,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR = -19,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER = -20,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND = -21,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND = -22,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS = -23,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR = -24,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR = -25,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR = -26,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27,
-    DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28,
-    DAP_CLI_STAKE_INVALIDATE_FEE_ERROR = -29
-} dap_cli_stake_invalidate_error_t;
+
 dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, compose_config_t *a_config);
 json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, 
                         const char *a_wallet_path, const char *a_cert_str, const char *a_fee_str, const char *a_url_str, uint16_t a_port);
 
-typedef enum {
-    DAP_COMPOSE_ERROR_NONE = 0,
-    DAP_COMPOSE_ERROR_RESPONSE_NULL = -1,
-    DAP_COMPOSE_ERROR_RESULT_NOT_FOUND = -2,
-    DAP_COMPOSE_ERROR_REQUEST_INIT_FAILED = -3,
-    DAP_COMPOSE_ERROR_REQUEST_TIMEOUT = -4,
-    DAP_COMPOSE_ERROR_REQUEST_FAILED = -5
-} dap_compose_error_t;
+
 json_object* dap_request_command_to_rpc(const char *request, compose_config_t *a_config);
 int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add);
 
@@ -265,7 +134,7 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(dap_enc_key_t *a_key
 dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
                               uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
-                              const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port);
+                              const char *a_token_ticker, compose_config_t *a_config);
 dap_chain_datum_tx_t *dap_stake_tx_create_compose(dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
-- 
GitLab


From 7f651debd2867bb96a97b368c7c9fff0f7e7fcc6 Mon Sep 17 00:00:00 2001
From: Olzhas <oljas.jarasbaev@demlabs.net>
Date: Thu, 17 Apr 2025 17:19:16 +0700
Subject: [PATCH 52/53] [+] purchase

---
 modules/compose/dap_chain_tx_compose.c        | 1014 ++++++++++-------
 .../compose/include/dap_chain_tx_compose.h    |   12 +-
 2 files changed, 636 insertions(+), 390 deletions(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 01a0815284..56681e539e 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -2548,334 +2548,295 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question,
     return l_tx;
 }
 
-/**
-int dap_cli_vote_compose(int a_argc, char **a_argv){
-    const char* l_cert_name = NULL;
-    const char* l_fee_str = NULL;
-    const char* l_wallet_str = NULL;
-    const char* l_hash_str = NULL;
-    const char* l_option_idx_str = NULL;
-    const char* l_net_str = NULL;
-    int arg_index = 1;
-
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
-    if(!l_net_str) {
-        printf("command requires parameter '-net'\n");
-        return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING;
-    } 
-
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hash", &l_hash_str);
-    if(!l_hash_str){
-        printf("Command 'vote' require the parameter -hash\n");
-        return -DAP_CHAIN_NET_VOTE_VOTING_HASH_NOT_FOUND;
-    }
 
-    dap_hash_fast_t l_voting_hash = {};
-    if (dap_chain_hash_fast_from_str(l_hash_str, &l_voting_hash)) {
-        printf("Hash string is not recognozed as hex of base58 hash\n");
-        return -DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID;
-    }
-
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_name);
-    dap_cert_t * l_cert = dap_cert_find_by_name(l_cert_name);
-    if (l_cert_name){
-        if (l_cert == NULL) {
-            printf("Can't find \"%s\" certificate\n", l_cert_name);
-            return -DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_FIND_CERT;
-        }
-    }
+// json_object* dap_cli_vote_compose(const char *a_net_str, const char *a_hash_str, const char *a_cert_name, const char *a_fee_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_option_idx_str, const char *a_url_str, uint16_t a_port) {
+//     compose_config_t *l_config = s_compose_config_init(a_net_str, a_url_str, a_port);
+//     if (!l_config) {
+//         json_object* l_json_obj_ret = json_object_new_object();
+//         dap_json_compose_error_add(l_json_obj_ret, TX_CREATE_COMPOSE_INVALID_CONFIG, "Can't create compose config");
+//         return l_json_obj_ret;
+//     }
 
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str);
-    if (!l_fee_str){
-        printf("Command 'vote' requires paramete -fee to be valid.\n");
-        return -DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_NOT_VALID;
-    }
-    uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str);
-    if (IS_ZERO_256(l_value_fee)) {
-        printf("command requires parameter '-fee' to be valid uint256\n");            
-        return -DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_BAD_TYPE;
-    }
+//     dap_hash_fast_t l_voting_hash = {};
+//     if (dap_chain_hash_fast_from_str(a_hash_str, &l_voting_hash)) {
+//         dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID, "Hash string is not recognozed as hex of base58 hash\n");
+//         return s_compose_config_return_response_handler(l_config);
+//     }
 
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str);
-    if (!l_wallet_str){
-        printf("Command 'vote' requires parameter -w to be valid.\n");
-        return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_PARAM_NOT_VALID;
-    }
+//     dap_cert_t * l_cert = dap_cert_find_by_name(a_cert_name);
+//     if (a_cert_name){
+//         if (l_cert == NULL) {
+//             dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_FIND_CERT, "Can't find \"%s\" certificate\n", l_cert_name);
+//             return s_compose_config_return_response_handler(l_config);
+//         }
+//     }
+//     uint256_t l_value_fee = dap_chain_balance_scan(a_fee_str);
+//     if (IS_ZERO_256(l_value_fee)) {
+//         dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_BAD_TYPE, "command requires parameter '-fee' to be valid uint256\n");            
+//         return s_compose_config_return_response_handler(l_config);
+//     }
 
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-option_idx", &l_option_idx_str);
-    if (!l_option_idx_str){
-        printf("Command 'vote' requires parameter -option_idx to be valid.\n");
-        return -DAP_CHAIN_NET_VOTE_VOTING_OPTION_IDX_PARAM_NOT_VALID;
-    }
 
-    const char *l_wallet_path = dap_chain_wallet_get_path(g_config);
-    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path,NULL);
-    if (!l_wallet) {
-        printf("Wallet %s does not exist\n", l_wallet_str);
-        return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST;
-    }
+//     const char *l_wallet_path = dap_chain_wallet_get_path(g_config);
+//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path,NULL);
+//     if (!l_wallet) {
+//         dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST, "Wallet %s does not exist\n", a_wallet_str);
+//         return s_compose_config_return_response_handler(l_config);
+//     }
 
-    uint64_t l_option_idx_count = strtoul(l_option_idx_str, NULL, 10);
+//     uint64_t l_option_idx_count = strtoul(a_option_idx_str, NULL, 10);
 
-    char *l_hash_tx;
+//     char *l_hash_tx;
 
-    int res = dap_chain_net_vote_voting_compose(l_cert, l_value_fee, l_wallet, l_voting_hash, l_option_idx_count,
-                                        l_net_str, &l_hash_tx);
-    dap_chain_wallet_close(l_wallet);
+//     int res = dap_chain_net_vote_voting_compose(l_cert, l_value_fee, l_wallet, l_voting_hash, l_option_idx_count, &l_hash_tx, l_config);
+//     dap_chain_wallet_close(l_wallet);
 
-    return res;
-}
+//     return res;
+// }
 
 
-int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wallet_t *a_wallet, dap_hash_fast_t a_hash,
-                              uint64_t a_option_idx, const char *a_net_str, const char *a_hash_out_type,
-                              char **a_hash_tx_out) {
-    const char * l_hash_str = dap_chain_hash_fast_to_str_static(&a_hash);
-    char data[512];
-    snprintf(data, sizeof(data), 
-            "{\"method\": \"voting\",\"params\": [\"voting;dump;-hash;%s\"],\"id\": \"2\"}", l_hash_str);
-    json_object *l_json_voting = dap_request_command_to_rpc(data);
-    if (!l_json_voting) {
-        printf("Error: Can't get voting info\n");
-        return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
-    }
+// dap_chain_datum_tx_t* dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wallet_t *a_wallet, dap_hash_fast_t a_hash,
+//                               uint64_t a_option_idx, const char *a_hash_out_type,
+//                               char **a_hash_tx_out, compose_config_t *a_config) {
+//     if (!a_config) {
+//         return NULL;
+//     }
+//     const char * l_hash_str = dap_chain_hash_fast_to_str_static(&a_hash);
+//     char data[512];
+//     snprintf(data, sizeof(data), 
+//             "{\"method\": \"voting\",\"params\": [\"voting;dump;-hash;%s\"],\"id\": \"2\"}", l_hash_str);
+//     json_object *l_json_voting = dap_request_command_to_rpc(data, a_config);
+//     if (!l_json_voting) {
+//         dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS, "Error: Can't get voting info\n");
+//         return NULL;
+//     }
 
     
-    json_object *l_voting_info = json_object_array_get_idx(l_json_voting, 0);
-    if (!l_voting_info) {
-        printf("Error: Can't get voting info from JSON\n");
-        return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
-    }
-
-    const char *l_voting_tx = json_object_get_string(json_object_object_get(l_voting_info, "voting_tx"));
-    const char *l_expiration_str = json_object_get_string(json_object_object_get(l_voting_info, "expiration"));
-    const char *l_status = json_object_get_string(json_object_object_get(l_voting_info, "status"));
-    int l_votes_max = json_object_get_int(json_object_object_get(l_voting_info, "votes_max"));
-    int l_votes_available = json_object_get_int(json_object_object_get(l_voting_info, "votes_available"));
-    bool l_vote_changed = json_object_get_boolean(json_object_object_get(l_voting_info, "can_change_status"));
-    bool l_delegated_key_required = json_object_get_boolean(json_object_object_get(l_voting_info, "delegated_key_required"));
-
-    json_object *l_results = json_object_object_get(l_voting_info, "results");
-    if (!l_results) {
-        printf("Error: Can't get results from JSON\n");
-        return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS;
-    }
-
-    int l_results_count = json_object_array_length(l_results);
+//     json_object *l_voting_info = json_object_array_get_idx(l_json_voting, 0);
+//     if (!l_voting_info) {
+//         dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS, "Error: Can't get voting info from JSON\n");
+//         return NULL;
+//     }
 
+//     const char *l_voting_tx = json_object_get_string(json_object_object_get(l_voting_info, "voting_tx"));
+//     const char *l_expiration_str = json_object_get_string(json_object_object_get(l_voting_info, "expiration"));
+//     const char *l_status = json_object_get_string(json_object_object_get(l_voting_info, "status"));
+//     int l_votes_max = json_object_get_int(json_object_object_get(l_voting_info, "votes_max"));
+//     int l_votes_available = json_object_get_int(json_object_object_get(l_voting_info, "votes_available"));
+//     bool l_vote_changed = json_object_get_boolean(json_object_object_get(l_voting_info, "can_change_status"));
+//     bool l_delegated_key_required = json_object_get_boolean(json_object_object_get(l_voting_info, "delegated_key_required"));
+
+//     json_object *l_results = json_object_object_get(l_voting_info, "results");
+//     if (!l_results) {
+//         dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS, "Error: Can't get results from JSON\n");
+//         return NULL;
+//     }
 
-    if (l_votes_max && l_votes_max <= l_results_count)
-        return DAP_CHAIN_NET_VOTE_VOTING_THIS_VOTING_HAVE_MAX_VALUE_VOTES;
+//     int l_results_count = json_object_array_length(l_results);
 
-    if (l_expiration_str) {
-        struct tm tm;
-        strptime(l_expiration_str, "%a, %d %b %Y %H:%M:%S %z", &tm);
-        time_t l_expiration_time = mktime(&tm);
-        if (l_expiration_time && dap_time_now() > l_expiration_time)
-            return DAP_CHAIN_NET_VOTE_VOTING_ALREADY_EXPIRED;
-    }
 
-    dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str));
-    if (!l_addr_from)
-        return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID;
+//     if (l_votes_max && l_votes_max <= l_results_count)
+//         dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_THIS_VOTING_HAVE_MAX_VALUE_VOTES, "This voting have max value votes\n");
+//         return NULL;
 
-    dap_hash_fast_t l_pkey_hash = {0};
-    if (l_delegated_key_required) {
-        if (!a_cert)
-            return DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED;
-        if (dap_cert_get_pkey_hash(a_cert, &l_pkey_hash))
-            return DAP_CHAIN_NET_VOTE_VOTING_NO_KEY_FOUND_IN_CERT;
-        char data[512];
-        snprintf(data, sizeof(data), 
-                "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str);
-        json_object *l_json_coins = dap_request_command_to_rpc(data);
-        if (!l_json_coins) {
-            printf("Error: Failed to retrieve coins from ledger\n");
-            return -4;
-        }
-        const char * l_hash_fast_str[DAP_HASH_FAST_STR_SIZE] = {};
-        dap_chain_hash_fast_from_str(l_hash_fast_str, &l_pkey_hash);
-        if (!l_hash_fast_str) {
-            printf("Error: Can't covert l_pkey_hash to str");
-            return -5;
-        }
-        int items_count = json_object_array_length(l_json_coins);
-        bool found = false;
-        for (int i = 0; i < items_count; i++) {
-            json_object *item = json_object_array_get_idx(l_json_coins, i);
-            const char *pkey_hash_str = json_object_get_string(json_object_object_get(item, "pkey_hash"));
-            if (l_hash_fast_str && !dap_strcmp(l_hash_fast_str, pkey_hash_str)) {
-                const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash"));
-                if (dap_chain_hash_fast_from_str(tx_hash_str, &l_pkey_hash)) {
-                    printf("Invalid transaction hash format\n");
-                    return DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED;
-                }
-                found = true;
-                break;
-            }
-        }
-        if (!found) {
-            printf("Specified certificate/pkey hash is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n");
-            return -9;
-        }
+//     if (l_expiration_str) {
+//         struct tm tm;
+//         strptime(l_expiration_str, "%a, %d %b %Y %H:%M:%S %z", &tm);
+//         time_t l_expiration_time = mktime(&tm);
+//         if (l_expiration_time && dap_time_now() > l_expiration_time)
+//             dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_ALREADY_EXPIRED, "This voting already expired\n");
+//             return NULL;
+//     }
 
+//     dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(l_config->net_name));
+//     if (!l_addr_from)
+//         dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID, "Source address is invalid\n");
+//         return NULL;
+
+//     dap_hash_fast_t l_pkey_hash = {0};
+//     if (l_delegated_key_required) {
+//         if (!a_cert)
+//             return DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED;
+//         if (dap_cert_get_pkey_hash(a_cert, &l_pkey_hash))
+//             return DAP_CHAIN_NET_VOTE_VOTING_NO_KEY_FOUND_IN_CERT;
+//         char data[512];
+//         snprintf(data, sizeof(data), 
+//                 "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str);
+//         json_object *l_json_coins = dap_request_command_to_rpc(data, a_config);
+//         if (!l_json_coins) {
+//             dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_FAILED_TO_RETRIEVE_COINS_FROM_LEDGER, "Failed to retrieve coins from ledger\n");
+//             return NULL;
+//         }
+//         const char * l_hash_fast_str[DAP_HASH_FAST_STR_SIZE] = {};
+//         dap_chain_hash_fast_from_str(l_hash_fast_str, &l_pkey_hash);
+//         if (!l_hash_fast_str) {
+//             dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_FAILED_TO_RETRIEVE_COINS_FROM_LEDGER, "Can't covert l_pkey_hash to str");
+//             return NULL;
+//         }
+//         int items_count = json_object_array_length(l_json_coins);
+//         bool found = false;
+//         for (int i = 0; i < items_count; i++) {
+//             json_object *item = json_object_array_get_idx(l_json_coins, i);
+//             const char *pkey_hash_str = json_object_get_string(json_object_object_get(item, "pkey_hash"));
+//             if (l_hash_fast_str && !dap_strcmp(l_hash_fast_str, pkey_hash_str)) {
+//                 const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash"));
+//                 if (dap_chain_hash_fast_from_str(tx_hash_str, &l_pkey_hash)) {
+//                     dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED, "Invalid transaction hash format\n");
+//                     return NULL;
+//                 }
+//                 found = true;
+//                 break;
+//             }
+//         }
+//         if (!found) {
+//             dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED, "Specified certificate/pkey hash is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n");
+//             return NULL;
+//         }
 
-    } else
-        l_pkey_hash = l_addr_from->data.hash_fast;
 
+//     } else
+//         l_pkey_hash = l_addr_from->data.hash_fast;
 
-    const char *l_token_ticker = json_object_get_string(json_object_object_get(l_voting_info, "token"));
-    uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer;
-    dap_chain_addr_t* l_addr_fee = NULL;
-    bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee);
-    if (l_net_fee_used)
-        SUM_256_256(l_net_fee, a_fee, &l_total_fee);
 
-    bool l_native_tx = !dap_strcmp(l_token_ticker, s_get_native_ticker(a_net_str));
+//     const char *l_token_ticker = json_object_get_string(json_object_object_get(l_voting_info, "token"));
+//     uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer;
+//     dap_chain_addr_t* l_addr_fee = NULL;
+//     bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, l_config);
+//     if (l_net_fee_used)
+//         SUM_256_256(l_net_fee, a_fee, &l_total_fee);
 
-    json_object *l_outs = NULL;
-    int l_outputs_count = 0;
-    if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_token_ticker, a_net_str, &l_outs, &l_outputs_count)) {
-        return -11;
-    }
+//     bool l_native_tx = !dap_strcmp(l_token_ticker, s_get_native_ticker(l_config->net_name));
 
-    dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
-                                                            l_total_fee,
-                                                            &l_value_transfer);
-    json_object_put(l_outs);
-    if (!l_list_used_out) {
-        printf("Not enough funds to transfer");
-        return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER;
-    }
-
-    // check outputs UTXOs
-    uint256_t l_value_transfer_new = {};
-    dap_list_t *it, *tmp;
-    DL_FOREACH_SAFE(l_list_used_out, it, tmp) {
-        dap_chain_tx_used_out_item_t *l_out = (dap_chain_tx_used_out_item_t *)it->data;
-        if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out,
-                                               l_vote_changed ? &l_pkey_hash : NULL)) {
-            l_list_used_out = dap_list_delete_link(l_list_used_out, it);
-            continue;
-        }
-        if (SUM_256_256(l_value_transfer_new, l_out->value, &l_value_transfer_new))
-            return DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW;
-    }
+//     json_object *l_outs = NULL;
+//     int l_outputs_count = 0;
+//     if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_token_ticker, l_config->net_name, &l_outs, &l_outputs_count)) {
+//         dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_FAILED_TO_GET_REMOTE_WALLET_OUTS, "Failed to get remote wallet outs\n");
+//         return NULL;
+//     }
 
-    if (IS_ZERO_256(l_value_transfer_new) || (l_native_tx && compare256(l_value_transfer_new, l_total_fee) <= 0))
-        return DAP_CHAIN_NET_VOTE_VOTING_UNSPENT_UTX0_FOR_PARTICIPATION_THIS_VOTING;
+//     dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+//                                                             l_total_fee,
+//                                                             &l_value_transfer);
+//     json_object_put(l_outs);
+//     if (!l_list_used_out) {
+//         printf("Not enough funds to transfer");
+//         return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER;
+//     }
 
-    l_value_transfer = l_value_transfer_new;
+//     // check outputs UTXOs
+//     uint256_t l_value_transfer_new = {};
+//     dap_list_t *it, *tmp;
+//     DL_FOREACH_SAFE(l_list_used_out, it, tmp) {
+//         dap_chain_tx_used_out_item_t *l_out = (dap_chain_tx_used_out_item_t *)it->data;
+//         if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out,
+//                                                l_vote_changed ? &l_pkey_hash : NULL)) {
+//             l_list_used_out = dap_list_delete_link(l_list_used_out, it);
+//             continue;
+//         }
+//         if (SUM_256_256(l_value_transfer_new, l_out->value, &l_value_transfer_new))
+//             return DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW;
+//     }
 
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+//     if (IS_ZERO_256(l_value_transfer_new) || (l_native_tx && compare256(l_value_transfer_new, l_total_fee) <= 0))
+//         return DAP_CHAIN_NET_VOTE_VOTING_UNSPENT_UTX0_FOR_PARTICIPATION_THIS_VOTING;
 
-    uint256_t l_value_back = l_value_transfer, l_fee_back = {};
-    if (!l_native_tx) {
-        dap_list_t *l_list_fee_outs = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_net->pub.native_ticker, l_addr_from, l_total_fee, &l_fee_transfer);
-        if (!l_list_fee_outs) {
-            dap_chain_datum_tx_delete(l_tx);
-            return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER;
-        }
-        uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_outs);
-        assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
-        dap_list_free_full(l_list_fee_outs, NULL);
-        SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_back);
-    } else
-        SUBTRACT_256_256(l_value_transfer, l_total_fee, &l_value_back);
+//     l_value_transfer = l_value_transfer_new;
 
-    // add 'in' items
-    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-    assert(EQUAL_256(l_value_to_items, l_value_transfer));
-    dap_list_free_full(l_list_used_out, NULL);
+//     // create empty transaction
+//     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
-    // Add vote item
-    if (a_option_idx > dap_list_length(l_voting->voting_params.option_offsets_list)){
-        dap_chain_datum_tx_delete(l_tx);
-        return DAP_CHAIN_NET_VOTE_VOTING_INVALID_OPTION_INDEX;
-    }
-    dap_chain_tx_vote_t* l_vote_item = dap_chain_datum_tx_item_vote_create(&a_hash, &a_option_idx);
-    if(!l_vote_item){
-        dap_chain_datum_tx_delete(l_tx);
-        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_VOTE_ITEM;
-    }
-    dap_chain_datum_tx_add_item(&l_tx, l_vote_item);
-    DAP_DEL_Z(l_vote_item);
-
-    // add out conds items
-    dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from);
-    for (dap_list_t *it = l_outs; it; it = it->next) {
-        dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data;
-        if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out,
-                                                  l_vote_changed ? &l_pkey_hash : NULL) != 0)
-            continue;
-        dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out);
-        if(!l_item){
-            dap_chain_datum_tx_delete(l_tx);
-
-            dap_list_free_full(l_outs, NULL);
-            return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_TSD_TX_COND_ITEM;
-        }
-        dap_chain_datum_tx_add_item(&l_tx, l_item);
-        DAP_DEL_Z(l_item);
-    }
-    dap_list_free_full(l_outs, NULL);
+//     uint256_t l_value_back = l_value_transfer, l_fee_back = {};
+//     if (!l_native_tx) {
+//         dap_list_t *l_list_fee_outs = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_net->pub.native_ticker, l_addr_from, l_total_fee, &l_fee_transfer);
+//         if (!l_list_fee_outs) {
+//             dap_chain_datum_tx_delete(l_tx);
+//             return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER;
+//         }
+//         uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_outs);
+//         assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+//         dap_list_free_full(l_list_fee_outs, NULL);
+//         SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_back);
+//     } else
+//         SUBTRACT_256_256(l_value_transfer, l_total_fee, &l_value_back);
+
+//     // add 'in' items
+//     uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+//     assert(EQUAL_256(l_value_to_items, l_value_transfer));
+//     dap_list_free_full(l_list_used_out, NULL);
+
+//     // Add vote item
+//     if (a_option_idx > dap_list_length(l_voting->voting_params.option_offsets_list)){
+//         dap_chain_datum_tx_delete(l_tx);
+//         return DAP_CHAIN_NET_VOTE_VOTING_INVALID_OPTION_INDEX;
+//     }
+//     dap_chain_tx_vote_t* l_vote_item = dap_chain_datum_tx_item_vote_create(&a_hash, &a_option_idx);
+//     if(!l_vote_item){
+//         dap_chain_datum_tx_delete(l_tx);
+//         return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_VOTE_ITEM;
+//     }
+//     dap_chain_datum_tx_add_item(&l_tx, l_vote_item);
+//     DAP_DEL_Z(l_vote_item);
+
+//     // add out conds items
+//     dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from);
+//     for (dap_list_t *it = l_outs; it; it = it->next) {
+//         dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data;
+//         if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out,
+//                                                   l_vote_changed ? &l_pkey_hash : NULL) != 0)
+//             continue;
+//         dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out);
+//         if(!l_item){
+//             dap_chain_datum_tx_delete(l_tx);
+
+//             dap_list_free_full(l_outs, NULL);
+//             return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_TSD_TX_COND_ITEM;
+//         }
+//         dap_chain_datum_tx_add_item(&l_tx, l_item);
+//         DAP_DEL_Z(l_item);
+//     }
+//     dap_list_free_full(l_outs, NULL);
 
-    // Network fee
-    if (l_net_fee_used && dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, a_net->pub.native_ticker) != 1) {
-        dap_chain_datum_tx_delete(l_tx);
-        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT;
-    }
+//     // Network fee
+//     if (l_net_fee_used && dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, a_net->pub.native_ticker) != 1) {
+//         dap_chain_datum_tx_delete(l_tx);
+//         return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT;
+//     }
 
-    // Validator's fee
-    if (!IS_ZERO_256(a_fee) && dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
-        dap_chain_datum_tx_delete(l_tx);
-        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT;
-    }
+//     // Validator's fee
+//     if (!IS_ZERO_256(a_fee) && dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) {
+//         dap_chain_datum_tx_delete(l_tx);
+//         return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT;
+//     }
 
-    // coin back
-    if (!IS_ZERO_256(l_value_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_token_ticker) != 1) {
-        dap_chain_datum_tx_delete(l_tx);
-        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
-    }
-    if (!IS_ZERO_256(l_fee_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_fee_back, a_net->pub.native_ticker) != 1) {
-        dap_chain_datum_tx_delete(l_tx);
-        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
-    }
+//     // coin back
+//     if (!IS_ZERO_256(l_value_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_token_ticker) != 1) {
+//         dap_chain_datum_tx_delete(l_tx);
+//         return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
+//     }
+//     if (!IS_ZERO_256(l_fee_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_fee_back, a_net->pub.native_ticker) != 1) {
+//         dap_chain_datum_tx_delete(l_tx);
+//         return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK;
+//     }
 
-    dap_enc_key_t *l_priv_key = dap_chain_wallet_get_key(a_wallet, 0);
-    // add 'sign' items with wallet sign
-    if (dap_chain_datum_tx_add_sign_item(&l_tx, l_priv_key) != 1) {
-        dap_chain_datum_tx_delete(l_tx);
-        dap_enc_key_delete(l_priv_key);
-        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX;
-    }
-    dap_enc_key_delete(l_priv_key);
+//     dap_enc_key_t *l_priv_key = dap_chain_wallet_get_key(a_wallet, 0);
+//     // add 'sign' items with wallet sign
+//     if (dap_chain_datum_tx_add_sign_item(&l_tx, l_priv_key) != 1) {
+//         dap_chain_datum_tx_delete(l_tx);
+//         dap_enc_key_delete(l_priv_key);
+//         return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX;
+//     }
+//     dap_enc_key_delete(l_priv_key);
 
-    // add 'sign' items with delegated key if needed
-    if (a_cert && dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) {
-        dap_chain_datum_tx_delete(l_tx);
-        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX;
-    }
+//     // add 'sign' items with delegated key if needed
+//     if (a_cert && dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) {
+//         dap_chain_datum_tx_delete(l_tx);
+//         return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX;
+//     }
 
-    size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
-    dap_hash_fast_t l_tx_hash;
-    dap_hash_fast(l_tx, l_tx_size, &l_tx_hash);
-    dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, l_tx_size);
-    DAP_DELETE(l_tx);
-    dap_chain_t* l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX);
 
-    char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, a_hash_out_type);
-    DAP_DELETE(l_datum);
-    if (l_ret) {
-        *a_hash_tx_out = l_ret;
-        return DAP_CHAIN_NET_VOTE_VOTING_OK;
-    } else {
-        return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_POOL_IN_MEMPOOL;
-    }
-}
+//     return l_tx;
+// }
 
-*/
 
 
 
@@ -4494,109 +4455,388 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(dap_hash_fast_t *
     DAP_DELETE(l_price);
     return l_tx;
 }
+typedef enum dap_tx_create_xchange_purchase_compose_error {
+    DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_NONE = 0,
+    DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_CONFIG_CREATE,
+    DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_FEE,
+    DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_HASH,
+    DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_WALLET_NOT_FOUND
+} dap_tx_create_xchange_purchase_compose_error_t;
+
+json_object *dap_tx_create_xchange_purchase_compose (const char *a_net_name, const char *a_order_hash, const char* a_value, 
+                                                     const char* a_fee, const char *a_wallet_name, const char *a_wallet_path, 
+                                                     const char *a_url_str, uint16_t a_port) {
+   compose_config_t *l_config = s_compose_config_init(a_net_name, a_url_str, a_port);
+   if (!l_config) {
+        json_object *l_json_obj_ret = json_object_new_object();
+        dap_json_compose_error_add(l_json_obj_ret, DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_CONFIG_CREATE, "Can't create compose config");
+        return l_json_obj_ret;
+   }
 
+    uint256_t l_datoshi_buy = dap_chain_balance_scan(a_value);
+    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_name, a_wallet_path, NULL);
+    if (!l_wallet) {
+        dap_json_compose_error_add(l_config->response_handler, DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_WALLET_NOT_FOUND, "Specified wallet not found");
+        return s_compose_config_return_response_handler(l_config);
+    }
 
-// srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value>
-// int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) {
-//     int arg_index = 1;
-//     const char * l_net_name = NULL;
-//     const char * l_wallet_name = NULL;  
-//     const char * l_order_hash = NULL;
-//     const char * l_value = NULL;
-//     const char * l_fee = NULL;
+   uint256_t l_datoshi_fee = dap_chain_balance_scan(a_fee);
+   if (IS_ZERO_256(l_datoshi_fee)) {
+        dap_json_compose_error_add(l_config->response_handler, DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_FEE, "Fee must be greater than 0");
+        return s_compose_config_return_response_handler(l_config);
+   }
+    dap_hash_fast_t l_tx_hash = {};
+    dap_chain_hash_fast_from_str(a_order_hash, &l_tx_hash);
+    if (dap_hash_fast_is_blank(&l_tx_hash)) {
+        dap_json_compose_error_add(l_config->response_handler, DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_HASH, "Invalid order hash");
+        return s_compose_config_return_response_handler(l_config);
+    }
+    char *l_str_ret_hash = NULL;
+    dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_purchase_compose(&l_tx_hash, l_datoshi_buy, l_datoshi_fee,
+                                                        l_wallet, &l_str_ret_hash, l_config);
+    if (l_tx) {
+        dap_chain_net_tx_to_json(l_tx, l_config->response_handler);
+        DAP_DELETE(l_tx);
+    }
+    return s_compose_config_return_response_handler(l_config);
+}
 
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
-//     if (!l_net_name) {
-//         printf("tx_create requires parameter '-net'");
-//         return -1;
-//     }
+typedef enum dap_chain_net_srv_xchange_purchase_compose_error {
+    DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NONE = 0,
+    DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_PARAMS,
+    DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE,
+    DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT,
+    DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_ITEMS_FOUND,
+    DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_COND_TX,
+    DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_TOKEN_TICKER,
+    DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_TIMESTAMP,
+    DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_PRICE_CREATE,
+    DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_TX_CREATE
+} dap_chain_net_srv_xchange_purchase_compose_error_t;
+
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_purchase_compose(dap_hash_fast_t *a_order_hash, uint256_t a_value,
+                                       uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out, compose_config_t *a_config){
+    if (!a_config || !a_order_hash || !a_wallet || !a_hash_out) {
+        return NULL;
+    }
 
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name);
-//     if (!l_wallet_name) {
-//         printf("Error: Command 'purchase' requires parameter -w\n");
-//         return -1;
-//     }
-//     dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL);
-//     if (!l_wallet) {
-//         printf("Error: Specified wallet not found\n");
-//         return -2;
-//     }
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-order", &l_order_hash);
-//     if (!l_order_hash) {
-//         printf("Error: Command 'purchase' requires parameter -order\n");
-//         return -3;
-//     }
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value);
-//     if (!l_value) {
-//         printf("Error: Command 'purchase' requires parameter -value\n");
-//         return -4;
-//     }
-//     uint256_t l_datoshi_buy = dap_chain_balance_scan(l_value);
-//     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee);
-//     if (!l_fee) {
-//         printf("Error: Command 'purchase' requires parameter -fee\n");
-//         return -5;
-//     }
-//     uint256_t l_datoshi_fee = dap_chain_balance_scan(l_fee);
-//     dap_hash_fast_t l_tx_hash = {};
-//     dap_chain_hash_fast_from_str(l_order_hash, &l_tx_hash);
-//     char *l_str_ret_hash = NULL;
-//     int l_ret_code = dap_chain_net_srv_xchange_purchase_compose(l_net_name, &l_tx_hash, l_datoshi_buy, l_datoshi_fee,
-//                                                         l_wallet, &l_str_ret_hash);
-//     switch (l_ret_code) {
-//         case XCHANGE_PURCHASE_ERROR_OK: {
-//             printf("Exchange transaction has done\n");
-//             printf("hash: %s\n", l_str_ret_hash);
-//             DAP_DELETE(l_str_ret_hash);
-//             return 0;
-//         }
-//         case XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND: {
-//             printf("Error: Specified order not found\n");
-//             return -6;
-//         }
-//         case XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE: {
-//             printf("Error: Can't create price from order\n");
-//             return -7;
-//         }
-//         case XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX: {
-//             printf("Error: Exchange transaction error\n");
-//             return -8;
-//         }
-//         default: {
-//             printf("Error: An error occurred with an unknown code: %d.\n", l_ret_code);
-//             return -9;
-//         }
-//     }
-//     return 0;
-// }
+    dap_time_t ts_created = 0;
 
+    dap_chain_tx_out_cond_t *l_cond_tx = NULL;
+    char data[512];
+    snprintf(data, sizeof(data), 
+            "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", 
+        dap_chain_hash_fast_to_str_static(a_order_hash), a_config->net_name);
+    
+    json_object *response = dap_request_command_to_rpc(data, a_config);
+    if (!response) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE, "Failed to get response from remote node");
+        return NULL;
+    }
+    
+    const char *items_str = json_object_get_string(response);
+    json_object *l_response_array = json_object_array_get_idx(response, 0);
+    if (!l_response_array) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT, "Can't get the first element from the response array");
+        json_object_put(response);
+        return NULL;
+    }
+    json_object *items = json_object_object_get(l_response_array, "ITEMS");
+    if (!items) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_ITEMS_FOUND, "No items found in response");
+        return NULL;
+    }
+    uint32_t l_prev_cond_idx = 0;
+    int items_count = json_object_array_length(items);
+    for (int i = 0; i < items_count; i++) {
+        json_object *item = json_object_array_get_idx(items, i);
+        const char *item_type = json_object_get_string(json_object_object_get(item, "item type"));
+        if (dap_strcmp(item_type, "OUT COND") == 0) {
+            const char *subtype = json_object_get_string(json_object_object_get(item, "subtype"));
+            if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) {
+                l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t);
+                l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND;
+                l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value")));
+                l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
+                l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16);
+                l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires")));
+                strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1);
+                l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0';
+                l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate")));
+                l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size"));
+                break;
+            } 
+            l_prev_cond_idx++;
+        } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT EXT") == 0 || dap_strcmp(item_type, "OLD_OUT") == 0) {
+            l_prev_cond_idx++;
+        }
+    }
+    if (!l_cond_tx) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_COND_TX, "No transaction output condition found");
+        return NULL;
+    }
 
-// dap_chain_net_srv_xchange_purchase_error_t dap_chain_net_srv_xchange_purchase_compose(const char *a_net_name, dap_hash_fast_t *a_order_hash, uint256_t a_value,
-//                                        uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out){
-//     if (!a_net_name || !a_order_hash || !a_wallet || !a_hash_out) {
-//         return XCHANGE_PURCHASE_ERROR_INVALID_ARGUMENT;
-//     }
-//     dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(a_net->pub.ledger, a_order_hash);
-//     if (l_cond_tx) {
-//         dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(a_net, l_cond_tx, a_order_hash, &a_fee, false);
-//         if(!l_price){
-//             return XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE;
-//         }
-//         // Create conditional transaction
-//         char *l_ret = NULL;
-//         dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_exchange(l_price, a_wallet, a_value, a_fee);
-//         if (l_tx ) {
-//             l_ret = s_xchange_tx_put(l_tx, a_net);
-//         }
-//         DAP_DELETE(l_price);
-//         if (l_tx && l_ret){
-//             *a_hash_out = l_ret;
-//             return XCHANGE_PURCHASE_ERROR_OK;
-//         } else
-//             return XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX;
-//     } else {
-//         return XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND;
-//     }
-// }
+    const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker"));
+    if (!token_ticker) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_TOKEN_TICKER, "Token_ticker not found in response");
+        return NULL;
+    }
+    const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created"));
+    if (ts_created_str) {
+        ts_created = dap_time_from_str_rfc822(ts_created_str);
+    } else {
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_TIMESTAMP, "TS_Created not found in response");
+        return NULL;
+    }
+
+    dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(l_cond_tx, ts_created, token_ticker, a_order_hash, &a_fee, false, a_config);
+    if(!l_price){
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_PRICE_CREATE, "Failed to create price from order");
+        return NULL;
+    }
+    // Create conditional transaction
+    dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_exchange_compose(l_price, a_wallet, a_value, a_fee, l_cond_tx, l_prev_cond_idx, a_config);
+    DAP_DELETE(l_cond_tx);
+    if (!l_tx) {
+        dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_TX_CREATE, "Failed to create exchange transaction");
+        DAP_DELETE(l_price);
+        return NULL;
+    }
+    return l_tx;
+}
+
+
+dap_chain_datum_tx_t *dap_xchange_tx_create_exchange_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, uint256_t a_datoshi_buy,
+                                                          uint256_t a_datoshi_fee, dap_chain_tx_out_cond_t* a_cond_tx, uint32_t a_prev_cond_idx, compose_config_t *a_config)
+{
+    if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) {
+        return NULL;
+    }
+    const char *l_native_ticker = s_get_native_ticker(a_config->net_name);
+    const char *l_service_ticker = NULL;
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer, // how many coins to transfer
+              l_value_need = a_datoshi_buy,
+              l_net_fee = {},
+              l_service_fee,
+              l_total_fee = a_datoshi_fee,
+              l_fee_transfer;
+    dap_chain_addr_t *l_net_fee_addr = NULL, *l_service_fee_addr = NULL;
+    dap_list_t *l_list_fee_out = NULL;
+    bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_net_fee_addr, a_config);
+    if (l_net_fee_used)
+        SUM_256_256(l_net_fee, a_price->fee, &l_total_fee);
+    uint16_t l_service_fee_type  = 0;
+    // Doesn't implement service fee for now
+    // bool l_service_fee_used = dap_chain_net_srv_xchange_get_fee(a_price->net->pub.id, &l_service_fee, &l_service_fee_addr, &l_service_fee_type);
+    // if (l_service_fee_used) {
+    //     switch (l_service_fee_type) {
+    //     case SERIVCE_FEE_NATIVE_PERCENT:
+    //         MULT_256_COIN(l_service_fee, a_datoshi_buy, &l_service_fee);
+    //     case SERVICE_FEE_NATIVE_FIXED:
+    //         SUM_256_256(l_total_fee, l_service_fee, &l_total_fee);
+    //         l_service_ticker = l_native_ticker;
+    //         break;
+    //     case SERVICE_FEE_OWN_PERCENT:
+    //         MULT_256_COIN(l_service_fee, a_datoshi_buy, &l_service_fee);
+    //     case SERVICE_FEE_OWN_FIXED:
+    //         SUM_256_256(l_value_need, l_service_fee, &l_value_need);
+    //         l_service_ticker = a_price->token_buy;
+    //     default:
+    //         break;
+    //     }
+    // }
+
+    dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_config->net_name));
+    dap_chain_addr_t l_buyer_addr = *l_wallet_addr;
+    DAP_DELETE(l_wallet_addr);
+
+    json_object *l_outs = NULL;
+    int l_outputs_count = 0;
+    if (!dap_get_remote_wallet_outs_and_count(l_wallet_addr, a_price->token_sell, &l_outs, &l_outputs_count, a_config)) {
+        dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Not enough funds to transfer");
+        return NULL;
+    }
+
+    dap_list_t *l_list_used_out = NULL;
+    l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                            l_value_need,
+                                                            &l_value_transfer);
+    json_object_put(l_outs);
+    if (!l_list_used_out) {
+        dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Not enough funds to transfer");
+        return NULL;
+    }
+
+    bool l_pay_with_native = !dap_strcmp(a_price->token_sell, l_native_ticker);
+    bool l_buy_with_native = !dap_strcmp(a_price->token_buy, l_native_ticker);
+    if (!l_pay_with_native) {
+        if (l_buy_with_native)
+            SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+        else {
+            l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count,
+                                                                l_total_fee, 
+                                                                &l_fee_transfer);
+            if (!l_list_fee_out) {
+                dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Not enough funds to pay fee");
+                json_object_put(l_outs);
+                return NULL;
+            }
+        }
+    }
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
+    // add 'in' items to sell
+    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+    dap_list_free_full(l_list_used_out, NULL);
+    if (!EQUAL_256(l_value_to_items, l_value_transfer)) {
+        dap_list_free_full(l_list_fee_out, NULL);
+        dap_chain_datum_tx_delete(l_tx);
+        dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't compose the transaction input");
+        return NULL;
+    }
+    if (!l_pay_with_native && !l_buy_with_native) {
+        // add 'in' items to fee
+        uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+        dap_list_free_full(l_list_fee_out, NULL);
+        if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Can't compose the transaction input");
+            return NULL;
+        }
+    }
+    // add 'in' item to buy from conditional transaction
+    if (!a_cond_tx) {
+        dap_chain_datum_tx_delete(l_tx);
+        dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Requested conditional transaction not found");
+        return NULL;
+    }
+    // int l_prev_cond_idx = 0;
+    // dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(a_cond_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+    //                                                                          &l_prev_cond_idx);
+    // if (!l_tx_out_cond) {
+    //     dap_chain_datum_tx_delete(l_tx);
+    //     dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Requested transaction has no conditional output");
+    //     return NULL;
+    // }
+
+    // if (dap_ledger_tx_hash_is_used_out_item(a_config->ledger, &a_price->tx_hash, l_prev_cond_idx, NULL)) {
+    //     dap_chain_datum_tx_delete(l_tx);
+    //     dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Requested conditional transaction is already used out");
+    //     return NULL;
+    // }
+    const dap_chain_addr_t *l_seller_addr = &a_cond_tx->subtype.srv_xchange.seller_addr;
+    if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, a_prev_cond_idx, 0)) {
+        dap_chain_datum_tx_delete(l_tx);
+        dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add conditional input");
+        return NULL;
+    }
+
+    // add 'out' items
+    // transfer selling coins
+    uint256_t l_datoshi_sell,
+              l_datoshi_buy,
+              l_value_back;
+    if (!IS_ZERO_256(a_price->rate)) {
+        DIV_256_COIN(a_datoshi_buy, a_price->rate, &l_datoshi_sell);
+        if (compare256(a_cond_tx->header.value, l_datoshi_sell) < 0) {
+            l_datoshi_sell = a_cond_tx->header.value;
+            MULT_256_COIN(l_datoshi_sell, a_price->rate, &l_datoshi_buy);
+            uint256_t l_exceed = {}; // Correct requested transfer value
+            SUBTRACT_256_256(a_datoshi_buy, l_datoshi_buy, &l_exceed);
+            SUBTRACT_256_256(l_value_need, l_exceed, &l_value_need);
+        } else
+            l_datoshi_buy = a_datoshi_buy;
+        
+        uint256_t l_value_sell = l_datoshi_sell;
+        if (l_pay_with_native) {
+            if (compare256(l_datoshi_sell, l_total_fee) <= 0) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Fee is greater or equal than transfer value");
+                return NULL;
+            }
+            SUBTRACT_256_256(l_datoshi_sell, l_total_fee, &l_value_sell);
+        }
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_buyer_addr, l_value_sell, a_price->token_sell) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add selling coins output");
+            return NULL;
+        }
+    } else {
+        dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add selling coins output because price rate is 0");
+        return NULL;
+    }
+    
+    if (compare256(a_cond_tx->header.value, l_datoshi_sell) == 1) {
+        SUBTRACT_256_256(a_cond_tx->header.value, l_datoshi_sell, &l_value_back);
+        
+        dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(
+                    c_dap_chain_net_srv_xchange_uid, s_get_net_id(a_config->net_name), l_value_back,
+                    s_get_net_id(a_config->net_name), a_price->token_buy, a_price->rate,
+                    l_seller_addr, NULL, 0);
+        if (!l_tx_out) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add selling coins back conditioned output (cond cashback)");
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
+        DAP_DELETE(l_tx_out);
+    } 
 
+    // transfer buying coins
+    if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_datoshi_buy, a_price->token_buy) == -1) {
+        dap_chain_datum_tx_delete(l_tx);
+        dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add buying coins output");
+        return NULL;
+    }
+    
+    // transfer validator's fee
+    if (!IS_ZERO_256(a_datoshi_fee)) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_datoshi_fee) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add validator fee output");
+            return NULL;
+        }
+    }
+    // transfer net fee
+    if (l_net_fee_used) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add net fee output");
+            return NULL;
+        }
+    }
+    // transfer service fee
+    // if (l_service_fee_used) {
+    //     if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_service_fee_addr, l_service_fee, l_service_ticker) == -1) {
+    //         dap_chain_datum_tx_delete(l_tx);
+    //         dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add net fee output");
+    //         return NULL;
+    //     }
+    // }
+    // coin back
+    SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back);
+    if (!IS_ZERO_256(l_value_back)) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_buyer_addr, l_value_back, a_price->token_buy) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add buying coins back output");
+            return NULL;
+        }
+    }
+    // fee back
+    if (!l_pay_with_native && !l_buy_with_native) {
+        SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back);
+        if (!IS_ZERO_256(l_value_back)) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_buyer_addr, l_value_back, l_native_ticker) == -1) {
+                dap_chain_datum_tx_delete(l_tx);
+                dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add buying coins back output");
+                return NULL;
+            }
+        }
+    }
+
+    return l_tx;
+}
 
diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h
index e70baec8da..d070a12c64 100644
--- a/modules/compose/include/dap_chain_tx_compose.h
+++ b/modules/compose/include/dap_chain_tx_compose.h
@@ -140,9 +140,15 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(dap_enc_key_t *a_key,
                                                dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr,
                                                dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
                                                dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, compose_config_t *a_config);
-
-
-
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_purchase_compose(dap_hash_fast_t *a_order_hash, uint256_t a_value,
+                                       uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out, compose_config_t *a_config);
+json_object *dap_tx_create_xchange_purchase_compose (const char *a_net_name, const char *a_order_hash, const char* a_value, 
+                                                     const char* a_fee, const char *a_wallet_name, const char *a_wallet_path, 
+                                                     const char *a_url_str, uint16_t a_port);
+dap_chain_datum_tx_t* dap_chain_net_srv_xchange_purchase_compose(dap_hash_fast_t *a_order_hash, uint256_t a_value,
+                                       uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out, compose_config_t *a_config);
+dap_chain_datum_tx_t *dap_xchange_tx_create_exchange_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, uint256_t a_datoshi_buy,
+                                                          uint256_t a_datoshi_fee, dap_chain_tx_out_cond_t* a_cond_tx, uint32_t a_prev_cond_idx, compose_config_t *a_config);
 
 #ifdef __cplusplus
 }
-- 
GitLab


From 8ec224f74d43bea21eaee197050e1391ced11a03 Mon Sep 17 00:00:00 2001
From: konstantin <konstantin.kuharenko@demlabs.net>
Date: Fri, 18 Apr 2025 09:34:07 +0300
Subject: [PATCH 53/53] [*] fix purchase

---
 modules/compose/dap_chain_tx_compose.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c
index 56681e539e..44c64812f8 100644
--- a/modules/compose/dap_chain_tx_compose.c
+++ b/modules/compose/dap_chain_tx_compose.c
@@ -4653,7 +4653,7 @@ dap_chain_datum_tx_t *dap_xchange_tx_create_exchange_compose(dap_chain_net_srv_x
 
     json_object *l_outs = NULL;
     int l_outputs_count = 0;
-    if (!dap_get_remote_wallet_outs_and_count(l_wallet_addr, a_price->token_sell, &l_outs, &l_outputs_count, a_config)) {
+    if (!dap_get_remote_wallet_outs_and_count(&l_buyer_addr, a_price->token_sell, &l_outs, &l_outputs_count, a_config)) {
         dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Not enough funds to transfer");
         return NULL;
     }
-- 
GitLab