From 1c863c545933b4c3920a70707daa518ab29ab8b9 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Wed, 30 Mar 2022 23:19:56 +0300
Subject: [PATCH] [+] API for bridge emissions

---
 dap-sdk/crypto/src/dap_uuid.c                 |  13 ++
 modules/common/dap_chain_datum_token.c        |  57 +++++---
 .../common/include/dap_chain_datum_token.h    |  28 ++--
 modules/mempool/dap_chain_mempool.c           |  36 +++--
 modules/mempool/include/dap_chain_mempool.h   |   6 +-
 modules/net/dap_chain_node_cli_cmd.c          | 137 ++++++++++--------
 6 files changed, 173 insertions(+), 104 deletions(-)

diff --git a/dap-sdk/crypto/src/dap_uuid.c b/dap-sdk/crypto/src/dap_uuid.c
index ac4a130496..9afa343389 100644
--- a/dap-sdk/crypto/src/dap_uuid.c
+++ b/dap-sdk/crypto/src/dap_uuid.c
@@ -73,3 +73,16 @@ uint64_t dap_uuid_generate_uint64()
    //         l_input[0],l_input[1],l_input[2],l_input[3]);
     return l_output;
 }
+
+void dap_uuid_generate_nonce(void *a_nonce, size_t a_nonce_size)
+{
+    if (!a_nonce || !a_none_size)
+        return;
+    uint32_t l_input[4] ={
+        [0] = random_uint32_t(UINT32_MAX),
+        [1] = time(NULL),
+        [2] = atomic_fetch_add(&s_global_counter, 1),
+        [3] = random_uint32_t(UINT32_MAX)
+    };
+    SHAKE128((unsigned char *)a_nonce, a_nonce_size, (unsigned char *)l_input, sizeof(l_input));
+}
diff --git a/modules/common/dap_chain_datum_token.c b/modules/common/dap_chain_datum_token.c
index 5dc8b7d004..a1069379ba 100644
--- a/modules/common/dap_chain_datum_token.c
+++ b/modules/common/dap_chain_datum_token.c
@@ -261,6 +261,18 @@ err:
 
 }
 
+dap_chain_datum_token_emission_t *dap_chain_datum_emission_create(uint256_t a_value, const char *a_ticker, dap_chain_addr_t *a_addr)
+{
+    dap_chain_datum_token_emission_t *l_emission = DAP_NEW_Z(dap_chain_datum_token_emission_t);
+    l_emission->hdr.version = 2;
+    l_emission->hdr.value_256 = a_value;
+    strncpy(l_emission->hdr.ticker, a_ticker, DAP_CHAIN_TICKER_SIZE_MAX - 1);
+    l_emission->hdr.ticker[DAP_CHAIN_TICKER_SIZE_MAX - 1] = '\0';
+    l_emission->hdr.type = DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH;
+    memcpy(&l_emission->hdr.address, a_addr, sizeof(l_emission->hdr.address));
+    dap_uuid_generate_nonce(&l_emission->hdr.nonce, DAP_CHAIN_DATUM_NONCE_SIZE);
+}
+
 size_t dap_chain_datum_emission_get_size(uint8_t *a_emission_serial)
 {
     size_t l_ret = 0;
@@ -270,24 +282,11 @@ size_t dap_chain_datum_emission_get_size(uint8_t *a_emission_serial)
     } else {
         l_ret = sizeof(l_emission->hdr);
     }
-    switch (l_emission->hdr.type) {
-        case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH: {
-            uint64_t l_size = *(uint64_t *)(a_emission_serial + l_ret);
-            l_ret += l_size;
-        } break;
-        case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ALGO:
-            l_ret += sizeof(l_emission->data.type_algo);
-            break;
-        case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ATOM_OWNER:
-            l_ret += sizeof(l_emission->data.type_atom_owner);
-            break;
-        case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_SMART_CONTRACT:
-            l_ret += sizeof(l_emission->data.type_presale);
-            break;
-        case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_UNDEFINED:
-        default:
-            break;
+    if (l_emission->hdr.type == DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH) {
+        uint64_t l_size = *(uint64_t *)(a_emission_serial + l_ret);
+        l_ret += l_size;
     }
+    l_ret += sizeof(l_emission->data);
     return l_ret;
 }
 
