From 34c40eb43f705cff7054dc7d6d89269b1b09324f Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Sat, 13 Jan 2024 14:42:01 +0000
Subject: [PATCH] feature-10082

---
 modules/common/dap_chain_datum_tx.c           |   15 +
 modules/common/include/dap_chain_datum_tx.h   |    2 +
 .../consensus/esbocs/dap_chain_cs_esbocs.c    |   15 +
 .../esbocs/include/dap_chain_cs_esbocs.h      |    1 +
 modules/net/dap_chain_ledger.c                |    4 +-
 modules/net/dap_chain_node_cli_cmd.c          |    4 +-
 modules/net/srv/dap_chain_net_srv.c           |    2 +-
 .../dap_chain_net_srv_stake_pos_delegate.c    | 1101 ++++++++++-------
 .../xchange/dap_chain_net_srv_xchange.c       |    2 +-
 modules/type/blocks/dap_chain_cs_blocks.c     |    8 +-
 10 files changed, 685 insertions(+), 469 deletions(-)

diff --git a/modules/common/dap_chain_datum_tx.c b/modules/common/dap_chain_datum_tx.c
index 0f2310fb97..7da9de1563 100644
--- a/modules/common/dap_chain_datum_tx.c
+++ b/modules/common/dap_chain_datum_tx.c
@@ -203,6 +203,21 @@ int dap_chain_datum_tx_get_fee_value(dap_chain_datum_tx_t *a_tx, uint256_t *a_va
     return l_ret;
 }
 
+dap_sign_t *dap_chain_datum_tx_get_sign(dap_chain_datum_tx_t *a_tx, int a_sign_num)
+{
+    dap_return_val_if_fail(a_tx, NULL);
+    if (!a_sign_num) {
+        dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_SIG, NULL);
+        return dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
+    }
+    dap_list_t *l_items_list = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_SIG, NULL);
+    if (dap_list_length(l_items_list) <= (uint64_t)a_sign_num)
+        return NULL;
+    dap_sign_t *l_ret = dap_list_nth_data(l_items_list, a_sign_num);
+    dap_list_free(l_items_list);
+    return l_ret;
+}
+
 /**
  * Create 'out' item and insert to transaction
  *
diff --git a/modules/common/include/dap_chain_datum_tx.h b/modules/common/include/dap_chain_datum_tx.h
index f2cc1c7e4e..33d37f5142 100644
--- a/modules/common/include/dap_chain_datum_tx.h
+++ b/modules/common/include/dap_chain_datum_tx.h
@@ -144,6 +144,8 @@ int dap_chain_datum_tx_add_out_cond_item(dap_chain_datum_tx_t **a_tx, dap_pkey_t
  */
 int dap_chain_datum_tx_add_sign_item(dap_chain_datum_tx_t **a_tx, dap_enc_key_t *a_key);
 
