diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index 742f44df087d93246d4508c07dfca9c83758feb9..5007e84720ff8993d91eadfc01c47952ca7dc222 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -271,6 +271,7 @@ typedef struct dap_ledger_private {
     const char *net_native_ticker;
     uint256_t fee_value;
     dap_chain_addr_t fee_addr;
+    dap_list_t *poa_certs;
     // List of ledger - unspent transactions cache
     dap_chain_ledger_tx_item_t *threshold_txs;
     dap_chain_ledger_token_emission_item_t * threshold_emissions;
@@ -2427,12 +2428,13 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger)
  * @param a_net_name char * network name, for example "kelvin-testnet"
  * @return dap_ledger_t*
  */
-dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const char *a_net_native_ticker)
+dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const char *a_net_native_ticker, dap_list_t *a_poa_certs)
 {
     dap_ledger_t *l_ledger = dap_chain_ledger_handle_new();
     l_ledger->net_name = a_net_name;
     dap_ledger_private_t *l_ledger_pvt = PVT(l_ledger);
     l_ledger_pvt->net_native_ticker = a_net_native_ticker;
+    l_ledger_pvt->poa_certs = a_poa_certs;
     l_ledger_pvt->flags = a_flags;
     l_ledger_pvt->check_ds = a_flags & DAP_CHAIN_LEDGER_CHECK_LOCAL_DS;
     l_ledger_pvt->check_cells_ds = a_flags & DAP_CHAIN_LEDGER_CHECK_CELLS_DS;
@@ -3339,6 +3341,19 @@ bool s_tx_match_sign(dap_chain_datum_token_emission_t *a_datum_emission, dap_cha
     return false;
 }
 
+static int s_callback_sign_compare(const void *a, const void *b)
+{
+    return !dap_pkey_match_sign((dap_pkey_t *)a, (dap_sign_t *)b);
+}
+
+bool dap_chain_ledger_tx_poa_signed(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
+{
+    dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_SIG, NULL);
+    dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig);
+    return dap_list_find_custom(PVT(a_ledger)->poa_certs, l_sign, s_callback_sign_compare);
+}
+
+
 /**
  * Checking a new transaction before adding to the cache
  *
@@ -3993,12 +4008,15 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
 
     // 7. Check the network fee
     if (l_fee_check && compare256(l_fee_sum, l_ledger_pvt->fee_value) == -1) {
-        char *l_current_fee = dap_chain_balance_to_coins(l_fee_sum);
-        char *l_expected_fee = dap_chain_balance_to_coins(l_ledger_pvt->fee_value);
-        log_it(L_ERROR, "Fee value is invalid, expected %s pointed %s", l_expected_fee, l_current_fee);
-        l_err_num = -55;
-        DAP_DEL_Z(l_current_fee);
-        DAP_DEL_Z(l_expected_fee);
+        // Check for PoA-cert-signed "service" no-tax tx
+        if (!dap_chain_ledger_tx_poa_signed(a_ledger, a_tx)) {
+            char *l_current_fee = dap_chain_balance_to_coins(l_fee_sum);
+            char *l_expected_fee = dap_chain_balance_to_coins(l_ledger_pvt->fee_value);
+            log_it(L_ERROR, "Fee value is invalid, expected %s pointed %s", l_expected_fee, l_current_fee);
+            l_err_num = -55;
+            DAP_DEL_Z(l_current_fee);
+            DAP_DEL_Z(l_expected_fee);
+        }
     }
 
     if (a_main_ticker && !l_err_num)
diff --git a/modules/chain/include/dap_chain_ledger.h b/modules/chain/include/dap_chain_ledger.h
index 14297dfd44595f6dabbea39ea0e0f187a0b955bb..f8005b2ecace918bbf51f3073dcca4dd40c1227b 100644
--- a/modules/chain/include/dap_chain_ledger.h
+++ b/modules/chain/include/dap_chain_ledger.h
@@ -131,7 +131,7 @@ typedef struct dap_chain_net dap_chain_net_t;
 int dap_chain_ledger_init();
 void dap_chain_ledger_deinit();
 
-dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const char *a_net_native_ticker);
+dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const char *a_net_native_ticker, dap_list_t *a_poa_certs);
 
 void dap_chain_ledger_set_fee(dap_ledger_t *a_ledger, uint256_t a_fee, dap_chain_addr_t a_fee_addr);
 
@@ -236,6 +236,8 @@ void dap_chain_ledger_addr_get_token_ticker_all_depricated(dap_ledger_t *a_ledge
 void dap_chain_ledger_addr_get_token_ticker_all(dap_ledger_t *a_ledger, dap_chain_addr_t * a_addr,
         char *** a_tickers, size_t * a_tickers_size);
 
+bool dap_chain_ledger_tx_poa_signed(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx);
+
 // Checking a new transaction before adding to the cache
 int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash,
                                     bool a_from_threshold, dap_list_t **a_list_bound_items, dap_list_t **a_list_tx_out, char **a_main_ticker);
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index c438ca2e17e297014a600981de0665e688c8fea6..a3478c334bd8c53b9ff603de72679dd5e22763a1 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -840,9 +840,10 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast
     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_to_fee);
-    if(l_net_fee_used)
-        SUM_256_256(l_total_fee,l_net_fee,&l_total_fee);
+    bool l_net_fee_used = IS_ZERO_256(a_value_fee) ? false :
+                                                     dap_chain_net_tx_get_fee(a_chain->net_id, &l_net_fee, &l_addr_to_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);
@@ -855,14 +856,14 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast
         dap_chain_datum_tx_delete(l_tx);
         return NULL;
     }
-    if (not_native)
+    if (not_native && !IS_ZERO_256(l_total_fee))
     {
         if (dap_chain_addr_fill_from_key(&l_addr_from_fee, a_private_key, a_chain->net_id) != 0 ) {
             log_it(L_WARNING,"Can't fill address from transfer");
             dap_chain_datum_tx_delete(l_tx);
             return NULL;
         }
-            // list of transaction with 'out' items
+        // 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_fee, l_total_fee, &l_value_transfer);
         if (!l_list_used_out) {
@@ -878,45 +879,50 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast
         }
          //add out
         uint256_t l_value_back = l_value_transfer; // how much datoshi add to 'out' items
-         // Network fee
-        if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_to_fee, l_net_fee, l_native_ticker)){
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
+        // Network fee
+        if (l_net_fee_used) {
+            SUBTRACT_256_256(l_value_back, l_net_fee, &l_value_back);
+            if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_to_fee, l_net_fee, l_native_ticker)){
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
         }
-        SUBTRACT_256_256(l_value_back, l_net_fee, &l_value_back);
-        if (!IS_ZERO_256(a_value_fee))
+        if (!IS_ZERO_256(a_value_fee)) {
             SUBTRACT_256_256(l_value_back, a_value_fee, &l_value_back);
+            if (!dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee)){
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
         // coin back
-        if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_from_fee, l_value_back, l_native_ticker)){
+        if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_from_fee, l_value_back, l_native_ticker)) {
             dap_chain_datum_tx_delete(l_tx);
             return NULL;
         }
-
-        if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to, l_value_need, a_ticker)){
+        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 { //native ticker
-        if (!IS_ZERO_256(a_value_fee))
+        if (!IS_ZERO_256(a_value_fee)) {
             SUBTRACT_256_256(l_value_need, a_value_fee, &l_value_need);
-        if(l_net_fee_used){
+            if (!dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee)){
+                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_to_fee, l_net_fee)){
+            if (!dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_to_fee, l_net_fee)) {
                 dap_chain_datum_tx_delete(l_tx);
                 return NULL;
             }
         }
-        if (!dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, 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 (!IS_ZERO_256(a_value_fee)){
-        if (!dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee)){
-            dap_chain_datum_tx_delete(l_tx);
-            return NULL;
-        }
-    }
     //sign item
     if(dap_chain_datum_tx_add_sign_item(&l_tx, a_private_key) < 0) {
         log_it(L_WARNING, "No private key for sign");
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 2b7829a57e0ba2838e5f660a42ce71fd4141bc2d..be375efd104acf6995bfddc02d4e9486b629cfa8 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -2300,8 +2300,18 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx)
         default:
             l_ledger_flags |= DAP_CHAIN_LEDGER_CHECK_CELLS_DS;
         }
+        dap_list_t *l_net_keys = NULL;
+        for (dap_chain_t *l_chain = l_net->pub.chains; l_chain; l_chain = l_chain->next) {
+            if (!l_chain->callback_get_poa_certs)
+                continue;
+            l_net_keys = l_chain->callback_get_poa_certs(l_chain, NULL, NULL);
+            if (l_net_keys)
+                break;
+        }
+        if (!l_net_keys)
+            log_it(L_WARNING,"PoA certificates for net %s not found.", l_net->pub.name);
         // init LEDGER model
-        l_net->pub.ledger = dap_chain_ledger_create(l_ledger_flags, l_net->pub.name, l_net->pub.native_ticker);
+        l_net->pub.ledger = dap_chain_ledger_create(l_ledger_flags, l_net->pub.name, l_net->pub.native_ticker, l_net_keys);
         // Check if seed nodes are present in local db alias
         char **l_seed_aliases = dap_config_get_array_str(l_cfg, "general", "seed_nodes_aliases",
                                                          &l_net_pvt->seed_aliases_count);
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index b7eabde8dc274e538785639794edc1f723b85291..f03f7a412d539fe2e72838c10bdd90a376c78d50 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -257,19 +257,25 @@ void dap_chain_node_mempool_process_all(dap_chain_t *a_chain, bool a_force)
                 if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX &&
                         a_chain->callback_get_minimum_fee){
                     uint256_t l_tx_fee = {};
-                    if (dap_chain_datum_tx_get_fee_value ((dap_chain_datum_tx_t*)l_datum->data, &l_tx_fee)) {
-                        log_it(L_WARNING, "Can't get fee value from tx");
-                        continue;
-                    }
-                    uint256_t l_min_fee = a_chain->callback_get_minimum_fee(a_chain);
-                    if (compare256(l_tx_fee, l_min_fee) < 0) {
-                        char *l_tx_fee_str = dap_chain_balance_to_coins(l_tx_fee);
-                        char *l_min_fee_str = dap_chain_balance_to_coins(l_min_fee);
-                        log_it(L_WARNING, "Fee %s is lower than minimum fee %s for tx %s",
-                               l_tx_fee_str, l_min_fee_str, l_objs[i].key);
-                        DAP_DELETE(l_tx_fee_str);
-                        DAP_DELETE(l_min_fee_str);
-                        continue;
+                    dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
+                    if (dap_chain_datum_tx_get_fee_value (l_tx, &l_tx_fee) ||
+                            IS_ZERO_256(l_tx_fee)) {
+                        if (!dap_chain_ledger_tx_poa_signed(l_net->pub.ledger, l_tx)) {
+                            log_it(L_WARNING, "Can't get fee value from tx");
+                            continue;
+                        } else
+                            log_it(L_DEBUG, "Process service tx without fee");
+                    } else {
+                        uint256_t l_min_fee = a_chain->callback_get_minimum_fee(a_chain);
+                        if (compare256(l_tx_fee, l_min_fee) < 0) {
+                            char *l_tx_fee_str = dap_chain_balance_to_coins(l_tx_fee);
+                            char *l_min_fee_str = dap_chain_balance_to_coins(l_min_fee);
+                            log_it(L_WARNING, "Fee %s is lower than minimum fee %s for tx %s",
+                                   l_tx_fee_str, l_min_fee_str, l_objs[i].key);
+                            DAP_DELETE(l_tx_fee_str);
+                            DAP_DELETE(l_min_fee_str);
+                            continue;
+                        }
                     }
                 }
 
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 93cd92c2fc65bd5b9dfe2be9553d786b64c571cf..cb47e1ee7d91f14b0ce2dcc39a942a4e30c5e7e6 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -5221,9 +5221,9 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply)
     }
 
     // Validator's fee
-    if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &str_tmp))
+    if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &str_tmp))
         l_value_fee = dap_chain_balance_scan(str_tmp);
-    if (IS_ZERO_256(l_value_fee)) {
+    if (IS_ZERO_256(l_value_fee) && (!l_emission_hash_str || (str_tmp && strcmp(str_tmp, "0")))) {
         dap_cli_server_cmd_set_reply_text(a_str_reply,
                 "tx_create requires parameter '-fee' to be valid uint256");
         return -5;
@@ -5280,38 +5280,24 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply)
             return -9;
         }
 
-        const char *l_native_ticker = l_net->pub.native_ticker;
-        bool not_native = dap_strcmp(l_token_ticker, l_native_ticker);
-
-        if (not_native) {
-            if (l_wallet_fee_name){
-                l_wallet_fee = dap_chain_wallet_open(l_wallet_fee_name, c_wallets_path);
-                if (!l_wallet_fee) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "wallet %s does not exist", l_wallet_fee_name);
-                    return -12;
-                }
-                l_priv_key = dap_chain_wallet_get_key(l_wallet_fee, 0);
-            } else {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "To create a basic transaction with a "
-                                                               "non-native ticker, you must specify the '-wallet_fee' "
-                                                               "parameter. It is required to pay a commission for the "
-                                                               "transaction.");
-                return -11;
+        if (l_wallet_fee_name){
+            l_wallet_fee = dap_chain_wallet_open(l_wallet_fee_name, c_wallets_path);
+            if (!l_wallet_fee) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Wallet %s does not exist", l_wallet_fee_name);
+                return -12;
             }
-        } else {
-            if (l_cert_str) {
-                l_cert = dap_cert_find_by_name(l_cert_str);
-                if (!l_cert) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply,
-                                                      "tx_create requires one valid certificate to sign the basic transaction of emission");
-                    return -5;
-                }
-                l_priv_key = l_cert->enc_key;
-            } else {
-                dap_cli_server_cmd_set_reply_text(a_str_reply,
-                                                  "tx_create requires parameter '-cert' for create base tx for emission in native token");
-                return -10;
+            l_priv_key = dap_chain_wallet_get_key(l_wallet_fee, 0);
+        } else if (l_cert_str) {
+            l_cert = dap_cert_find_by_name(l_cert_str);
+            if (!l_cert) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Certificate %s is invalid", l_cert_str);
+                return -5;
             }
+            l_priv_key = l_cert->enc_key;
+        } else {
+            dap_cli_server_cmd_set_reply_text(a_str_reply,
+                                              "tx_create requires parameter '-cert' or '-wallet' for create base tx for emission");
+            return -10;
         }
     }
 
@@ -5337,7 +5323,6 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply)
     dap_string_t *l_string_ret = dap_string_new(NULL);
     int res = 0;
     if (l_emission_hash_str) {
-        bool not_native = dap_strcmp(l_token_ticker, l_net->pub.native_ticker);
         char *l_tx_hash_str = NULL;
         if (!l_priv_key) {
             dap_string_append_printf(l_string_ret, "No private key defined for creating the underlying "
@@ -5346,7 +5331,7 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply)
         }
         l_tx_hash_str = dap_chain_mempool_base_tx_create(l_chain, &l_emission_hash, l_emission_chain->id,
                                                          l_value, l_token_ticker, l_addr_to, l_priv_key,
-                                                         l_hash_out_type,l_value_fee);
+                                                         l_hash_out_type, l_value_fee);
         if (l_tx_hash_str) {
             dap_string_append_printf(l_string_ret, "\nDatum %s with 256bit TX is placed in datum pool\n", l_tx_hash_str);
             DAP_DELETE(l_tx_hash_str);