@@ -319,18 +318,34 @@ dap_chain_datum_token_emission_t *dap_chain_datum_emission_read(byte_t *a_emissi
     return l_emission;
 }
 
-dap_chain_datum_token_emission_t *dap_chain_datum_emission_add_sign(dap_chain_datum_token_emission_t *a_emission, dap_enc_key_t *a_sign_key)
+dap_chain_datum_token_emission_t *dap_chain_datum_emission_add_tsd(dap_chain_datum_token_emission_t *a_emission, int a_type, size_t a_size, void *a_data)
 {
+    if (!a_emission || a_emission->hdr.type != DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH)
+        return NULL;
+    dap_tsd_t *l_tsd = dap_tsd_create(a_type, a_data, a_size);
+    size_t l_tsd_size = sizeof(dap_tsd_t) + a_size;
+    size_t l_emission_size = dap_chain_datum_emission_get_size((uint8_t *)a_emission);
+    dap_chain_datum_token_emission_t *l_emission = DAP_REALLOC(a_emission, l_emission_size + l_tsd_size);
+    memcpy(l_emission->tsd_n_signs + l_emission->data.type_auth.tsd_total_size, l_tsd, l_tsd_size);
+    DAP_DELETE(l_tsd);
+    l_emission->data.type_auth.tsd_total_size += l_tsd_size;
+    return l_emission;
+}
+
+dap_chain_datum_token_emission_t *dap_chain_datum_emission_add_sign(dap_enc_key_t *a_sign_key, dap_chain_datum_token_emission_t *a_emission)
+{
+    if (!a_emission)
+        return NULL;
     size_t l_emission_size = dap_chain_datum_emission_get_size((uint8_t *)a_emission);
-    dap_chain_datum_token_emission_t *l_ret = dap_chain_datum_emission_read((uint8_t *)a_emission, &l_emission_size);
-    dap_sign_t *l_sign = dap_sign_create(a_sign_key, l_ret, l_emission_size, 0);
+    dap_sign_t *l_sign = dap_sign_create(a_sign_key, l_ret, sizeof(l_ret->hdr), 0);
     if (!l_sign)
         return NULL;
     l_ret = DAP_REALLOC(l_ret, l_emission_size + dap_sign_get_size(l_sign));
     size_t l_sign_size = dap_sign_get_size(l_sign);
-    memcpy((byte_t *)&l_ret->data + l_ret->data.type_auth.size, l_sign, l_sign_size);
+    memcpy(l_ret->tsd_n_signs + l_ret->data.type_auth.size, l_sign, l_sign_size);
     DAP_DELETE(l_sign);
     l_ret->data.type_auth.size += l_sign_size;
+    l_ret->data.type_auth.signs_count++;
     return l_ret;
 }
 
diff --git a/modules/common/include/dap_chain_datum_token.h b/modules/common/include/dap_chain_datum_token.h
index 3f5de21111..db02764436 100644
--- a/modules/common/include/dap_chain_datum_token.h
+++ b/modules/common/include/dap_chain_datum_token.h
@@ -386,11 +386,13 @@ typedef struct dap_chain_datum_token_emission{
             char codename[32];
         } DAP_ALIGN_PACKED type_algo;
         struct {
-            uint16_t signs_count;
             uint64_t size;
-            byte_t  signs[];
+            uint64_t tsd_total_size;
+            uint16_t signs_count;
         } DAP_ALIGN_PACKED type_auth;// Signs if exists
+        byte_t free_space[128];     // For future changes
     } data;
+    byte_t tsd_n_signs[];
 } DAP_ALIGN_PACKED dap_chain_datum_token_emission_t;
 
 // Different emissions type