+dap_sign_t *dap_chain_datum_tx_get_sign(dap_chain_datum_tx_t *a_tx, int a_sign_num);
+
 /**
  * Verify all sign item in transaction
  *
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index b7e065545b..5ce9425bc6 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -397,6 +397,21 @@ static void s_new_atom_notifier(void *a_arg, dap_chain_t *a_chain, dap_chain_cel
     }
 }
 
+bool dap_chain_esbocs_get_autocollect_status(dap_chain_net_id_t a_net_id)
+{
+    dap_chain_esbocs_session_t *l_session;
+    DL_FOREACH(s_session_items, l_session) {
+        if (l_session->chain->net_id.uint64 == a_net_id.uint64) {
+            if (l_session->esbocs && l_session->esbocs->_pvt &&
+                    !dap_chain_addr_is_blank(PVT(l_session->esbocs)->collecting_addr))
+                return true;
+            else
+                return false;
+        }
+    }
+    return false;
+}
+
 static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cfg)
 {
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
diff --git a/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h b/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
index 0f9d9a5544..914c430414 100644
--- a/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
+++ b/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
@@ -214,3 +214,4 @@ void dap_chain_esbocs_stop_timer(dap_chain_net_id_t a_net_id);
 void dap_chain_esbocs_start_timer(dap_chain_net_id_t a_net_id);
 dap_pkey_t *dap_chain_esbocs_get_sign_pkey(dap_chain_net_id_t a_net_id);
 uint256_t dap_chain_esbocs_get_fee(dap_chain_net_id_t a_net_id);
+bool dap_chain_esbocs_get_autocollect_status(dap_chain_net_id_t a_net_id);
diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c
index 5b73b08c88..f6d78a3b01 100644
--- a/modules/net/dap_chain_ledger.c
+++ b/modules/net/dap_chain_ledger.c
@@ -3360,7 +3360,7 @@ bool s_tx_match_sign(dap_chain_datum_token_emission_t *a_datum_emission, dap_cha
             // Get sign from sign item
             dap_sign_t *l_tx_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t*) l_tx_sig);
             // Compare signs
-            if(dap_sign_match_pkey_signs(l_emission_sign, l_tx_sign)) {
+            if(dap_sign_compare_pkeys(l_emission_sign, l_tx_sign)) {
                 dap_list_free(l_list_sig);
                 return true;
             }
@@ -3920,7 +3920,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx
                 dap_chain_tx_out_cond_t *l_tx_prev_out_cond = NULL;
                 l_tx_prev_out_cond = (dap_chain_tx_out_cond_t *)l_tx_prev_out;
                 bool l_owner = false;
-                l_owner = dap_sign_match_pkey_signs(l_prev_sign, l_sign);
+                l_owner = dap_sign_compare_pkeys(l_prev_sign, l_sign);
 
                 // 5b. Call verificator for conditional output
                 dap_ledger_verificator_t *l_verificator;
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 130757998c..a247fed056 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -3196,8 +3196,8 @@ void s_com_mempool_list_print_for_chain(dap_chain_net_t * a_net, dap_chain_t * a
     dap_global_db_objs_delete(l_objs, l_objs_count);
     json_object_object_add(l_obj_chain, "datums", l_jobj_datums);
     
-    char * l_net_chain_count_total[64] = {0};
-    sprintf(l_net_chain_count_total, "%s.%s: %d", a_net->pub.name, a_chain->name, l_objs_count);
+    char l_net_chain_count_total[64] = {0};
+    sprintf(l_net_chain_count_total, "%s.%s: %zu", a_net->pub.name, a_chain->name, l_objs_count);
     json_object * l_object_total = json_object_new_string(l_net_chain_count_total);
     if (!l_object_total) {
         json_object_put(l_obj_chain);
diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c
index 37da291861..a8b7d359f6 100644
--- a/modules/net/srv/dap_chain_net_srv.c
+++ b/modules/net/srv/dap_chain_net_srv.c
@@ -687,7 +687,7 @@ static bool s_fee_verificator_callback(dap_ledger_t *a_ledger, dap_chain_tx_out_
         // TX sign is already verified, just compare pkeys
         dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(a_tx_in, NULL, TX_ITEM_TYPE_SIG, NULL);
         dap_sign_t *l_sign_tx = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
-        return dap_sign_match_pkey_signs(l_sign_block, l_sign_tx);
+        return dap_sign_compare_pkeys(l_sign_block, l_sign_tx);
     }
     return false;
 }
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 9abdc13bc7..b2eecedb98 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
@@ -71,7 +71,7 @@ int dap_chain_net_srv_stake_pos_delegate_init()
     "srv_stake order create validator -net <net_name> -value_min <minimum_stake_value> -value_max <maximum_stake_value>"
                         " -tax <percent> -cert <priv_cert_name> [-H {hex(default) | base58}]\n"
         "\tCreates an order declaring wanted tax and minimum/maximum stake value that the validator agrees to work.\n"
-    "srv_stake order create staker -net <net_name> -w <wallet_wtih_m_tokens> -value <stake_value> -tax <percent>"
+    "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 <priv_cert_name>] [-H {hex(default) | base58}]\n"
         "\tCreates an order allowing the validator to delegate it's key with specified params\n"
     "srv_stake order update -net <net_name> -order <order_hash> [-params]\n"
@@ -156,22 +156,61 @@ void dap_chain_net_srv_stake_pos_delegate_deinit()
     DAP_DEL_Z(s_srv_stake);
 }
 
-static bool s_stake_verificator_callback(dap_ledger_t UNUSED_ARG *a_ledger, dap_chain_tx_out_cond_t UNUSED_ARG *a_cond,
+static bool s_stake_verificator_callback(dap_ledger_t UNUSED_ARG *a_ledger, dap_chain_tx_out_cond_t *a_cond,
                                          dap_chain_datum_tx_t *a_tx_in, bool a_owner)
 {
     assert(s_srv_stake);
-    if (!a_owner)
-        return false;
-    if (a_tx_in->header.ts_created < 1705104000) // Jan 13 2024 00:00:00 GMT
+    // It's a order conditional TX
+    if (dap_chain_addr_is_blank(&a_cond->subtype.srv_stake_pos_delegate.signing_addr) ||
+            a_cond->subtype.srv_stake_pos_delegate.signer_node_addr.uint64 == 0) {
+        if (a_owner)
+            return true;
+        int l_out_idx = 0;
+        dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(a_tx_in, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_idx);
+        if (!l_tx_out_cond)
+            return false;
+        if (compare256(l_tx_out_cond->header.value, a_cond->header.value))
+            return false;
+        if (l_tx_out_cond->tsd_size != a_cond->tsd_size ||
+                memcmp(l_tx_out_cond->tsd, a_cond->tsd, a_cond->tsd_size))
+            return false;
+        if (dap_chain_addr_is_blank(&l_tx_out_cond->subtype.srv_stake_pos_delegate.signing_addr) ||
+                l_tx_out_cond->subtype.srv_stake_pos_delegate.signer_node_addr.uint64 == 0)
+            return false;
         return true;
+    }
+    // It's a delegation conitional TX
     dap_chain_tx_in_cond_t *l_tx_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(a_tx_in, 0, TX_ITEM_TYPE_IN_COND, 0);
     if (!l_tx_in_cond)
         return false;
-    if (dap_hash_fast_is_blank(&l_tx_in_cond->header.tx_prev_hash))
+    dap_hash_fast_t *l_prev_hash = &l_tx_in_cond->header.tx_prev_hash;
+    if (dap_hash_fast_is_blank(l_prev_hash))
+        return false;
+    dap_chain_datum_tx_t *l_prev_tx = dap_ledger_tx_find_by_hash(a_ledger, l_prev_hash);
+    if (!l_prev_tx)
         return false;
+    bool l_owner = false;
+    dap_chain_tx_in_cond_t *l_tx_prev_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(l_prev_tx, 0, TX_ITEM_TYPE_IN_COND, 0);
+    if (!l_tx_prev_in_cond)
+        l_owner = a_owner;
+    else {
+        dap_hash_fast_t *l_owner_tx_hash = &l_tx_prev_in_cond->header.tx_prev_hash;
+        dap_chain_datum_tx_t *l_owner_tx = dap_ledger_tx_find_by_hash(a_ledger, l_owner_tx_hash);
+        dap_sign_t *l_owner_sign = dap_chain_datum_tx_get_sign(l_owner_tx, 0);
+        if (!l_owner_sign)
+            return false;
+        dap_sign_t *l_taker_sign = dap_chain_datum_tx_get_sign(a_tx_in, 0);
+        if (!l_taker_sign)
+            return false;
+        l_owner = dap_sign_compare_pkeys(l_taker_sign, l_owner_sign);
+    }
+    if (!l_owner)
+        return false;
+    if (a_tx_in->header.ts_created < 1705104000) // Jan 13 2024 00:00:00 GMT, old policy rules
+        return true;
     dap_chain_net_srv_stake_item_t *l_stake;
-    HASH_FIND(hh, s_srv_stake->tx_itemlist, &l_tx_in_cond->header.tx_prev_hash, sizeof(dap_hash_t), l_stake);
-    if (l_stake)
+    HASH_FIND(hh, s_srv_stake->tx_itemlist, l_prev_hash, sizeof(dap_hash_t), l_stake);
+    if (l_stake)                                // Key is active with delegation decree, need to revoke it first
         return false;
     return true;
 }
@@ -227,7 +266,7 @@ void dap_chain_net_srv_stake_key_delegate(dap_chain_net_t *a_net, dap_chain_addr
         dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_net->pub.ledger, a_stake_tx_hash);
         if (l_tx) {
             dap_chain_tx_out_cond_t *l_cond = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, NULL);
-            if (l_cond && l_cond->tsd_size) {
+            if (l_cond && l_cond->tsd_size == sizeof(dap_chain_addr_t) + sizeof(uint256_t) + sizeof(dap_tsd_t) * 2) {
                 dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR);
                 l_stake->sovereign_addr = dap_tsd_get_scalar(l_tsd, dap_chain_addr_t);
                 l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE);
@@ -329,7 +368,12 @@ int dap_chain_net_srv_stake_verify_key_and_node(dap_chain_addr_t *a_signing_addr
         log_it(L_WARNING, "Bad srv_stake_verify arguments");
         return -100;
     }
-return 0; //TODO rmv
+
+    if (dap_chain_addr_is_blank(a_signing_addr) || a_node_addr->uint64 == 0) {
+        log_it(L_WARNING, "Trying to approve bad delegating TX. Node or key addr is blank");
+        return -103;
+    }
+
     dap_chain_net_srv_stake_item_t *l_stake = NULL, *l_tmp = NULL;
     HASH_ITER(hh, s_srv_stake->itemlist, l_stake, l_tmp){
         //check key not activated for other node
@@ -414,58 +458,68 @@ void dap_chain_net_srv_stake_purge(dap_chain_net_t *a_net)
 
 
 // Freeze staker's funds when delegating a key
-static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_t * a_net, dap_chain_wallet_t *a_wallet,
+static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_t * a_net, 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_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax,
+                                               dap_chain_datum_tx_t *a_prev_tx)
 {
-    if (!a_net || !a_wallet || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr)
+    if (!a_net || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr)
         return NULL;
 
-
-
     const char *l_native_ticker = a_net->pub.native_ticker;
     char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
     dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker);
     dap_ledger_t *l_ledger = dap_ledger_by_net_name(a_net->pub.name);
     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_t *)dap_chain_wallet_get_addr(a_wallet, a_net->pub.id);
+    dap_chain_addr_t l_owner_addr;
+    dap_chain_addr_fill_from_key(&l_owner_addr, a_key, a_net->pub.id);
     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_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)");
-        DAP_DELETE(l_owner_addr);
-        return NULL;
-    }
     dap_list_t *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_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)");
-        DAP_DELETE(l_owner_addr);
         return NULL;
     }
 
     // create empty transaction
     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
-    // 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;
+    if (!a_prev_tx) {
+        dap_list_t *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)");
+            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");
+            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 (dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_out_num, -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 transaction input");
+        log_it(L_ERROR, "Can't compose the fee transaction input");
         goto tx_fail;
     }
 
@@ -479,53 +533,51 @@ static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_t * a_net, dap_chai
     }
     dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
     DAP_DELETE(l_tx_out);
-    // 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;
+    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) {
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
+            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) {
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
+            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) {
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
+        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
-    dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(a_wallet, 0);
-    if(dap_chain_datum_tx_add_sign_item(&l_tx, l_enc_key) != 1) {
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) {
         log_it(L_ERROR, "Can't add sign output");
-        dap_enc_key_delete(l_enc_key);
         goto tx_fail;
     }
-    dap_enc_key_delete(l_enc_key);
-    DAP_DELETE(l_owner_addr);
+
     return l_tx;
 
 tx_fail:
     dap_chain_datum_tx_delete(l_tx);
-    DAP_DELETE(l_owner_addr);
     return NULL;
 }
 
@@ -533,20 +585,26 @@ static dap_chain_datum_tx_t *s_order_tx_create(dap_chain_net_t * a_net, dap_enc_
                                                uint256_t a_value, uint256_t a_fee,
                                                 uint256_t a_sovereign_tax, dap_chain_addr_t *a_sovereign_addr)
 {
-    return NULL;
+    dap_chain_node_addr_t l_node_addr = {};
+    return s_stake_tx_create(a_net, 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);
 }
 
 // Put the transaction to mempool
-static char *s_stake_tx_put(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_net)
+static char *s_stake_tx_put(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_net, const char *a_hash_out_type)
 {
+    dap_chain_t *l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX);
+    if (!l_chain)
+        return NULL;
     size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
     dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, a_tx, l_tx_size);
-    dap_chain_t *l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX);
-    if (!l_chain) {
+    if (!l_datum) {
+        log_it(L_CRITICAL, "Not enough memory");
         return NULL;
     }
     // Processing will be made according to autoprocess policy
-    char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, "hex");
+    char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, a_hash_out_type);
     DAP_DELETE(l_datum);
     return l_ret;
 }
@@ -737,7 +795,7 @@ static dap_chain_datum_tx_t *s_stake_tx_invalidate(dap_chain_net_t *a_net, dap_h
     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) {
-        log_it(L_WARNING, "Requested conditional transaction has no requires conditional output");
+        log_it(L_WARNING, "Requested conditional transaction requires conditional output");
         return NULL;
     }
     dap_hash_fast_t l_spender_hash = { };
@@ -747,6 +805,14 @@ static dap_chain_datum_tx_t *s_stake_tx_invalidate(dap_chain_net_t *a_net, dap_h
         log_it(L_WARNING, "Requested conditional transaction is already used out by %s", 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, 0, TX_ITEM_TYPE_IN_COND, 0);
+    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) {
+            log_it(L_ERROR, "Requested conditional transaction is unchained");
+            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,
             TX_ITEM_TYPE_SIG, NULL);
@@ -1026,7 +1092,7 @@ char *s_fee_order_create(dap_chain_net_t *a_net, uint256_t *a_fee, dap_enc_key_t
 }
 
 struct validator_odrer_ext {
-    uint256_t value_min;
+    uint256_t tax;
     uint256_t value_max;
 } DAP_ALIGN_PACKED;
 
@@ -1035,12 +1101,13 @@ char *s_validator_order_create(dap_chain_net_t *a_net, uint256_t a_value_min, ui
 {
     dap_chain_hash_fast_t l_tx_hash = {};
     dap_chain_net_srv_order_direction_t l_dir = SERV_DIR_SELL;
-    const char *l_native_ticker = a_net->pub.native_ticker;
+    char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+    dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, a_net->pub.native_ticker);
     dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 =  SERV_UNIT_PCS};
     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ORDERS };
-    struct validator_odrer_ext l_order_ext = { a_value_min, a_value_max };
+    struct validator_odrer_ext l_order_ext = { a_tax, a_value_max };
     dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_compose(a_net, l_dir, l_uid, g_node_addr,
-                                                            l_tx_hash, &a_tax, l_unit, l_native_ticker, 0,
+                                                            l_tx_hash, &a_value_min, l_unit, l_delegated_ticker, 0,
                                                             (const uint8_t *)&l_order_ext, sizeof(l_order_ext),
                                                             1, NULL, 0, a_key);
     if (!l_order)
@@ -1055,21 +1122,16 @@ char *s_validator_order_create(dap_chain_net_t *a_net, uint256_t a_value_min, ui
     return l_order_hash_str;
 }
 
-char *s_staker_order_create(dap_chain_net_t *a_net, uint256_t a_value, uint256_t a_tax, dap_hash_fast_t *a_tx_hash,
-                            dap_chain_addr_t *a_addr, dap_enc_key_t *a_key, const char *a_hash_out_type)
+char *s_staker_order_create(dap_chain_net_t *a_net, uint256_t a_value, dap_hash_fast_t *a_tx_hash, dap_enc_key_t *a_key, const char *a_hash_out_type)
 {
     dap_chain_net_srv_order_direction_t l_dir = SERV_DIR_BUY;
-    const char *l_native_ticker = a_net->pub.native_ticker;
+    char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+    dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, a_net->pub.native_ticker);
     dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 =  SERV_UNIT_PCS};
     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ORDERS };
-    struct odrer_ext {
-        uint256_t value;
-        dap_chain_addr_t addr;
-    } DAP_ALIGN_PACKED l_order_ext = { a_value, *a_addr };
     dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_compose(a_net, l_dir, l_uid, g_node_addr,
-                                                            *a_tx_hash, &a_tax, l_unit, l_native_ticker, 0,
-                                                             (const uint8_t *)&l_order_ext, sizeof(l_order_ext),
-                                                             1, NULL, 0, a_key);
+                                                            *a_tx_hash, &a_value, l_unit, l_delegated_ticker, 0,
+                                                            NULL, 0, 1, NULL, 0, a_key);
     if (!l_order)
         return NULL;
     char *l_order_hash_str = dap_chain_net_srv_order_save(a_net, l_order, true);
@@ -1198,6 +1260,13 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, voi
             dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't load cert %s", l_cert_str);
             return -8;
         }
+        dap_chain_addr_t l_signing_addr;
+        dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, l_net->pub.id);
+        int l_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &g_node_addr);
+        if (l_result) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Key and node verification error");
+            return l_result;
+        }
         // Create the order & put it in GDB
         char *l_order_hash_str = s_validator_order_create(l_net, l_value_min, l_value_max, l_tax, l_cert->enc_key, a_hash_out_type);
         if (l_order_hash_str) {
@@ -1275,14 +1344,15 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, voi
         dap_chain_wallet_close(l_wallet);
         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))) {
+        if (!l_tx || !(l_tx_hash_str = s_stake_tx_put(l_tx, l_net, a_hash_out_type))) {
             dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't compose transaction for order, examine log files for details");
             DAP_DEL_Z(l_tx);
             return -21;
-        }*/ // TODO - make conditional transaction with specified params
+        }
+        DAP_DELETE(l_tx);
         // Create the order & put it in GDB
         dap_hash_fast_t l_tx_hash = {};
