From 2624dd36e6eb9a202571b25cd560f5dbd43a2dd1 Mon Sep 17 00:00:00 2001
From: "roman.padenkov" <roman.padenkov@demlabs.net>
Date: Mon, 13 Feb 2023 08:17:33 +0000
Subject: [PATCH] features-7410+

---
 modules/chain/dap_chain_ledger.c              |  48 ++--
 modules/common/dap_chain_datum.c              |   4 +-
 modules/mempool/dap_chain_mempool.c           |  53 ++--
 .../stake_lock/dap_chain_net_srv_stake_lock.c | 234 +++++++++++++-----
 .../include/dap_chain_net_srv_stake_lock.h    |   4 +-
 5 files changed, 233 insertions(+), 110 deletions(-)

diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index d04aefb667..016a464a66 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -84,7 +84,7 @@ static  pthread_rwlock_t s_verificators_rwlock;
 typedef struct dap_chain_ledger_stake_lock_item {
     dap_chain_hash_fast_t	tx_for_stake_lock_hash;
     dap_chain_hash_fast_t	tx_used_out;
-//	const char 				datum_token_emission_hash[DAP_CHAIN_HASH_FAST_STR_SIZE];
+    uint256_t ems_value;
     UT_hash_handle hh;
 } dap_chain_ledger_stake_lock_item_t;
 
@@ -3026,8 +3026,8 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         default:
             break;
         }
-
         bound_item->tx_prev_hash = l_tx_prev_hash;
+
         bool l_is_ems = (l_cond_type ==TX_ITEM_TYPE_IN_EMS) ? 1 : 0;
         char l_tx_prev_hash_str[70]={[0]='\0'};
         if (l_is_ems){
@@ -3040,21 +3040,16 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         uint256_t l_value;
         void *l_tx_prev_out = NULL;
         dap_chain_datum_tx_t *l_tx_prev = NULL;
-
+        bool is_emission = false;
         if (l_is_ems) {   // It's the emission TX
-            // if at least one blank hash is present, then all the hashes should be blank
-            if (l_list_tmp_num > 1) {
-                l_err_num = -3;
-                log_it(L_WARNING, "Only one IN item allowed for base TX");
-                break;
-            }
+
             dap_chain_tx_in_ems_t *l_tx_token = (dap_chain_tx_in_ems_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_IN_EMS, NULL);
             if (!l_tx_token) {
                 log_it(L_WARNING, "tx token item is mandatory for base TX");
                 l_err_num = -4;
                 break;
             }
-            bool is_emission = false;
+            //bool is_emission = false;
             l_token = l_tx_token->header.ticker;
             l_emission_hash = &l_tx_token->header.token_emission_hash;
             dap_chain_ledger_token_emission_item_t *l_emission_item = s_emission_item_find(a_ledger, l_token, l_emission_hash);
@@ -3083,9 +3078,9 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                         break;
                     }
 //				int item_count = 0;
-                    dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*)dap_chain_datum_tx_item_get(a_tx, 0, TX_ITEM_TYPE_OUT, 0);//TODO: ADD CHECK COUNT TX
+                    dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*)dap_chain_datum_tx_item_get(a_tx, 0, TX_ITEM_TYPE_OUT_EXT, 0);//TODO: ADD CHECK COUNT TX
                     if (!l_tx_out) {
-                        debug_if(s_debug_more, L_WARNING, "Can't find OUT item for base TX with tx_token [%s]", l_tx_token->header.ticker);
+                        debug_if(true, L_WARNING, "Can't find OUT item for base TX with tx_token [%s]", l_tx_token->header.ticker);
                         l_err_num = -24;
                         break;
                     }
@@ -3167,8 +3162,10 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                     debug_if(s_debug_more, L_NOTICE, "Check emission passed for tx_token [%s]", l_tx_token->header.ticker);
                     bound_item->tx_prev = l_tx_stake_lock;
                     bound_item->stake_lock_item = stake_lock_emission;