@@ -399,12 +401,17 @@ typedef struct dap_chain_datum_token_emission{
 #define DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ALGO              0x02
 #define DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ATOM_OWNER        0x03
 #define DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_SMART_CONTRACT    0x04
-// 256
-// #define DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_256_UNDEFINED         0x05
-// #define DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_256_AUTH              0x06
-// #define DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_256_ALGO              0x07
-// #define DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_256_ATOM_OWNER        0x08
-// #define DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_256_SMART_CONTRACT    0x09
+
+// TSD sections with emission additional params for AUTH type
+#define DAP_CHAIN_DATUM_EMISSION_TSD_TYPE_UNKNOWN           0x0000
+#define DAP_CHAIN_DATUM_EMISSION_TSD_TYPE_TIMESTAMP         0x0001
+#define DAP_CHAIN_DATUM_EMISSION_TSD_TYPE_ADDRESS           0x0002
+#define DAP_CHAIN_DATUM_EMISSION_TSD_TYPE_VALUE             0x0003
+#define DAP_CHAIN_DATUM_EMISSION_TSD_TYPE_CONTRACT          0x0004
+#define DAP_CHAIN_DATUM_EMISSION_TSD_TYPE_NET_ID            0x0005
+#define DAP_CHAIN_DATUM_EMISSION_TSD_TYPE_BLOCK_NUM         0x0006
+#define DAP_CHAIN_DATUM_EMISSION_TSD_TYPE_TOKEN_SYM         0x0007
+
 extern const char *c_dap_chain_datum_token_emission_type_str[];
 
 /// TDS op funcs
@@ -413,8 +420,11 @@ void dap_chain_datum_token_flags_dump(dap_string_t * a_str_out, uint16_t a_flags
 void dap_chain_datum_token_certs_dump(dap_string_t * a_str_out, byte_t * a_data_n_tsd, size_t a_certs_size);
 dap_sign_t ** dap_chain_datum_token_simple_signs_parse(dap_chain_datum_token_t * a_datum_token, size_t a_datum_token_size, size_t *a_signs_count, size_t * a_signs_valid);
 dap_chain_datum_token_t *dap_chain_datum_token_read(byte_t *a_token_serial, size_t *a_token_size);
+
+dap_chain_datum_token_emission_t *dap_chain_datum_emission_create(uint256_t a_value, const char *a_ticker, dap_chain_addr_t *a_addr);
+dap_chain_datum_token_emission_t *dap_chain_datum_emission_add_tsd(dap_chain_datum_token_emission_t *a_emission, int a_type, size_t a_size, void *a_data);
 dap_chain_datum_token_emission_t *dap_chain_datum_emission_read(byte_t *a_emission_serial, size_t *a_emission_size);
 size_t dap_chain_datum_emission_get_size(uint8_t *a_emission_serial);
-dap_chain_datum_token_emission_t *dap_chain_datum_emission_add_sign(dap_chain_datum_token_emission_t *a_emission, dap_enc_key_t *a_sign_key);
+dap_chain_datum_token_emission_t *dap_chain_datum_emission_add_sign(dap_enc_key_t *a_sign_key, dap_chain_datum_token_emission_t *a_emission);
 // 256 TYPE
 bool dap_chain_datum_token_is_old(uint8_t a_type);
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index c392357992..bb13a77c4d 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -93,8 +93,8 @@ char *dap_chain_mempool_datum_add(const dap_chain_datum_t *a_datum, dap_chain_t
     if (dap_chain_global_db_gr_set(l_key_str, a_datum, dap_chain_datum_size(a_datum), l_gdb_group)) {
         log_it(L_NOTICE, "Datum with data's hash %s was placed in mempool", l_key_str);
     } else {
-        log_it(L_WARNING, "Can't place data's hash %s was placed in mempool", l_key_str);
-        DAP_DELETE(l_key_str);
+        log_it(L_WARNING, "Can't place data's hash %s in mempool", l_key_str);
+        DAP_DEL_Z(l_key_str);
     }
 
     DAP_DELETE(l_gdb_group);
@@ -588,8 +588,8 @@ dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond(dap_chain_net_t * a_net,
 }
 
 dap_chain_hash_fast_t *dap_chain_mempool_base_tx_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,
-                                                        dap_chain_addr_t *a_addr_to, dap_cert_t *a_certs, size_t a_certs_count)
+                                                        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_cert_t **a_certs, size_t a_certs_count)
 {
     char *l_gdb_group_mempool_base_tx = dap_chain_net_get_gdb_group_mempool(a_chain);
     // create first transaction (with tx_token)
@@ -598,7 +598,7 @@ dap_chain_hash_fast_t *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, da
     dap_chain_hash_fast_t l_tx_prev_hash = { 0 };
     // create items
 
-    dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(a_emission_chain_id, a_emission_hash, l_ticker);
+    dap_chain_tx_token_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);
 
@@ -607,13 +607,11 @@ dap_chain_hash_fast_t *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, da
     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);
 