-        dap_chain_hash_fast_from_hex_str(l_tx_hash_str, &l_tx_hash);
+        dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash);
         char *l_cert_str = NULL, *l_default_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)
@@ -1291,17 +1361,19 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, voi
         if (!l_cert) {
             dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't load cert %s", l_cert_str);
             DAP_DEL_Z(l_default_cert_str);
+            DAP_DELETE(l_tx_hash_str);
             return -8;
         }
         DAP_DEL_Z(l_default_cert_str);
-        char *l_order_hash_str = s_staker_order_create(l_net, l_value, l_tax, &l_tx_hash, &l_addr, l_cert->enc_key, a_hash_out_type);
-        if (l_order_hash_str) {
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "%sSuccessfully created order %s", l_sign_str, l_order_hash_str);
-            DAP_DELETE(l_order_hash_str);
-        } else {
+        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) {
             dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't compose the order");
+            DAP_DELETE(l_tx_hash_str);
             return -9;
         }
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "%sSuccessfully created order %s\nSAVE TO TAKE ===>>> Order tx hash = %s", l_sign_str, l_order_hash_str, l_tx_hash_str);
+        DAP_DELETE(l_order_hash_str);
+        DAP_DELETE(l_tx_hash_str);
     } break;
 
     case CMD_REMOVE:
@@ -1422,6 +1494,468 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, voi
     return 0;
 }
 
+static int s_cli_srv_stake_delegate(int a_argc, char **a_argv, int a_arg_index, void **a_str_reply, const char *a_hash_out_type)
+{
+    const char *l_net_str = NULL,
+               *l_wallet_str = NULL,
+               *l_cert_str = NULL,
+               *l_value_str = NULL,
+               *l_fee_str = NULL,
+               *l_node_addr_str = NULL,
+               *l_order_hash_str = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-net", &l_net_str);
+    if (!l_net_str) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -net");
+        return -3;
+    }
+    dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
+    if (!l_net) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
+        return -4;
+    }
+    dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-w", &l_wallet_str);
+    if (!l_wallet_str) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -w");
+        return -17;
+    }
+    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));
+    if (!l_wallet) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified wallet not found");
+        return -18;
+    } 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);
+    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, a_arg_index, a_argc, "-cert", &l_cert_str);
+    dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-order", &l_order_hash_str);
+    if (!l_cert_str && !l_order_hash_str) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -cert and/or -order");
+        dap_enc_key_delete(l_enc_key);
+        return -13;
+    }
+    dap_chain_node_addr_t l_node_addr = { .uint64 = 0 };
+    uint256_t l_value = uint256_0;
+    dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-value", &l_value_str);
+    if (!l_value_str) {
+        if (!l_order_hash_str) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -value");
+            dap_enc_key_delete(l_enc_key);
+            return -9;
+        }
+    } else {
+        l_value = dap_chain_balance_scan(l_value_str);
+        if (IS_ZERO_256(l_value)) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized number in '-value' param");
+            dap_enc_key_delete(l_enc_key);
+            return -10;
+        }
+    }
+    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) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate not found");
+            dap_enc_key_delete(l_enc_key);
+            return -19;
+        }
+        if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, l_net->pub.id)) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is wrong");
+            dap_enc_key_delete(l_enc_key);
+            return -20;
+        }
+        dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-node_addr", &l_node_addr_str);
+        if (l_node_addr_str) {
+            if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized node addr %s", l_node_addr_str);
+                dap_enc_key_delete(l_enc_key);
+                return -14;
+            }
+        } else
+            l_node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
+    }
+    if (l_order_hash_str) {
+        dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str);
+        if (!l_order) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found");
+            dap_enc_key_delete(l_enc_key);
+            return -25;
+        }
+        if (l_order->direction == SERV_DIR_BUY) { // Staker order
+            if (!l_cert_str) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -cert with this order type");
+                dap_enc_key_delete(l_enc_key);
+                return -22;
+            }
+            if (l_order->ext_size != 0) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order has invalid size");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -26;
+            }
+            l_prev_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash);
+            if (l_prev_tx) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "The order's conditional transaction not found in ledger");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -30;
+            }
+            int l_out_num = 0;
+            dap_chain_tx_out_cond_t *l_cond = 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) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "The order's conditional transaction has invalid type");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -31;
+            }
+            if (dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_order->tx_cond_hash, l_out_num, NULL)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "The order's conditional transaction is already spent");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -32;
+            }
+            char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+            dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_net->pub.native_ticker);
+            const char *l_tx_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash);
+            if (dap_strcmp(l_tx_ticker, l_delegated_ticker)) {
+                log_it(L_WARNING, "Requested conditional transaction have another ticker (not %s)", l_delegated_ticker);
+                return -38;
+            }
+            if (l_cond->tsd_size != sizeof(dap_chain_addr_t) + sizeof(uint256_t) + sizeof(dap_tsd_t) * 2) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "The order's conditional transaction has invalid format");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -33;
+            }
+            if (compare256(l_cond->header.value, l_order->price)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "The order's conditional transaction has different value");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -34;
+            }
+            if (!dap_chain_addr_is_blank(&l_cond->subtype.srv_stake_pos_delegate.signing_addr) ||
+                    l_cond->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "The order's conditional transaction gas not blank address or key");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -35;
+            }
+            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_sovereign_addr = dap_tsd_get_scalar(l_tsd, dap_chain_addr_t);
+            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);
+        } else {
+            if (!l_value_str) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -value with this order type");
+                dap_enc_key_delete(l_enc_key);
+                return -23;
+            }
+            const char *l_sovereign_addr_str = NULL;
+            dap_cli_server_cmd_find_option_val(a_argv, a_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) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified address is ivalid");
+                    return -24;
+                }
+                l_sovereign_addr = *l_spec_addr;
+                DAP_DELETE(l_spec_addr);
+            } else
+                dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, l_net->pub.id);
+
+            if (l_order->ext_size != sizeof(struct validator_odrer_ext)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order has invalid size");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -26;
+            }
+            struct validator_odrer_ext *l_ext = (struct validator_odrer_ext *)l_order->ext_n_sign;
+            l_sovereign_tax = l_ext->tax;
+            if (l_order_hash_str && compare256(l_value, l_order->price) == -1) {
+                char *l_coin_str = dap_chain_balance_to_coins(l_value);
+                char *l_value_min_str = dap_chain_balance_print(l_order->price);
+                char *l_coin_min_str = dap_chain_balance_to_coins(l_order->price);
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Number in '-value' param %s(%s) is lower than order minimum allowed value %s(%s)",
+                                                  l_coin_str, l_value_str, l_coin_min_str, l_value_min_str);
+                DAP_DELETE(l_coin_str);
+                DAP_DELETE(l_value_min_str);
+                DAP_DELETE(l_coin_min_str);
+                dap_enc_key_delete(l_enc_key);
+                return -13;
+            }
+            if (l_order_hash_str && compare256(l_value, l_ext->value_max) == 1) {
+                char *l_coin_str = dap_chain_balance_to_coins(l_value);
+                char *l_value_max_str = dap_chain_balance_print(l_ext->value_max);
+                char *l_coin_max_str = dap_chain_balance_to_coins(l_ext->value_max);
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Number in '-value' param %s(%s) is higher than order minimum allowed value %s(%s)",
+                                                  l_coin_str, l_value_str, l_coin_max_str, l_value_max_str);
+                DAP_DELETE(l_coin_str);
+                DAP_DELETE(l_value_max_str);
+                DAP_DELETE(l_coin_max_str);
+                dap_enc_key_delete(l_enc_key);
+                return -14;
+            }
+            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) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order is unsigned");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -27;
+            }
+            dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_net->pub.id);
+            if (dap_strcmp(l_order->price_ticker, l_net->pub.native_ticker)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order is invalid");
+                dap_enc_key_delete(l_enc_key);
+                DAP_DELETE(l_order);
+                return -28;
+            }
+            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_cli_server_cmd_set_reply_text(a_str_reply, "Tax must be lower or eqal than 100%% and higher or eqal than 1.0e-16%%");
+            dap_enc_key_delete(l_enc_key);
+            return -29;
+        }
+        DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
+    }
+    if (dap_chain_net_srv_stake_key_delegated(&l_signing_addr)) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is already delegated");
+        dap_enc_key_delete(l_enc_key);
+        return -21;
+    }
+
+    if (compare256(l_value, s_srv_stake->delegate_allowed_min) == -1) {
+        char *l_coin_str = dap_chain_balance_to_coins(l_value);
+        char *l_value_min_str = dap_chain_balance_print(s_srv_stake->delegate_allowed_min);
+        char *l_coin_min_str = dap_chain_balance_to_coins(s_srv_stake->delegate_allowed_min);
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Number in '-value' param %s(%s) is lower than minimum allowed value %s(%s)",
+                                          l_coin_str, l_value_str, l_coin_min_str, l_value_min_str);
+        DAP_DELETE(l_coin_str);
+        DAP_DELETE(l_value_min_str);
+        DAP_DELETE(l_coin_min_str);
+        dap_enc_key_delete(l_enc_key);
+        return -11;
+    }
+
+    dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-fee", &l_fee_str);
+    if (!l_fee_str) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -fee");
+        dap_enc_key_delete(l_enc_key);
+        return -15;
+    }
+    uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+    if (IS_ZERO_256(l_fee)) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized number in '-fee' param");
+        dap_enc_key_delete(l_enc_key);
+        return -16;
+    }
+    int ret_val = 0;
+    if((ret_val = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr)) != 0){
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Key and node verification error");
+        dap_enc_key_delete(l_enc_key);
+        return ret_val;
+    }
+
+    // Create conditional transaction
+    dap_chain_datum_tx_t *l_tx = s_stake_tx_create(l_net, 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);
+    dap_enc_key_delete(l_enc_key);
+    char *l_tx_hash_str;
+    if (!l_tx || !(l_tx_hash_str = s_stake_tx_put(l_tx, l_net, a_hash_out_type))) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Stake transaction error");
+        DAP_DEL_Z(l_tx);
+        return -12;
+    }
+    DAP_DELETE(l_tx);
+    const char *c_save_to_take = l_prev_tx ? "" : "SAVE TO TAKE ===>>> ";
+    dap_cli_server_cmd_set_reply_text(a_str_reply, "%s%sStake transaction %s has done", l_sign_str, c_save_to_take, l_tx_hash_str);
+    DAP_DELETE(l_tx_hash_str);
+    return 0;
+}
+
+static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv, int a_arg_index, void **a_str_reply, const char *a_hash_out_type)
+{
+    const char *l_net_str = NULL,
+               *l_wallet_str = NULL,
+               *l_fee_str = NULL,
+               *l_tx_hash_str = NULL,
+               *l_cert_str = NULL,
+               *l_poa_cert_str = NULL,
+               *l_signing_pkey_hash_str = NULL,
+               *l_signing_pkey_type_str = NULL;
+    dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-net", &l_net_str);
+    if (!l_net_str) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'invalidate' requires parameter -net");
+        return -3;
+    }
+    dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
+    if (!l_net) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
+        return -4;
+    }
+    uint256_t l_fee = {};
+    dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-w", &l_wallet_str);
+    if (!l_wallet_str) {
+        dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-poa_cert", &l_poa_cert_str);
+        if (!l_poa_cert_str) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'invalidate' requires parameter -w or -poa_cert");
+            return -17;
+        }
+    } else {
+        dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-fee", &l_fee_str);
+        if (!l_fee_str) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -fee");
+            return -5;
+        }
+        l_fee = dap_chain_balance_scan(l_fee_str);
+        if (IS_ZERO_256(l_fee)) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized number in '-fee' param");
+            return -6;
+        }
+    }
+    dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-tx", &l_tx_hash_str);
+    if (!l_tx_hash_str) {
+        dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-cert", &l_cert_str);
+        if (!l_cert_str) {
+            dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-signing_pkey_hash", &l_signing_pkey_hash_str);
+            if (!l_signing_pkey_hash_str) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'invalidate' requires parameter -tx or -cert or -signing_pkey_hash");
+                return -13;
+            }
+            dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-signing_pkey_type", &l_signing_pkey_type_str);
+            if (!l_signing_pkey_type_str) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'invalidate' requires parameter -signing_pkey_type");
+                return -14;
+            }
+            if (dap_sign_type_from_str(l_signing_pkey_type_str).type == SIG_TYPE_NULL) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Invalid signing_pkey_type %s", l_signing_pkey_type_str);
+                return -15;
+            }
+        }
+    }
+
+    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);
+        dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_tx_hash);
+        if (!l_tx) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Transaction %s is not found", l_tx_hash_str);
+            return -21;
+        }
+        int l_out_num = 0;
+        if (!dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num)) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Transaction %s is invalid", l_tx_hash_str);
+            return -22;
+        }
+        dap_hash_fast_t l_spender_hash = {};
+        if (dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_tx_hash, l_out_num, &l_spender_hash)) {
+            l_tx_hash = l_spender_hash;
+            if (!dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_tx_hash)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Previous transaction %s is not found", l_tx_hash_str);
+                return -21;
+            }
+        }
+        dap_chain_net_srv_stake_item_t *l_stake;
+        HASH_FIND(hh, s_srv_stake->tx_itemlist, &l_tx_hash, sizeof(dap_hash_t), l_stake);
+        if (l_stake) {
+            char *l_delegated_hash_str = dap_hash_fast_is_blank(&l_spender_hash) ? dap_strdup(l_tx_hash_str)
+                                                                                 : dap_hash_fast_to_str_new(&l_spender_hash);
+            char l_pkey_hash_str[DAP_HASH_FAST_STR_SIZE];
+            dap_hash_fast_to_str(&l_stake->signing_addr.data.hash_fast, l_pkey_hash_str, DAP_HASH_FAST_STR_SIZE);
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Transaction %s has active delegated key %s, need to revoke it first",
+                                              l_delegated_hash_str, l_pkey_hash_str);
+            DAP_DELETE(l_delegated_hash_str);
+            return -30;
+        }
+    } 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) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate not found");
+                return -18;
+            }
+            if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, l_net->pub.id)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is wrong");
+                return -22;
+            }
+        } else {
+            dap_hash_fast_t l_pkey_hash = {};
+            if (dap_chain_hash_fast_from_str(l_signing_pkey_hash_str, &l_pkey_hash)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Invalid pkey hash format");
+                return -23;
+            }
+            dap_chain_addr_fill(&l_signing_addr, dap_sign_type_from_str(l_signing_pkey_type_str), &l_pkey_hash, l_net->pub.id);
+        }
+        dap_chain_net_srv_stake_item_t *l_stake;
+        HASH_FIND(hh, s_srv_stake->itemlist, &l_signing_addr, sizeof(dap_chain_addr_t), l_stake);
+        if (!l_stake) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate/pkey hash is not delegated nor this delegating is approved."
+                                                           " Try to invalidate with tx hash instead");
+            return -24;
+        }
+        l_tx_hash = l_stake->tx_hash;
+    }
+    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));
+        if (!l_wallet) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified wallet not found");
+            return -18;
+        } 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);
+        dap_chain_datum_tx_t *l_tx = s_stake_tx_invalidate(l_net, &l_tx_hash, l_fee, l_enc_key);
+        dap_chain_wallet_close(l_wallet);
+        dap_enc_key_delete(l_enc_key);
+        char *l_out_hash_str = NULL;
+        if (l_tx && (l_out_hash_str = s_stake_tx_put(l_tx, l_net, a_hash_out_type))) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "%sAll m-tokens successfully returned to "
+                                                           "owner. Returning tx hash %s.", l_sign_str, l_out_hash_str);
+            DAP_DELETE(l_out_hash_str);
+            DAP_DELETE(l_tx);
+        } else {
+            l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_tx_hash);
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't invalidate transaction %s, examine log files for details", l_tx_hash_str);
+            DAP_DELETE(l_tx_hash_str);
+            DAP_DEL_Z(l_tx);
+            return -21;
+        }
+    } else {
+        dap_cert_t *l_poa_cert = dap_cert_find_by_name(l_poa_cert_str);
+        if (!l_poa_cert) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate not found");
+            return -25;
+        }
+        if (!s_srv_stake_is_poa_cert(l_net, l_poa_cert->enc_key)) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is not PoA root one");
+            return -26;
+        }
+        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))) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified delegated key invalidated. "
+                                                           "Created key invalidation decree %s."
+                                                           "Try to execute this command with -w to return m-tokens to owner", l_decree_hash_str);
+            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_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't invalidate transaction %s, examine log files for details", l_tx_hash_str);
+            DAP_DEL_Z(l_decree);
+            return -21;
+        }
+    }
+    return 0;
+}
+
 DAP_STATIC_INLINE bool s_chain_esbocs_started(dap_chain_net_t *a_net)
 {
     dap_chain_t *l_chain;
@@ -1487,22 +2021,21 @@ static void s_get_tx_filter_callback(dap_chain_net_t* a_net, dap_chain_datum_tx_
 {
     struct get_tx_cond_pos_del_from_tx * l_args = (struct get_tx_cond_pos_del_from_tx* ) a_arg;
     int l_out_idx_tmp = 0;
-    dap_chain_tx_out_cond_t *l_tx_out_cond = NULL;
+    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE,
+                                                                             &l_out_idx_tmp);
+    if (!l_tx_out_cond)
+        return;
+    if (dap_chain_addr_is_blank(&l_tx_out_cond->subtype.srv_stake_pos_delegate.signing_addr) ||
+            l_tx_out_cond->subtype.srv_stake_pos_delegate.signer_node_addr.uint64 == 0)
+        return;
     dap_hash_fast_t l_datum_hash;
-
-    if (NULL != (l_tx_out_cond = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE,
-                                                                 &l_out_idx_tmp)))
-    {
-        dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_datum_hash);
-        if (!dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_datum_hash, l_out_idx_tmp, NULL)) {
-            dap_chain_net_srv_stake_item_t *l_stake = NULL;
-            HASH_FIND(ht, s_srv_stake->tx_itemlist, &l_datum_hash, sizeof(dap_hash_fast_t), l_stake);
-            if(!l_stake){
-                l_args->ret = dap_list_append(l_args->ret,a_tx);
-            }
-        }
-    }
-    return;
+    dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_datum_hash);
+    if (dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_datum_hash, l_out_idx_tmp, NULL))
+        return;
+    dap_chain_net_srv_stake_item_t *l_stake = NULL;
+    HASH_FIND(ht, s_srv_stake->tx_itemlist, &l_datum_hash, sizeof(dap_hash_fast_t), l_stake);
+    if (!l_stake)
+        l_args->ret = dap_list_append(l_args->ret,a_tx);
 }
 
 static int s_callback_compare_tx_list(dap_list_t *a_datum1, dap_list_t *a_datum2)