-                    l_list_bound_items = dap_list_append(l_list_bound_items, bound_item);
-                    break;
+                    bound_item->stake_lock_item->ems_value = l_value_expected;
+                    //l_list_bound_items = dap_list_append(l_list_bound_items, bound_item);
+                    is_emission = true;
+
                 } else {
                     debug_if(s_debug_more, L_WARNING, "tx_token [%s] not valid for stake_lock transaction", l_token);
                     l_err_num = -31;
@@ -3183,8 +3180,9 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                         l_err_num = -22;
                         break;
                     }
+                    bound_item->item_emission = l_emission_item;
             }//end else emission
-            bound_item->item_emission = l_emission_item;
+
         }
         else //It's not the emission TX
         {
@@ -3322,10 +3320,15 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             l_value = l_tx_prev_out_cond->header.value;
         }
         else if(l_cond_type == TX_ITEM_TYPE_IN_EMS){
-
-            l_token = bound_item->item_emission->datum_token_emission->hdr.ticker;
-            l_value = bound_item->item_emission->datum_token_emission->hdr.value_256;
-
+            if(is_emission){
+                l_token = bound_item->in.tx_cur_in_ems->header.ticker;
+                l_value = bound_item->stake_lock_item->ems_value;
+                is_emission = false;
+            }
+            else{
+                l_token = bound_item->item_emission->datum_token_emission->hdr.ticker;
+                l_value = bound_item->item_emission->datum_token_emission->hdr.value_256;
+            }
         }
         if (! l_token || !*l_token ) {
             log_it(L_WARNING, "No token ticker found in previous transaction");
@@ -3794,7 +3797,11 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
                 }
                 if (!IS_ZERO_256(l_token_item->total_supply)) {
                     dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*)dap_chain_datum_tx_item_get(a_tx, 0, TX_ITEM_TYPE_OUT, 0);
-                    SUBTRACT_256_256(l_token_item->current_supply, l_tx_out->header.value, &l_token_item->current_supply);
+//                    dap_chain_tx_out_ext_t *l_tx_out_ext = (dap_chain_tx_out_ext_t*)dap_chain_datum_tx_item_get(a_tx, 0, TX_ITEM_TYPE_OUT_EXT, 0);
+//                    uint256_t tmp = l_tx_out ? l_tx_out->header.value : l_tx_out_ext->header.value;
+                    uint256_t l_value_tmp = bound_item->stake_lock_item->ems_value;
+                    //SUBTRACT_256_256(l_token_item->current_supply, l_tx_out->header.value, &l_token_item->current_supply);
+                    SUBTRACT_256_256(l_token_item->current_supply, l_value_tmp, &l_token_item->current_supply);
                     char *l_balance = dap_chain_balance_print(l_token_item->current_supply);
                     log_it(L_DEBUG, "New current supply %s for token %s", l_balance, l_token_item->ticker);
                     DAP_DEL_Z(l_balance);
@@ -4519,7 +4526,6 @@ uint256_t dap_chain_ledger_calc_balance_full(dap_ledger_t *a_ledger, const dap_c
     return balance;
 }
 