-    if (a_certs){
+    if (a_certs) {
         // Sign all that we have with certs
         for(size_t i = 0; i < a_certs_count; i++) {
             if(dap_chain_datum_tx_add_sign_item(&l_tx, a_certs[i]->enc_key) < 0) {
-                dap_chain_node_cli_set_reply_text(a_str_reply, "No private key for certificate=%s",
-                        a_certs[i]->name);
-                DAP_DELETE(l_addr);
+                log_it(L_WARNING, "No private key for certificate '%s'", a_certs[i]->name);
                 return NULL;
             }
         }
@@ -644,6 +642,26 @@ dap_chain_hash_fast_t *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, da
     return l_datum_tx_hash;
 }
 
+dap_chain_datum_token_emission_t *dap_chain_mempool_emission_get(dap_chain_t *a_chain, const char *a_emission_hash_str)
+{
+    size_t l_emission_size;
+    char *l_gdb_group = dap_chain_net_get_gdb_group_mempool(a_chain);
+    dap_chain_datum_t *l_emission = (dap_chain_datum_t *)dap_chain_global_db_gr_get(
+                                                    l_emission_hash_str, &l_emission_size, l_gdb_group);
+    if (!l_emission) {
+        char *l_emission_hash_str_from_base58 = dap_enc_base58_to_hex_str_from_str(a_emission_hash_str);
+        l_emission = (dap_chain_datum_t *)dap_chain_global_db_gr_get(
+                                    l_emission_hash_str_from_base58, &l_emission_size, l_gdb_group);
+        DAP_DELETE(l_emission_hash_str_from_base58);
+    }
+    DAP_DELETE(l_gdb_group);
+    if (!l_emission)
+        return NULL;
+    dap_chain_datum_token_emission_t *l_ret = dap_chain_datum_emission_read(l_emission->data, &l_emission_size);
+    DAP_DELETE(l_emission);
+    return l_ret;
+}
+
 uint8_t* dap_datum_mempool_serialize(dap_datum_mempool_t *datum_mempool, size_t *size)
 {
     size_t a_request_size = 2 * sizeof(uint16_t), shift_size = 0;
diff --git a/modules/mempool/include/dap_chain_mempool.h b/modules/mempool/include/dap_chain_mempool.h
index c9db3876ff..a89a68be4b 100644
--- a/modules/mempool/include/dap_chain_mempool.h
+++ b/modules/mempool/include/dap_chain_mempool.h
@@ -68,5 +68,7 @@ int dap_chain_mempool_tx_create_massive(dap_chain_t * a_chain, dap_enc_key_t *a_
         uint256_t a_value, uint256_t a_value_fee, size_t a_tx_num);
 
 dap_chain_hash_fast_t *dap_chain_mempool_base_tx_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,
-                                                        dap_chain_addr_t *a_addr_to, dap_cert_t *a_certs, size_t a_certs_count);
+                                                        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_cert_t **a_certs, size_t a_certs_count);
+dap_chain_datum_token_emission_t *dap_chain_mempool_emission_get(dap_chain_t *a_chain, const char *a_emission_hash_str);
+
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 1cd965b421..0234781cec 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -3238,7 +3238,7 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
     const char * l_addr_str = NULL;
 
     const char * l_emission_hash_str = NULL;
-    dap_chain_hash_fast_t l_emission_hash;
+    dap_chain_hash_fast_t l_emission_hash, l_datum_emission_hash;
     dap_chain_datum_token_emission_t *l_emission = NULL;
     size_t l_emission_size;
 