@@ -1669,6 +2202,16 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply)
     }
 
     switch (l_cmd_num) {
+
+        case CMD_ORDER:
+            return s_cli_srv_stake_order(a_argc, a_argv, l_arg_index + 1, a_str_reply, l_hash_out_type);
+
+        case CMD_DELEGATE:
+            return s_cli_srv_stake_delegate(a_argc, a_argv, l_arg_index + 1, a_str_reply, l_hash_out_type);
+
+        case CMD_INVALIDATE:
+            return s_cli_srv_stake_invalidate(a_argc, a_argv, l_arg_index + 1, a_str_reply, l_hash_out_type);
+
         case CMD_CHECK:
         {
             const char * l_netst = NULL;
@@ -1748,213 +2291,7 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply)
 
         }
         break;
-        case CMD_ORDER:
-            return s_cli_srv_stake_order(a_argc, a_argv, l_arg_index + 1, a_str_reply, l_hash_out_type);
-        case CMD_DELEGATE: {
-            const char *l_net_str = NULL,
-                       *l_wallet_str = NULL,
-                       *l_cert_str = NULL,
-                       *l_value_str = NULL,
-                       *l_fee_str = NULL,
-                       *l_node_addr_str = NULL,
-                       *l_order_hash_str = NULL,
-                       *l_sovereign_addr_str = NULL;
-            l_arg_index++;
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
-            if (!l_net_str) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -net");
-                return -3;
-            }
-            dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
-            if (!l_net) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
-                return -4;
-            }
-            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_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -w");
-                return -17;
-            }
-            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));
-            if (!l_wallet) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified wallet not found");
-                return -18;
-            } else {
-                l_sign_str = dap_chain_wallet_check_sign(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, "-order", &l_order_hash_str);
-            if (!l_cert_str && !l_order_hash_str) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -cert or -order");
-                dap_chain_wallet_close(l_wallet);
-                return -13;
-            }
-            dap_chain_node_addr_t l_node_addr;
-            uint256_t l_value_min, l_value_max;
-            if (l_cert_str) {
-                dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str);
-                if (!l_signing_cert) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate not found");
-                    dap_chain_wallet_close(l_wallet);
-                    return -19;
-                }
-                if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, l_net->pub.id)) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is wrong");
-                    dap_chain_wallet_close(l_wallet);
-                    return -20;
-                }
-                dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str);
-                if (l_node_addr_str) {
-                    if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) {
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized node addr %s", l_node_addr_str);
-                        dap_chain_wallet_close(l_wallet);
-                        return -14;
-                    }
-                } else
-                    l_node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
-            } else {
-                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) {
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified address is ivalid");
-                        return -24;
-                    }
-                    l_sovereign_addr = *l_spec_addr;
-                    DAP_DELETE(l_spec_addr);
-                } else
-                    dap_chain_addr_fill_from_key(&l_sovereign_addr, dap_chain_wallet_get_key(l_wallet, 0), l_net->pub.id);
-                dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str);
-                if (!l_order) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found");
-                    dap_chain_wallet_close(l_wallet);
-                    return -25;
-                }
-                if (l_order->ext_size != sizeof(struct validator_odrer_ext)) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order has invalid size");
-                    dap_chain_wallet_close(l_wallet);
-                    DAP_DELETE(l_order);
-                    return -26;
-                }
-                struct validator_odrer_ext *l_ext = (struct validator_odrer_ext *)l_order->ext_n_sign;
-                l_value_min = l_ext->value_min;
-                l_value_max = l_ext->value_max;
-                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) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order is unsigned");
-                    dap_chain_wallet_close(l_wallet);
-                    DAP_DELETE(l_order);
-                    return -27;
-                }
-                if (dap_strcmp(l_order->price_ticker, l_net->pub.native_ticker)) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order is invalid");
-                    dap_chain_wallet_close(l_wallet);
-                    DAP_DELETE(l_order);
-                    return -28;
-                }
-                dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_net->pub.id);
-                l_node_addr = l_order->node_addr;
-                l_sovereign_tax = l_order->price;
-                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_cli_server_cmd_set_reply_text(a_str_reply, "Tax must be lower or eqal than 100%% and higher or eqal than 1.0e-16%%");
-                    dap_chain_wallet_close(l_wallet);
-                    return -29;
-                }
-                DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax);
-            }
-            if (dap_chain_net_srv_stake_key_delegated(&l_signing_addr)) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is already delegated");
-                dap_chain_wallet_close(l_wallet);
-                return -21;
-            }
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str);
-            if (!l_value_str) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -value");
-                dap_chain_wallet_close(l_wallet);
-                return -9;
-            }
-            uint256_t l_value = dap_chain_balance_scan(l_value_str);
-            if (IS_ZERO_256(l_value)) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized number in '-value' param");
-                dap_chain_wallet_close(l_wallet);
-                return -10;
-            }
-            if (compare256(l_value, s_srv_stake->delegate_allowed_min) == -1) {
-                char *l_coin_str = dap_chain_balance_to_coins(l_value);
-                char *l_value_min_str = dap_chain_balance_print(s_srv_stake->delegate_allowed_min);
-                char *l_coin_min_str = dap_chain_balance_to_coins(s_srv_stake->delegate_allowed_min);
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Number in '-value' param %s(%s) is lower than minimum allowed value %s(%s)",
-                                                  l_coin_str, l_value_str, l_coin_min_str, l_value_min_str);
-                DAP_DELETE(l_coin_str);
-                DAP_DELETE(l_value_min_str);
-                DAP_DELETE(l_coin_min_str);
-                dap_chain_wallet_close(l_wallet);
-                return -11;
-            }
-            if (l_order_hash_str && compare256(l_value, l_value_min) == -1) {
-                char *l_coin_str = dap_chain_balance_to_coins(l_value);
-                char *l_value_min_str = dap_chain_balance_print(l_value_min);
-                char *l_coin_min_str = dap_chain_balance_to_coins(l_value_min);
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Number in '-value' param %s(%s) is lower than order minimum allowed value %s(%s)",
-                                                  l_coin_str, l_value_str, l_coin_min_str, l_value_min_str);
-                DAP_DELETE(l_coin_str);
-                DAP_DELETE(l_value_min_str);
-                DAP_DELETE(l_coin_min_str);
-                dap_chain_wallet_close(l_wallet);
-                return -13;
-            }
-            if (l_order_hash_str && compare256(l_value, l_value_max) == 1) {
-                char *l_coin_str = dap_chain_balance_to_coins(l_value);
-                char *l_value_max_str = dap_chain_balance_print(l_value_max);
-                char *l_coin_max_str = dap_chain_balance_to_coins(l_value_max);
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Number in '-value' param %s(%s) is higher than order minimum allowed value %s(%s)",
-                                                  l_coin_str, l_value_str, l_coin_max_str, l_value_max_str);
-                DAP_DELETE(l_coin_str);
-                DAP_DELETE(l_value_max_str);
-                DAP_DELETE(l_coin_max_str);
-                dap_chain_wallet_close(l_wallet);
-                return -14;
-            }
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
-            if (!l_fee_str) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -fee");
-                dap_chain_wallet_close(l_wallet);
-                return -15;
-            }
-            uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
-            if (IS_ZERO_256(l_fee)) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized number in '-fee' param");
-                dap_chain_wallet_close(l_wallet);
-                return -16;
-            }
-            int ret_val = 0;
-            if((ret_val = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr)) != 0){
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Key and node verification error");
-                dap_chain_wallet_close(l_wallet);
-                return ret_val;
-            }
 