-
 /**
  * Get the transaction in the cache by the addr in out item
  *
diff --git a/modules/common/dap_chain_datum.c b/modules/common/dap_chain_datum.c
index 92f2c1eb9d..71f4cdc95d 100644
--- a/modules/common/dap_chain_datum.c
+++ b/modules/common/dap_chain_datum.c
@@ -281,7 +281,7 @@ bool dap_chain_datum_dump_tx(dap_chain_datum_tx_t *a_datum,
                 l_hash_str = dap_chain_hash_fast_to_str_new(l_hash_tmp);
             else
                 l_hash_str = dap_enc_base58_encode_hash_to_str(l_hash_tmp);
-            dap_string_append_printf(a_str_out, "\t TOKEN:\n"
+            dap_string_append_printf(a_str_out, "\t IN_EMS:\n"
                                                 "\t\t ticker: %s \n"
                                                 "\t\t token_emission_hash: %s\n"
                                                 "\t\t token_emission_chain_id: 0x%016"DAP_UINT64_FORMAT_x"\n",
@@ -296,7 +296,7 @@ bool dap_chain_datum_dump_tx(dap_chain_datum_tx_t *a_datum,
                 l_hash_str = dap_chain_hash_fast_to_str_new(l_hash_tmp);
             else
                 l_hash_str = dap_enc_base58_encode_hash_to_str(l_hash_tmp);
-            dap_string_append_printf(a_str_out, "\t TOKEN EXT:\n"
+            dap_string_append_printf(a_str_out, "\t IN_EMS EXT:\n"
                                          "\t\t Version: %u\n"
                                          "\t\t Ticker: %s\n"
                                          "\t\t Ext chain id: 0x%016"DAP_UINT64_FORMAT_x"\n"
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index fef0ffa03a..66d8de69e3 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -703,17 +703,20 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast
                                        const char *a_hash_out_type, uint256_t a_value_fee)
 {
     uint256_t l_net_fee = {};
+    uint256_t l_total_fee = a_value_fee;
     uint256_t l_value_need = a_emission_value;
     uint256_t l_value_transfer = {};
     dap_chain_addr_t l_addr_fee = {};
     dap_chain_addr_t* l_addr_from = NULL;
-    dap_chain_tx_out_cond_t *l_tx_out_fee = NULL;
-    dap_chain_tx_out_t *l_out_fee_net;
-    dap_chain_tx_in_t *l_in;
+    //dap_chain_tx_out_cond_t *l_tx_out_fee = NULL;
+    //dap_chain_tx_out_t *l_out_fee_net;
+    //dap_chain_tx_in_t *l_in;
     dap_list_t *l_list_used_out;
     const char *l_native_ticker = dap_chain_net_by_id(a_chain->net_id)->pub.native_ticker;
     bool not_native = dap_strcmp(a_ticker, l_native_ticker);
     bool l_net_fee_used = dap_chain_net_tx_get_fee(a_chain->net_id, &l_net_fee, &l_addr_fee);
+    if(l_net_fee_used)
+        SUM_256_256(l_total_fee,l_net_fee,&l_total_fee);
 
     dap_chain_datum_tx_t *l_tx = DAP_NEW_Z_SIZE(dap_chain_datum_tx_t, sizeof(dap_chain_datum_tx_t));
     l_tx->header.ts_created = time(NULL);
@@ -729,7 +732,7 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast
         }
             // list of transaction with 'out' items
         l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, l_native_ticker,
-                                                                                 l_addr_from, l_net_fee, &l_value_transfer);
+                                                                                 l_addr_from, l_total_fee, &l_value_transfer);
         if (!l_list_used_out) {
             log_it(L_WARNING,"Not enough funds to transfer");
             DAP_DEL_Z(l_addr_from);
@@ -737,26 +740,20 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast
             return NULL;
         }
         //add in
-        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_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
         uint256_t l_value_back = l_value_transfer; // how much datoshi add to 'out' items
-        if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to, l_value_need, a_ticker)){
+         // Network fee
+        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_DEL_Z(l_addr_from);
             return NULL;
         }
-        if(l_net_fee_used){
-             // Network fee
-            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_DEL_Z(l_addr_from);
-                return NULL;
-            }
-            SUBTRACT_256_256(l_value_back, l_net_fee, &l_value_back);
-        }
+        SUBTRACT_256_256(l_value_back, l_net_fee, &l_value_back);
         if (!IS_ZERO_256(a_value_fee))
             SUBTRACT_256_256(l_value_back, a_value_fee, &l_value_back);
         // coin back
@@ -766,21 +763,27 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast
             return NULL;
         }
         DAP_DEL_Z(l_addr_from);
+
+        if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to, l_value_need, a_ticker)){
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
     }
     else
     {//nativ ticker
         if (!IS_ZERO_256(a_value_fee))
             SUBTRACT_256_256(l_value_need, a_value_fee, &l_value_need);
-        if(l_net_fee_used)
-            SUBTRACT_256_256(l_value_need, l_net_fee, &l_value_need);        
-        if (!dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_need)){
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
+        if(l_net_fee_used){
+            SUBTRACT_256_256(l_value_need, l_net_fee, &l_value_need);
+            if (!dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee)){
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
         }
-        if (!dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee)){
+        if (!dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_need)){
             dap_chain_datum_tx_delete(l_tx);
             return NULL;
-        }
+        }        
     }
     //in_ems
     dap_chain_tx_in_ems_t    *l_tx_token = dap_chain_datum_tx_item_token_create(a_emission_chain_id, a_emission_hash, a_ticker);
diff --git a/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c b/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c
index aa52f19647..2bb5e6600d 100644
--- a/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c
+++ b/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c
@@ -98,7 +98,8 @@ typedef struct dap_chain_ledger_token_emission_for_stake_lock_item {
 static int												s_cli_stake_lock(int a_argc, char **a_argv, char **a_str_reply);
 static char                                             *dap_chain_mempool_base_tx_for_stake_lock_create(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_emission_hash,
                                                                               dap_chain_id_t a_emission_chain_id, uint256_t a_emission_value, const char *a_ticker,
-                                                                              dap_chain_addr_t *a_addr_to, dap_enc_key_t *a_key_from, const char *a_hash_out_type, uint256_t a_value_fee);
+                                                                              dap_chain_addr_t *a_addr_to, dap_enc_key_t *a_key_from, const char *a_hash_out_type, uint256_t a_value_fee,
+                                                                              uint256_t a_value_change, uint32_t a_tx_out_prev_idx);
 // Callbacks
 static void												s_callback_decree (dap_chain_net_srv_t * a_srv, dap_chain_net_t *a_net, dap_chain_t * a_chain,
                                                                               dap_chain_datum_decree_t * a_decree, size_t a_decree_size);
@@ -362,11 +363,13 @@ static enum error_code s_cli_hold(int a_argc, char **a_argv, int a_arg_index, da
         dap_string_append_printf(output_line, "'%s'", l_cert_str);
         return CERT_KEY_ERROR;
     }
+    uint256_t l_value_change = {};
+    uint32_t l_tx_out_prev_idx = 0;
 
     // Make transfer transaction
     dap_chain_datum_t *l_datum = dap_chain_net_srv_stake_lock_datum_create(l_net, l_key_from, l_key_cond,
                                                                  l_ticker_str,l_value,l_value_fee, l_uid,
-                                                                 l_time_staking, l_reinvest_percent, create_base_tx);
+                                                                 l_time_staking, l_reinvest_percent, create_base_tx,&l_value_change,&l_tx_out_prev_idx);
     DAP_DEL_Z(l_key_cond);
     if (create_base_tx)
         dap_hash_fast(l_datum->data, l_datum->header.data_size, &l_tx_cond_hash);
@@ -386,7 +389,7 @@ static enum error_code s_cli_hold(int a_argc, char **a_argv, int a_arg_index, da
     if (create_base_tx)
         l_hash_str = dap_chain_mempool_base_tx_for_stake_lock_create(l_chain, &l_tx_cond_hash, l_chain->id,
                                                       l_value_delegated, delegate_ticker_str, l_addr_holder,
-                                                      l_key_from, l_hash_out_type, l_value_fee);
+                                                      l_key_from, l_hash_out_type, l_value_fee,l_value_change,l_tx_out_prev_idx);
 
     dap_chain_wallet_close(l_wallet);
 
@@ -566,13 +569,7 @@ static enum error_code s_cli_take(int a_argc, char **a_argv, int a_arg_index, da
         SUM_256_256(l_value_need,l_net_fee,&l_value_need);
     SUM_256_256(l_value_need,l_value_fee,&l_value_need);
 
-    // list of transaction with 'out' items
-    dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, l_ticker_str,
-                                                                             l_owner_addr, l_value_need, &l_value_transfer);
-    if(!l_list_used_out) {
-        log_it( L_ERROR, "Nothing to transfer (not enough funds)");
-        return -1;
-    }
+
     //add tx
     if (NULL == (l_tx = dap_chain_datum_tx_create())) {//malloc
         dap_chain_wallet_close(l_wallet);
@@ -581,12 +578,8 @@ static enum error_code s_cli_take(int a_argc, char **a_argv, int a_arg_index, da
     }
 
     dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_tx_hash, l_prev_cond_idx, 0);
-    {
-        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, free);
-    }
-    //dap_chain_datum_tx_add_out_item(&l_tx, l_owner_addr, l_tx_out_cond->header.value);
+
+    dap_chain_datum_tx_add_out_item(&l_tx, l_owner_addr, l_tx_out_cond->header.value);
 
     uint256_t l_value_back = {},l_value_pack = {};
     // Network fee
@@ -605,23 +598,14 @@ static enum error_code s_cli_take(int a_argc, char **a_argv, int a_arg_index, da
         }
         SUM_256_256(l_value_pack, l_value_fee, &l_value_pack);
     }
-    // coin back
-
-    SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-    SUM_256_256(l_value_back, l_tx_out_cond->header.value, &l_value_back);
-    if (!IS_ZERO_256(l_value_back)) {
-        if(dap_chain_datum_tx_add_out_item(&l_tx, l_owner_addr, l_value_back) != 1)
-        {
-            dap_chain_datum_tx_delete(l_tx);
-            return COIN_BACK_ERROR;
-        }
-    }
 
     //add burning tx
     if (l_tx_out_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX) {
         dap_chain_addr_t l_addr_blank = {0};
+        uint32_t l_tx_out_prev_idx = 0;
+        uint256_t l_value_change = {};
         if (NULL == (l_datum_burning_tx = dap_chain_burning_tx_create(l_chain, l_owner_key, l_owner_addr, &l_addr_blank,
-                                                                  delegate_ticker_str, l_value_delegated))) {//malloc
+                                                                  delegate_ticker_str, l_value_delegated, l_value_fee,&l_tx_out_prev_idx,&l_value_change))) {//malloc
             dap_chain_wallet_close(l_wallet);
             DAP_DEL_Z(l_owner_addr);
             dap_chain_datum_tx_delete(l_tx);
@@ -640,6 +624,36 @@ static enum error_code s_cli_take(int a_argc, char **a_argv, int a_arg_index, da
         }
 
         dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt);
+
+        dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(&l_tx_burning_hash, l_tx_out_prev_idx-1);
+        dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in);
+        l_value_transfer = l_value_change;
+    }
+    else
+    {
+            dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, l_ticker_str,
+                                                                                     l_owner_addr, l_value_need, &l_value_transfer);
+            if(!l_list_used_out) {
+                log_it( L_ERROR, "Nothing to transfer (not enough funds)");
+                return -1;
+            }
+
+            {
+                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, free);
+            }
+    }
+    // coin back
+
+    SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
+    //SUM_256_256(l_value_back, l_tx_out_cond->header.value, &l_value_back);
+    if (!IS_ZERO_256(l_value_back)) {
+        if(dap_chain_datum_tx_add_out_item(&l_tx, l_owner_addr, l_value_back) != 1)
+        {
+            dap_chain_datum_tx_delete(l_tx);
+            return COIN_BACK_ERROR;
+        }
     }
 
     if(dap_chain_datum_tx_add_sign_item(&l_tx, l_owner_key) != 1) {
@@ -1135,7 +1149,13 @@ static bool s_stake_lock_callback_verificator(dap_ledger_t *a_ledger, dap_hash_f
         return false;
 
     if (!EQUAL_256(a_cond->header.value, l_tx_out->header.value))
+    {
+        char *l_balance_coins = dap_chain_balance_to_coins(a_cond->header.value);
+        log_it(L_ERROR, "a_cond->header.value - %s", l_balance_coins);
+        l_balance_coins = dap_chain_balance_to_coins(l_tx_out->header.value);
+        log_it(L_ERROR, "l_tx_out->header.value - %s", l_balance_coins);
         return false;
+    }
 
     if (a_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX) {
         if (NULL == (delegate_token = dap_chain_ledger_token_ticker_check(a_ledger, delegated_ticker))
@@ -1241,7 +1261,7 @@ dap_chain_datum_t *dap_chain_net_srv_stake_lock_datum_create(dap_chain_net_t *a_
                                                    const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
                                                    uint256_t a_value, uint256_t a_value_fee, dap_chain_net_srv_uid_t a_srv_uid,
                                                    dap_time_t a_time_staking, uint256_t a_reinvest_percent,
-                                                   bool a_create_base_tx)
+                                                   bool a_create_base_tx,uint256_t *a_value_change, uint32_t *a_tx_out_prev_idx)
 {
     dap_ledger_t * l_ledger = a_net ? dap_chain_ledger_by_net_name( a_net->pub.name ) : NULL;
     // check valid param
@@ -1251,17 +1271,14 @@ dap_chain_datum_t *dap_chain_net_srv_stake_lock_datum_create(dap_chain_net_t *a_
 
     // 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 = {};
-//	SUM_256_256(a_value, a_value_fee, &l_value_need);
+    uint256_t l_value_need = {}, l_net_fee = {}, l_total_fee = {};
+    SUM_256_256(a_value, a_value_fee, &l_value_need);
     // where to take coins for service
     dap_chain_addr_t l_addr_from;
     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_net_fee,a_value_fee,&l_total_fee);
-    else
-        SUM_256_256(l_total_fee,a_value_fee,&l_total_fee);
-    SUM_256_256(l_value_need,l_total_fee,&l_value_need);
+        SUM_256_256(l_value_need,l_net_fee,&l_value_need);
 
     dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, a_net->pub.id);
     // list of transaction with 'out' items
@@ -1287,12 +1304,13 @@ dap_chain_datum_t *dap_chain_net_srv_stake_lock_datum_create(dap_chain_net_t *a_
         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);
+            DAP_DEL_Z(l_tx_out_cond);
             // transaction fee
 //			if (!IS_ZERO_256(a_value_fee)) {
                 // TODO add condition with fee for mempool-as-service
 //			}
         }//TODO: else return false;
+        (*a_tx_out_prev_idx)++;
 
         uint256_t l_value_back = {};
         // Network fee
@@ -1303,8 +1321,9 @@ dap_chain_datum_t *dap_chain_net_srv_stake_lock_datum_create(dap_chain_net_t *a_
                 return NULL;
             }
             SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            (*a_tx_out_prev_idx)++;
         }
-        // Validator's fee        
+        // 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);
@@ -1312,10 +1331,9 @@ dap_chain_datum_t *dap_chain_net_srv_stake_lock_datum_create(dap_chain_net_t *a_
                 return NULL;
             }
             SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            (*a_tx_out_prev_idx)++;
         }
-
         // 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_item(&l_tx, &l_addr_from, l_value_back) != 1) {
@@ -1323,6 +1341,8 @@ dap_chain_datum_t *dap_chain_net_srv_stake_lock_datum_create(dap_chain_net_t *a_
                 log_it( L_ERROR, "Cant add coin back output");
                 return NULL;
             }
+            (*a_tx_out_prev_idx)++;
+            *a_value_change = l_value_back;
         }
     }
 
@@ -1376,7 +1396,7 @@ dap_chain_tx_out_cond_t *dap_chain_net_srv_stake_lock_create_cond_out(dap_pkey_t
 dap_chain_datum_t *dap_chain_burning_tx_create(dap_chain_t *a_chain, dap_enc_key_t *a_key_from,
                                              const dap_chain_addr_t* a_addr_from, const dap_chain_addr_t* a_addr_to,
                                              const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-                                             uint256_t a_value)
+                                             uint256_t a_value, uint256_t a_value_fee, uint32_t *a_tx_out_prev_idx,uint256_t *a_value_change)
 {
     // check valid param
     if(!a_chain | !a_key_from || ! a_addr_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size ||
@@ -1385,14 +1405,23 @@ dap_chain_datum_t *dap_chain_burning_tx_create(dap_chain_t *a_chain, dap_enc_key
 
     // find the transactions from which to take away coins
     uint256_t l_value_transfer = {}; // how many coins to transfer
+    uint256_t l_net_fee = {};
+    uint256_t l_total_fee = a_value_fee;
+    dap_chain_addr_t l_addr_fee = {};
+    const char *l_native_ticker = dap_chain_net_by_id(a_chain->net_id)->pub.native_ticker;
     dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, a_token_ticker,
                                                                              a_addr_from, a_value, &l_value_transfer);
+    bool l_net_fee_used = dap_chain_net_tx_get_fee(a_chain->net_id, &l_net_fee, &l_addr_fee);
+    if(l_net_fee_used)
+        SUM_256_256(l_total_fee,l_net_fee,&l_total_fee);
+
     if (!l_list_used_out) {
         log_it(L_WARNING,"Not enough funds to transfer");
         return NULL;
     }
-    // create empty transaction
+    // create empty transaction    
     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    //----------burning add transaction------------
     // add 'in' items
     {
         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
@@ -1402,17 +1431,64 @@ dap_chain_datum_t *dap_chain_burning_tx_create(dap_chain_t *a_chain, dap_enc_key
     // add 'out' items
     {
         uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
-        if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, a_value) == 1) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to, a_value, a_token_ticker)==1){
             SUM_256_256(l_value_pack, a_value, &l_value_pack);
+            (*a_tx_out_prev_idx)++;
         }
         // coin back
         uint256_t l_value_back;
         SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
         if(!IS_ZERO_256(l_value_back)) {
-            if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) {
+            if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker)){
                 dap_chain_datum_tx_delete(l_tx);
                 return NULL;
             }
+            (*a_tx_out_prev_idx)++;
+        }        
+    }
+    //----------fee add transaction------------
+    l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, l_native_ticker,
+                                                                                 a_addr_from, l_total_fee, &l_value_transfer);
+    // add 'in' items
+    {
+        uint256_t l_value_to_items_fee = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+        assert(EQUAL_256(l_value_to_items_fee, l_value_transfer));
+        dap_list_free_full(l_list_used_out, free);
+    }
+    // add 'out fee' items
+    {
+        uint256_t l_value_pack = {};
+        // 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);
+                return NULL;
+            }
+            SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            (*a_tx_out_prev_idx)++;
+        }
+        // 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);
+                (*a_tx_out_prev_idx)++;
+            }
+            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_ext_item(&l_tx, a_addr_from, l_value_back,l_native_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+            (*a_tx_out_prev_idx)++;
+            *a_value_change = l_value_back;
         }
     }
 
@@ -1432,44 +1508,81 @@ dap_chain_datum_t *dap_chain_burning_tx_create(dap_chain_t *a_chain, dap_enc_key
 
 static char *dap_chain_mempool_base_tx_for_stake_lock_create(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_emission_hash,
                                                         dap_chain_id_t a_emission_chain_id, uint256_t a_emission_value, const char *a_ticker,
-                                                        dap_chain_addr_t *a_addr_to, dap_enc_key_t *a_key_from, const char *a_hash_out_type, uint256_t a_value_fee)
+                                                        dap_chain_addr_t *a_addr_to, dap_enc_key_t *a_key_from, const char *a_hash_out_type,
+                                                        uint256_t a_value_fee, uint256_t a_value_change, uint32_t a_tx_out_prev_idx)
 {
 
     uint256_t l_net_fee = {};
+    uint256_t l_value_transfer = {}; // how many coins to transfer
+    uint256_t l_value_need = a_value_fee;
     dap_chain_addr_t l_net_fee_addr = {};
+    dap_chain_addr_t *l_addr_from;
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
+
+    const char *l_native_ticker = l_net->pub.native_ticker;
     bool l_net_fee_used = dap_chain_net_tx_get_fee(a_chain->net_id, &l_net_fee, &l_net_fee_addr);
+    if(l_net_fee_used)
+        SUM_256_256(l_value_need,l_net_fee,&l_value_need);
     // create first transaction (with tx_token)
     dap_chain_datum_tx_t *l_tx = DAP_NEW_Z_SIZE(dap_chain_datum_tx_t, sizeof(dap_chain_datum_tx_t));
     l_tx->header.ts_created = time(NULL);
-    dap_chain_hash_fast_t l_tx_prev_hash = { 0 };
+
+    l_addr_from = DAP_NEW_Z(dap_chain_addr_t);
+    dap_chain_addr_fill_from_key(l_addr_from, a_key_from, l_net->pub.id);
     // create items
 
     dap_chain_tx_in_ems_t *l_tx_token = dap_chain_datum_tx_item_token_create(a_emission_chain_id, a_emission_hash, a_ticker);
-    dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(&l_tx_prev_hash, 0);
-    dap_chain_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(a_addr_to, a_emission_value);
 
+    dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(a_emission_hash, a_tx_out_prev_idx-1);
+    //dap_chain_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(a_addr_to, a_emission_value);
 
     // pack items to transaction
     dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_token);
     dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in);
-    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out);
+    //dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out);
+    if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to, a_emission_value, a_ticker)){
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+
+//    dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, l_native_ticker,
+//                                                                             l_addr_from, l_value_need, &l_value_transfer);
+    if(compare256(a_value_change,l_value_need)<0) {
+        log_it(L_WARNING,"Not enough funds to transfer");
+        DAP_DEL_Z(l_addr_from);
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+    l_value_transfer = a_value_change;
+    uint256_t l_value_back = l_value_transfer;
+    //add in
+//    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);
     // Network fee
-/*    if (l_net_fee_used) {
-        if (dap_chain_datum_tx_add_out_item(&l_tx, &l_net_fee_addr, l_net_fee) != 1) {
+    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)){
             dap_chain_datum_tx_delete(l_tx);
-            log_it(L_ERROR, "Cant add network fee output");
+            DAP_DEL_Z(l_addr_from);
             return NULL;
         }
+        SUBTRACT_256_256(l_value_back, l_net_fee, &l_value_back);
     }
     // 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);
-            log_it(L_ERROR, "Cant add validator's fee output");
-            return NULL;
-        }
+    if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        log_it(L_ERROR, "Cant add validator's fee output");
+        return NULL;
+    }
+    SUBTRACT_256_256(l_value_back, a_value_fee, &l_value_back);
+    // coin back
+    if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_native_ticker)){
+        dap_chain_datum_tx_delete(l_tx);
+        DAP_DEL_Z(l_addr_from);
+        return NULL;
     }
-    */
+    DAP_DEL_Z(l_addr_from);
+
     if (a_key_from) {
         if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) < 0) {
             log_it(L_WARNING, "Private key not valid");
@@ -1481,8 +1594,9 @@ static char *dap_chain_mempool_base_tx_for_stake_lock_create(dap_chain_t *a_chai
     }
 
     DAP_DEL_Z(l_tx_token);
-    DAP_DEL_Z(l_in);
-    DAP_DEL_Z(l_out);
+    DAP_DEL_Z(l_addr_from);
+    //DAP_DEL_Z(l_in);
+   // DAP_DEL_Z(l_out);
 
     size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
 
diff --git a/modules/service/stake_lock/include/dap_chain_net_srv_stake_lock.h b/modules/service/stake_lock/include/dap_chain_net_srv_stake_lock.h
index 6596c2d35a..b6a086266f 100644
--- a/modules/service/stake_lock/include/dap_chain_net_srv_stake_lock.h
+++ b/modules/service/stake_lock/include/dap_chain_net_srv_stake_lock.h
@@ -60,9 +60,9 @@ dap_chain_datum_t *dap_chain_net_srv_stake_lock_datum_create(dap_chain_net_t *a_
                                                    const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
                                                    uint256_t a_value, uint256_t a_value_fee, dap_chain_net_srv_uid_t a_srv_uid,
                                                    dap_time_t a_time_staking, uint256_t a_reinvest_percent,
-                                                   bool a_create_base_tx);
+                                                   bool a_create_base_tx,uint256_t *a_value_change, uint32_t *a_tx_out_prev_idx);
 // Burning_tx_create
 dap_chain_datum_t *dap_chain_burning_tx_create(dap_chain_t* a_chain, dap_enc_key_t* a_key_from,
                                                     const dap_chain_addr_t* a_addr_from, const dap_chain_addr_t* a_addr_to,
                                                     const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-                                                    uint256_t a_value);
+                                                    uint256_t a_value,uint256_t a_value_fee,uint32_t *a_tx_out_prev_idx,uint256_t *a_value_change);
-- 
GitLab