@@ -3337,15 +3337,8 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
         }
     } else {
         if (l_emission_hash_str) {
-            char *l_emission_hash_str_from_base58 = dap_enc_base58_to_hex_str_from_str(l_emission_hash_str);
-            DL_FOREACH(l_net->pub.chains, l_chain_emission) {
-
-                l_emission = (dap_chain_datum_token_emission_t *)dap_chain_global_db_gr_get(
-                            l_emission_hash_str, &l_emission_size, dap_chain_net_get_gdb_group_mempool(l_chain_emission));
-                if (l_emission)
-                    break;
-                l_emission = (dap_chain_datum_token_emission_t *)dap_chain_global_db_gr_get(
-                            l_emission_hash_str_from_base58, &l_emission_size, dap_chain_net_get_gdb_group_mempool(l_chain_emission));
+            DL_FOREACH(a_net->pub.chains, l_chain_emission) {
+                l_emission = dap_chain_mempool_emission_get(l_chain_emission, l_emission_hash_str);
                 if (l_emission)
                     break;
             }
@@ -3369,54 +3362,42 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
             DAP_DELETE(l_addr);
             return -47;
         }
+        if(!l_ticker) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "token_emit requires parameter '-token'");
+            return -3;
+        }
     }
 
+    //dap_chain_mempool_emission_create(l_emission, DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH, l_ticker, l_emission_value);
     if (!l_add_sign) {
-        // Create emission datum
-        if (!l_chain_emission) {
+        if (!l_chain_emission)
             l_chain_emission = dap_chain_net_get_chain_by_chain_type(l_net, CHAIN_TYPE_EMISSION);
-        }
-        l_emission = DAP_NEW_Z(dap_chain_datum_token_emission_t);
-        l_emission->hdr.version = 2;
-        l_emission->hdr.value_256 = l_emission_value;
-        strncpy(l_emission->hdr.ticker, l_ticker, sizeof(l_emission->hdr.ticker) - 1);
-        l_emission->hdr.type = DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH;
-        memcpy(&l_emission->hdr.address, l_addr, sizeof(l_emission->hdr.address));
-        time_t l_time = time(NULL);
-        memcpy(&l_emission->hdr.nonce, &l_time, sizeof(time_t));
-        l_emission_size = sizeof(l_emission->hdr) + sizeof(l_emission->data.type_auth);
+        // Create emission datum
+        l_emission = dap_chain_datum_emission_create(l_emission_value, l_ticker, l_addr);
     }
     l_emission->data.type_auth.signs_count += l_certs_size;
     // Then add signs
-    for(size_t i = 0; i < l_certs_size; i++) {
-        dap_sign_t *l_sign = dap_cert_sign(l_certs[i], &l_emission->hdr,
-                sizeof(l_emission->hdr), 0);
-        size_t l_sign_size = dap_sign_get_size(l_sign);
-        l_emission_size += l_sign_size;
-        l_emission->data.type_auth.size += l_sign_size;
-        l_emission = DAP_REALLOC(l_emission, l_emission_size);
-        memcpy(l_emission->data.type_auth.signs + l_emission->data.type_auth.size, l_sign, l_sign_size);
-        DAP_DELETE(l_sign);
-    }
-
+    for(size_t i = 0; i < l_certs_size; i++)
+        l_emission = dap_chain_datum_emission_add_sign(l_certs[i]->enc_key, l_emission);
+    // Calc emission's hash
+    l_emission_size = dap_chain_datum_emission_get_size(l_emission);
+    dap_hash_fast(l_emission, l_emission_size, &l_emission_hash);
     // Produce datum
     dap_chain_datum_t *l_datum_emission = dap_chain_datum_create(DAP_CHAIN_DATUM_TOKEN_EMISSION,
             l_emission,
             l_emission_size);
+    // Delete token emission
+    DAP_DEL_Z(l_emission);
     size_t l_datum_emission_size = sizeof(l_datum_emission->header) + l_datum_emission->header.data_size;
 
     // Calc datum emission's hash