-            // Create conditional transaction
-            dap_chain_datum_tx_t *l_tx = s_stake_tx_create(l_net, l_wallet, l_value, l_fee, &l_signing_addr, &l_node_addr,
-                                                           l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax);
-            dap_chain_wallet_close(l_wallet);
-            if (!l_tx || !s_stake_tx_put(l_tx, l_net)) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Stake transaction error");
-                DAP_DEL_Z(l_tx);
-                return -12;
-            }
-            dap_hash_fast_t l_tx_hash;
-            dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
-            DAP_DELETE(l_tx);
-            char *l_tx_hash_str = dap_hash_fast_to_str_new(&l_tx_hash);
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "%sSAVE TO TAKE ===>>> Stake transaction %s has done", l_sign_str, l_tx_hash_str);
-            DAP_DELETE(l_tx_hash_str);
-        } break;
         case CMD_APPROVE: {
             const char *l_net_str = NULL, *l_tx_hash_str = NULL, *l_cert_str = NULL;
             l_arg_index++;
@@ -2003,6 +2340,7 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply)
                                               l_decree_hash_str);
             DAP_DELETE(l_decree_hash_str);
         } break;
+
         case CMD_LIST: {
             l_arg_index++;            
             if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "keys", NULL)) {
@@ -2160,165 +2498,7 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply)
                 return -2;
             }
         } break;
-        case CMD_INVALIDATE: {
-            const char *l_net_str = NULL,
-                       *l_wallet_str = NULL,
-                       *l_fee_str = NULL,
-                       *l_tx_hash_str = NULL,
-                       *l_cert_str = NULL,
-                       *l_poa_cert_str = NULL,
-                       *l_signing_pkey_hash_str = NULL,
-                       *l_signing_pkey_type_str = NULL;
-            l_arg_index++;
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
-            if (!l_net_str) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'invalidate' requires parameter -net");
-                return -3;
-            }
-            dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
-            if (!l_net) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
-                return -4;
-            }
-            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) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'invalidate' requires parameter -w or -poa_cert");
-                    return -17;
-                }
-            } else {
-                dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
-                if (!l_fee_str) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -fee");
-                    return -5;
-                }
-                l_fee = dap_chain_balance_scan(l_fee_str);
-                if (IS_ZERO_256(l_fee)) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized number in '-fee' param");
-                    return -6;
-                }
-            }
-            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) {
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'invalidate' requires parameter -tx or -cert or -signing_pkey_hash");
-                        return -13;
-                    }
-                    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) {
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'invalidate' requires parameter -signing_pkey_type");
-                        return -14;
-                    }
-                    if (dap_sign_type_from_str(l_signing_pkey_type_str).type == SIG_TYPE_NULL) {
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Invalid signing_pkey_type %s", l_signing_pkey_type_str);
-                        return -15;
-                    }
-                }
-            }
 