-    dap_hash_fast(l_datum_emission, l_datum_emission_size, &l_emission_hash);
-    // Calc token's hash
-    dap_hash_fast(l_emission, l_emission_size, &l_token_emission_hash);
-
+    dap_hash_fast(l_datum_emission, l_datum_emission_size, &l_datum_emission_hash);
     bool l_hex_format = dap_strcmp(l_hash_out_type, "hex");
-    l_emission_hash_str = l_hex_format ? dap_chain_hash_fast_to_str_new(&l_emission_hash)
-                                       : dap_enc_base58_encode_hash_to_str(&l_emission_hash);
-    // Delete token emission
-    DAP_DEL_Z(l_emission);
+    l_emission_hash_str = l_hex_format ? dap_chain_hash_fast_to_str_new(&l_datum_emission_hash)
+                                       : dap_enc_base58_encode_hash_to_str(&l_datum_emission_hash);
     // Add token emission datum to mempool
-    bool l_placed = dap_chain_global_db_gr_set(dap_strdup(l_emission_hash_str),
+    char *l_gdb_group_mempool_emission = dap_chain_net_get_gdb_group_mempool(l_chain_emission);
+    bool l_placed = dap_chain_global_db_gr_set(l_emission_hash_str,
                                                (uint8_t *)l_datum_emission,
                                                l_datum_emission_size,
                                                l_gdb_group_mempool_emission);
@@ -3431,7 +3412,7 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
 
     if(l_chain_base_tx) {
         dap_chain_hash_fast_t *l_datum_tx_hash = dap_chain_mempool_base_tx_create(l_chain_base_tx, &l_emission_hash,
-                                                                l_chain_emission->id, l_emission_value,
+                                                                l_chain_emission->id, l_emission_value, l_ticker,
                                                                 l_addr, l_certs, l_certs_size);
         char *l_tx_hash_str = l_hex_format ? dap_chain_hash_fast_to_str_new(l_datum_tx_hash)
                                            : dap_enc_base58_encode_hash_to_str(l_datum_tx_hash);
@@ -3826,8 +3807,12 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
     const char * l_token_ticker = NULL;
     const char * l_net_name = NULL;
     const char * l_chain_name = NULL;
+    const char * l_emission_chain_name = NULL;
     const char * l_tx_num_str = NULL;
     const char *l_emission_hash_str = NULL;
+    const char *l_certs_str = NULL;
+    dap_cert_t **l_certs = NULL;
+    size_t l_certs_count = 0;
     dap_chain_hash_fast_t l_emission_hash = {};
     size_t l_tx_num = 0;
 
@@ -3835,11 +3820,13 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
     uint256_t l_value_fee = {};
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name);
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-from_emission", &l_emission_hash_str);
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-emission_chain", &l_emission_chain_name);
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to);
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name);
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-tx_num", &l_tx_num_str);
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-certs", &l_certs_str);
 
     if(l_tx_num_str)
         l_tx_num = strtoul(l_tx_num_str, NULL, 10);
@@ -3860,17 +3847,45 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
         dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-to_addr'");
         return -2;
     }
+
+    if(!l_net_name) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-net'");
+        return -6;
+    }
+    dap_chain_net_t * l_net = dap_chain_net_by_name(l_net_name);
+    dap_ledger_t *l_ledger = l_net ? l_net->pub.ledger : NULL;
+    if(l_net == NULL || (l_ledger = dap_chain_ledger_by_net_name(l_net_name)) == NULL) {
+        dap_chain_node_cli_set_reply_text(str_reply, "not found net by name '%s'", l_net_name);
+        return -7;
+    }
+
+    dap_chain_t *l_emission_chain;
     if (l_emission_hash_str) {
         if (dap_chain_hash_fast_from_str(l_emission_hash_str, &l_emission_hash)) {
             dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-emission_hash' "
                                                          "to be valid string containing hash in hex or base58 format");
             return -3;
         }