-            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 (!dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_tx_hash)) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Transaction %s is not found", l_tx_hash_str);
-                    return -20;
-                }
-                dap_chain_net_srv_stake_item_t *l_stake;
-                HASH_FIND(hh, s_srv_stake->tx_itemlist, &l_tx_hash, sizeof(dap_hash_t), l_stake);
-                if (l_stake) {
-                    char l_pkey_hash_str[DAP_HASH_FAST_STR_SIZE];
-                    dap_hash_fast_to_str(&l_stake->signing_addr.data.hash_fast, l_pkey_hash_str, DAP_HASH_FAST_STR_SIZE);
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Transaction %s has active delegated key %s, need to revoke it first",
-                                                      l_tx_hash_str, l_pkey_hash_str);
-                    return -30;
-                }
-            } 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) {
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate not found");
-                        return -18;
-                    }
-                    if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, l_net->pub.id)) {
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is wrong");
-                        return -22;
-                    }
-                } else {
-                    dap_hash_fast_t l_pkey_hash = {};
-                    if (dap_chain_hash_fast_from_str(l_tx_hash_str, &l_pkey_hash)) {
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Invalid pkey hash format");
-                        return -23;
-                    }
-                    dap_chain_addr_fill(&l_signing_addr, dap_sign_type_from_str(l_signing_pkey_type_str), &l_pkey_hash, l_net->pub.id);
-                }
-                dap_chain_net_srv_stake_item_t *l_stake;
-                HASH_FIND(hh, s_srv_stake->itemlist, &l_signing_addr, sizeof(dap_chain_addr_t), l_stake);
-                if (!l_stake) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate/pkey hash is not delegated nor this delegating is approved."
-                                                                   " Try to invalidate with tx hash instead");
-                    return -24;
-                }
-                l_tx_hash = l_stake->tx_hash;
-            }
-            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));
-                if (!l_wallet) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified wallet not found");
-                    return -18;
-                } 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);
-                dap_chain_datum_tx_t *l_tx = s_stake_tx_invalidate(l_net, &l_tx_hash, l_fee, l_enc_key);
-                dap_chain_wallet_close(l_wallet);
-                dap_enc_key_delete(l_enc_key);
-                char *l_tx_hash_str = NULL;
-                if (l_tx && (l_tx_hash_str = s_stake_tx_put(l_tx, l_net))) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "%sAll m-tokens successfully returned to "
-                                                                   "owner. Returning tx hash %s.", l_sign_str, l_tx_hash_str);
-                    DAP_DEL_Z(l_tx_hash_str);
-                    DAP_DELETE(l_tx);
-                } else {
-                    l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_tx_hash);
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't invalidate transaction %s, examine log files for details", l_tx_hash_str);
-                    DAP_DELETE(l_tx_hash_str);
-                    DAP_DEL_Z(l_tx);
-                    return -21;
-                }
-            } else {
-                dap_cert_t *l_poa_cert = dap_cert_find_by_name(l_poa_cert_str);
-                if (!l_poa_cert) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate not found");
-                    return -25;
-                }
-                if (!s_srv_stake_is_poa_cert(l_net, l_poa_cert->enc_key)) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is not PoA root one");
-                    return -26;
-                }
-                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))) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified delageted key invalidated. "
-                                                                   "Created key invalidation decree %s."
-                                                                   "Try to execute this command with -w to return m-tokens to owner", l_decree_hash_str);
-                    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_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't invalidate transaction %s, examine log files for details", l_tx_hash_str);
-                    DAP_DEL_Z(l_decree);
-                    return -21;
-                }
-            }
-        } break;
         case CMD_MIN_VALUE: {
             const char *l_net_str = NULL,
                        *l_cert_str = NULL,
@@ -2373,7 +2553,8 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply)
                 DAP_DEL_Z(l_decree);
                 return -21;
             }
-        } break;        
+        } break;
+
         default: {
             dap_cli_server_cmd_set_reply_text(a_str_reply, "Command %s not recognized", a_argv[l_arg_index]);
             return -1;
diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c
index 013ccb5d87..c1e8f25e29 100644
--- a/modules/service/xchange/dap_chain_net_srv_xchange.c
+++ b/modules/service/xchange/dap_chain_net_srv_xchange.c
@@ -1502,7 +1502,7 @@ static xchange_tx_type_t s_xchange_tx_get_type (dap_chain_net_t * a_net, dap_cha
         dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig);
 
         bool l_owner = false;
-        l_owner = dap_sign_match_pkey_signs(l_prev_sign,l_sign);
+        l_owner = dap_sign_compare_pkeys(l_prev_sign,l_sign);
         if (l_owner)
                 l_tx_type = TX_TYPE_INVALIDATE;
         else
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 38fce2f0ea..5cdb1c557b 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -450,7 +450,9 @@ static void s_cli_meta_hex_print(  dap_string_t * a_str_tmp, const char * a_meta
 
 static void s_print_autocollect_table(dap_chain_net_t *a_net, dap_string_t *a_reply_str, const char *a_table_name)
 {
-    dap_string_append_printf(a_reply_str, "\n=== %s ===\n", a_table_name);
+    dap_string_append_printf(a_reply_str, "\nAutocollect status is %s\n", dap_chain_esbocs_get_autocollect_status(a_net->pub.id) ?
+                                                             "active" : "inactive, check the network config");
+    dap_string_append_printf(a_reply_str, "\nAutocollect tables content for:\n=== %s ===\n", a_table_name);
     size_t l_objs_count = 0;
     char *l_group = dap_strcmp(a_table_name, "Fees") ? dap_chain_cs_blocks_get_reward_group(a_net->pub.name)
                                                      : dap_chain_cs_blocks_get_fee_group(a_net->pub.name);
@@ -486,7 +488,7 @@ static void s_print_autocollect_table(dap_chain_net_t *a_net, dap_string_t *a_re
         char *l_profit_str = dap_chain_balance_to_coins(l_collect_value);
         char *l_tax_str = dap_chain_balance_to_coins(l_collect_tax);
         char *l_fee_str = dap_chain_balance_to_coins(l_collect_fee);
-        dap_string_append_printf(a_reply_str, "Total prepared value: %s %s, where\n\tprofit is %s, tax is %s, fee is %s\n",
+        dap_string_append_printf(a_reply_str, "\nTotal prepared value: %s %s, where\n\tprofit is %s, tax is %s, fee is %s\n",
                                  l_total_str, a_net->pub.native_ticker, l_profit_str, l_tax_str, l_fee_str);
         DAP_DEL_Z(l_total_str);
         DAP_DEL_Z(l_profit_str);
@@ -1048,7 +1050,7 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void **a_str_reply)
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'block autocollect' requires subcommand 'status'");
                 return -14;
             }
-            dap_string_t *l_reply_str = dap_string_new("Autocollect tables content for:\n");
+            dap_string_t *l_reply_str = dap_string_new("");
             s_print_autocollect_table(l_net, l_reply_str, "Fees");
             s_print_autocollect_table(l_net, l_reply_str, "Rewards");
             dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_reply_str->str);
-- 
GitLab