-    } else {
-        if(IS_ZERO_256(l_value)) {
-            dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-value' to be valid uint256 value");
+        if (!l_emission_chain_name ||
+                (l_emission_chain = dap_chain_net_get_chain_by_name(l_net, l_emission_chain_name)) == NULL) {
+            dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-emission_chain' "
+                                                         "to be a valid chain name");
+            return -9;
+        }
+        if(!l_certs_str) {
+            dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-certs'");
             return -4;
         }
+        dap_cert_parse_str_list(l_certs_str, &l_certs, &l_certs_count);
+        if(!l_certs_count) {
+            dap_chain_node_cli_set_reply_text(str_reply,
+                    "tx_create requires at least one valid certificate to sign the basic transaction of emission");
+            return -5;
+        }
+    }
+    if(IS_ZERO_256(l_value)) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-value' to be valid uint256 value");
+        return -4;
     }
     if(addr_base58_fee && IS_ZERO_256(l_value_fee)) {
         dap_chain_node_cli_set_reply_text(str_reply,
@@ -3878,17 +3893,6 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
         return -5;
     }
 
-    if(!l_net_name) {
-        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-net'");
-        return -6;
-    }
-    dap_chain_net_t * l_net = dap_chain_net_by_name(l_net_name);
-    dap_ledger_t *l_ledger = l_net ? l_net->pub.ledger : NULL;
-    if(l_net == NULL || (l_ledger = dap_chain_ledger_by_net_name(l_net_name)) == NULL) {
-        dap_chain_node_cli_set_reply_text(str_reply, "not found net by name '%s'", l_net_name);
-        return -7;
-    }
-
     dap_chain_t * l_chain = dap_chain_net_get_chain_by_name(l_net, l_chain_name);
     if(!l_chain) {
         l_chain = dap_chain_net_get_chain_by_chain_type(l_net, CHAIN_TYPE_TX);
@@ -3908,7 +3912,8 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
     dap_string_t *string_ret = dap_string_new(NULL);
     int res = 0;
     if (l_emission_hash_str) {
-        dap_hash_fast_t *l_tx_hash = dap_chain_mempool_base_tx_create(l_chain, &l_emission_hash, l_addr_to);
+        dap_hash_fast_t *l_tx_hash = dap_chain_mempool_base_tx_create(l_chain, &l_emission_hash, l_emission_chain->id,
+                                                                      l_value, l_token_ticker, l_addr_to, l_certs, l_certs_count);
         if (l_tx_hash){
             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)-1);
@@ -4013,20 +4018,26 @@ int com_tx_verify(int a_argc, char **a_argv, char **a_str_reply)
         *a_str_reply = NULL;
     }
     dap_hash_fast_t l_tx_hash;
-    if (dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash)) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "Invalid tx hash format, need hex or base58");
-        return -3;
+    char *l_hex_str_from58 = NULL;
+    if (dap_chain_hash_fast_from_hex_str(l_tx_hash_str, &l_tx_hash)) {
+        l_hex_str_from58 = dap_enc_base58_to_hex_str_from_str(l_tx_hash_str);
+        if (dap_chain_hash_fast_from_hex_str(l_hex_str_from58, &l_tx_hash)) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Invalid tx hash format, need hex or base58");
+            return -3;
+        }
     }
     size_t l_tx_size = 0;
     char *l_gdb_group = dap_chain_net_get_gdb_group_mempool(l_chain);
     dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)
             dap_chain_global_db_gr_get(l_hex_str_from58 ? l_hex_str_from58 : l_tx_hash_str, &l_tx_size, l_gdb_group);
+    DAP_DEL_Z(l_hex_str_from58);
     if (!l_tx) {
         dap_chain_node_cli_set_reply_text(a_str_reply, "Specified tx not found");
         return -3;
     }
-    if (dap_chain_ledger_tx_add_check(l_net->pub.ledger, l_tx)) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "Specified tx verify fail!");
+    int l_ret = dap_chain_ledger_tx_add_check(l_net->pub.ledger, l_tx);
+    if (l_ret) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "Specified tx verify fail with return code=%d", l_ret);
         return -4;
     }
     dap_chain_node_cli_set_reply_text(a_str_reply, "Specified tx verified successfully");
-- 
GitLab