From 2fc6f709d9ae124470fad658d0e7cab7d542de3d Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Fri, 28 Feb 2025 18:47:58 +0700 Subject: [PATCH 01/53] [*] Condition owner collect & check corrections --- dap-sdk | 2 +- modules/net/dap_chain_ledger.c | 304 ++++++------------ modules/net/include/dap_chain_ledger.h | 22 +- .../service/voting/dap_chain_net_srv_voting.c | 65 ++-- 4 files changed, 133 insertions(+), 260 deletions(-) diff --git a/dap-sdk b/dap-sdk index d9b03ffb93..3491640b76 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit d9b03ffb93d4003cb1a33c6470612a7f88ad6005 +Subproject commit 3491640b76de5715eb3936ccd377abd51d88b99e diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index 1a883dd8dd..03fcb33ba6 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -288,8 +288,6 @@ typedef struct dap_ledger_private { #define PVT(a) ( (dap_ledger_private_t *) a->_internal ) -static dap_ledger_tx_item_t* tx_item_find_by_addr(dap_ledger_t *a_ledger, - const dap_chain_addr_t *a_addr, const char * a_token, dap_chain_hash_fast_t *a_tx_first_hash); static void s_threshold_emissions_proc( dap_ledger_t * a_ledger); static void s_threshold_txs_proc( dap_ledger_t * a_ledger); static void s_threshold_txs_free(dap_ledger_t *a_ledger); @@ -5273,8 +5271,8 @@ uint256_t dap_ledger_calc_balance_full(dap_ledger_t *a_ledger, const dap_chain_a * a_public_key_size[in] public key size * a_tx_first_hash [in/out] hash of the initial transaction/ found transaction, if 0 start from the beginning */ -static dap_ledger_tx_item_t *tx_item_find_by_addr(dap_ledger_t *a_ledger, const dap_chain_addr_t *a_addr, - const char * a_token, dap_chain_hash_fast_t *a_tx_first_hash) +dap_chain_datum_tx_t *dap_ledger_tx_find_by_addr(dap_ledger_t *a_ledger, const char *a_token, + const dap_chain_addr_t *a_addr, dap_chain_hash_fast_t *a_tx_first_hash) { if(!a_addr || !a_tx_first_hash) return NULL; @@ -5331,20 +5329,7 @@ static dap_ledger_tx_item_t *tx_item_find_by_addr(dap_ledger_t *a_ledger, const break; } pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock); - return is_tx_found ? l_iter_current : NULL; -} - -/** - * @brief dap_ledger_tx_find_by_addr - * @param a_addr - * @param a_tx_first_hash - * @return - */ - dap_chain_datum_tx_t* dap_ledger_tx_find_by_addr(dap_ledger_t *a_ledger , const char * a_token , - const dap_chain_addr_t *a_addr, dap_chain_hash_fast_t *a_tx_first_hash) -{ - dap_ledger_tx_item_t* l_tx_item = tx_item_find_by_addr(a_ledger, a_addr, a_token, a_tx_first_hash); - return (l_tx_item) ? l_tx_item->tx : NULL; + return is_tx_found ? l_iter_current->tx : NULL; } bool dap_ledger_tx_check_recipient(dap_ledger_t* a_ledger, dap_chain_hash_fast_t* a_tx_prev_hash, dap_chain_addr_t *a_addr) @@ -5374,52 +5359,6 @@ static dap_ledger_tx_item_t *tx_item_find_by_addr(dap_ledger_t *a_ledger, const return false; } -/** - * Get the transaction in the cache by the public key that signed the transaction, - * starting from the next hash after a_tx_first_hash - * - * a_public_key[in] public key that signed the transaction - * a_public_key_size[in] public key size - * a_tx_first_hash [in/out] hash of the initial transaction/ found transaction, if 0 start from the beginning - */ -const dap_chain_datum_tx_t* dap_ledger_tx_find_by_pkey(dap_ledger_t *a_ledger, - char *a_public_key, size_t a_public_key_size, dap_chain_hash_fast_t *a_tx_first_hash) -{ - if(!a_public_key || !a_tx_first_hash) - return NULL; - dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger); - dap_chain_datum_tx_t *l_cur_tx = NULL; - bool is_null_hash = dap_hash_fast_is_blank(a_tx_first_hash); - bool is_search_enable = is_null_hash; - dap_ledger_tx_item_t *l_iter_current, *l_item_tmp; - pthread_rwlock_rdlock(&l_ledger_pvt->ledger_rwlock); - HASH_ITER(hh, l_ledger_pvt->ledger_items , l_iter_current, l_item_tmp) { - dap_chain_datum_tx_t *l_tx_tmp = l_iter_current->tx; - dap_chain_hash_fast_t *l_tx_hash_tmp = &l_iter_current->tx_hash_fast; - // start searching from the next hash after a_tx_first_hash - if (!is_search_enable) { - is_search_enable = dap_hash_fast_compare(l_tx_hash_tmp, a_tx_first_hash); - continue; - } - // Get sign item from transaction - dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(l_tx_tmp, NULL, - NULL, TX_ITEM_TYPE_SIG, NULL); - // Get dap_sign_t from item - dap_sign_t *l_sig = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); - if(l_sig) { - // compare public key in transaction with a_public_key - if(a_public_key_size == l_sig->header.sign_pkey_size && - !memcmp(a_public_key, l_sig->pkey_n_sign, a_public_key_size)) { - l_cur_tx = l_tx_tmp; - memcpy(a_tx_first_hash, l_tx_hash_tmp, sizeof(dap_chain_hash_fast_t)); - break; - } - } - } - pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock); - return l_cur_tx; -} - /** * @brief Get all transactions from the cache with the out_cond item * @param a_ledger @@ -5442,93 +5381,6 @@ dap_list_t* dap_ledger_tx_cache_find_out_cond_all(dap_ledger_t *a_ledger, dap_ch return l_ret; } - -/** - * Get the transaction in the cache with the out_cond item - * - * a_addr[in] wallet address, whose owner can use the service - */ -dap_chain_datum_tx_t* dap_ledger_tx_cache_find_out_cond(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type, - dap_chain_hash_fast_t *a_tx_first_hash, dap_chain_tx_out_cond_t **a_out_cond, int *a_out_cond_idx, char *a_token_ticker) -{ - if (!a_tx_first_hash) - return NULL; - dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger); - dap_chain_datum_tx_t *l_cur_tx = NULL; - bool is_null_hash = dap_hash_fast_is_blank(a_tx_first_hash); - bool is_search_enable = is_null_hash; - dap_ledger_tx_item_t *l_iter_current = NULL, *l_item_tmp = NULL; - dap_chain_tx_out_cond_t *l_tx_out_cond = NULL; - int l_tx_out_cond_idx = 0; - pthread_rwlock_rdlock(&l_ledger_pvt->ledger_rwlock); - HASH_ITER(hh, l_ledger_pvt->ledger_items, l_iter_current, l_item_tmp) { - dap_chain_datum_tx_t *l_tx_tmp = l_iter_current->tx; - dap_chain_hash_fast_t *l_tx_hash_tmp = &l_iter_current->tx_hash_fast; - // start searching from the next hash after a_tx_first_hash - if (!is_search_enable) { - is_search_enable = dap_hash_fast_compare(l_tx_hash_tmp, a_tx_first_hash); - continue; - } - // Get out_cond item from transaction - l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_tmp, a_cond_type, &l_tx_out_cond_idx); - - if(l_tx_out_cond) { - l_cur_tx = l_tx_tmp; - memcpy(a_tx_first_hash, l_tx_hash_tmp, sizeof(dap_chain_hash_fast_t)); - if (a_token_ticker) { - strcpy(a_token_ticker, l_iter_current->cache_data.token_ticker); - } - break; - } - } - pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock); - if (a_out_cond) { - *a_out_cond = l_tx_out_cond; - } - if (a_out_cond_idx) { - *a_out_cond_idx = l_tx_out_cond_idx; - } - return l_cur_tx; -} - -/** - * Get the value from all transactions in the cache with out_cond item - * - * a_addr[in] wallet address, whose owner can use the service - * a_sign [in] signature of a_addr hash for check valid key - * a_sign_size [in] signature size - * - * a_public_key[in] public key that signed the transaction - * a_public_key_size[in] public key size - */ -uint256_t dap_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type, - dap_chain_addr_t *a_addr, dap_chain_tx_out_cond_t **tx_out_cond) - -{ - uint256_t l_ret_value = {}; - - dap_chain_datum_tx_t *l_tx_tmp; - dap_chain_hash_fast_t l_tx_first_hash = { 0 }; // start hash - /* size_t l_pub_key_size = a_key_from->pub_key_data_size; - uint8_t *l_pub_key = dap_enc_key_serialize_pub_key(a_key_from, &l_pub_key_size);*/ - dap_chain_tx_out_cond_t *l_tx_out_cond; - // Find all transactions - do { - l_tx_tmp = dap_ledger_tx_cache_find_out_cond(a_ledger, a_cond_type, &l_tx_first_hash, &l_tx_out_cond, NULL, NULL); - // Get out_cond item from transaction - if(l_tx_tmp) { - UNUSED(a_addr); - // TODO check relations a_addr with cond_data and public key - if(l_tx_out_cond) { - l_ret_value = l_tx_out_cond->header.value; - if(tx_out_cond) - *tx_out_cond = l_tx_out_cond; - } - } - } while(l_tx_tmp); - return l_ret_value; -} - /** * @brief dap_ledger_get_list_tx_outs_with_val * @param a_ledger @@ -5784,7 +5636,7 @@ dap_chain_datum_tx_t *dap_ledger_datum_iter_get_last(dap_ledger_datum_iter_t *a_ { dap_ledger_private_t *l_ledger_pvt = PVT(a_iter->net->pub.ledger); pthread_rwlock_rdlock(&l_ledger_pvt->ledger_rwlock); - a_iter->cur_ledger_tx_item = l_ledger_pvt->ledger_items->hh.prev; + a_iter->cur_ledger_tx_item = HASH_LAST(l_ledger_pvt->ledger_items); a_iter->cur = ((dap_ledger_tx_item_t *)(a_iter->cur_ledger_tx_item))->tx; a_iter->cur_hash = ((dap_ledger_tx_item_t *)(a_iter->cur_ledger_tx_item))->tx_hash_fast; a_iter->is_unspent = ((dap_ledger_tx_item_t *)(a_iter->cur_ledger_tx_item))->cache_data.ts_spent ? false : true; @@ -5793,72 +5645,116 @@ dap_chain_datum_tx_t *dap_ledger_datum_iter_get_last(dap_ledger_datum_iter_t *a_ return a_iter->cur; } - /** - * @brief dap_ledger_get_list_tx_cond_outs_with_val - * @param a_ledger - * @param a_token_ticker - * @param a_addr_from - * @param a_subtype - * @param a_value_need - * @param a_value_transfer - * @return + * Get the transaction in the cache by the addr in sig item + * + * a_addr[in] public key that signed the transaction + * a_tx_first_hash [in/out] hash of the initial transaction/ found transaction, if 0 start from the beginning */ -dap_list_t *dap_ledger_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledger, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from, - dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t a_value_need, uint256_t *a_value_transfer) +dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t *a_ledger, const char *a_token, dap_chain_tx_out_cond_subtype_t a_subtype, + const dap_chain_addr_t *a_addr, dap_chain_hash_fast_t *a_tx_first_hash, int *a_out_idx) { - dap_list_t *l_list_used_out = NULL; // list of transaction with 'out' items - dap_chain_hash_fast_t l_tx_cur_hash = { 0 }; - uint256_t l_value_transfer = { }; - dap_chain_datum_tx_t *l_tx; - while( compare256(l_value_transfer, a_value_need) == -1 - && ( l_tx = dap_ledger_tx_find_by_addr(a_ledger, a_token_ticker, a_addr_from, &l_tx_cur_hash)) ) - { - byte_t *it; size_t l_size; int i, l_out_idx_tmp = -1; - TX_ITEM_ITER_TX_TYPE(it, TX_ITEM_TYPE_OUT_COND, l_size, i, l_tx) { - ++l_out_idx_tmp; - dap_chain_tx_out_cond_t *l_out_cond = (dap_chain_tx_out_cond_t*) it; - if (a_subtype != l_out_cond->header.subtype || IS_ZERO_256(l_out_cond->header.value) ) - continue; - dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); - *l_item = (dap_chain_tx_used_out_item_t) { l_tx_cur_hash, (uint32_t)l_out_idx_tmp, l_out_cond->header.value }; - l_list_used_out = dap_list_append(l_list_used_out, l_item); - SUM_256_256(l_value_transfer, l_item->value, &l_value_transfer); - // already accumulated the required value, finish the search for 'out' items - if ( compare256(l_value_transfer, a_value_need) != -1 ) { + if (!a_addr || !a_token) + return NULL; + dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger); + dap_chain_tx_out_cond_t *ret = NULL; + dap_ledger_tx_item_t *l_iter_start = NULL, *it; + pthread_rwlock_rdlock(&l_ledger_pvt->ledger_rwlock); + if (a_tx_first_hash && !dap_hash_fast_is_blank(a_tx_first_hash)) { + HASH_FIND(hh, l_ledger_pvt->ledger_items, a_tx_first_hash, sizeof(dap_hash_t), l_iter_start); + if (!l_iter_start || !l_iter_start->hh.next) { + pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock); + return NULL; + } + // start searching from the next hash after a_tx_first_hash + l_iter_start = l_iter_start->hh.next; + } else + l_iter_start = l_ledger_pvt->ledger_items; + for (it = l_iter_start; it; it = it->hh.next) { + // If a_token is setup we check if its not our token - miss it + if (*it->cache_data.token_ticker && dap_strcmp(it->cache_data.token_ticker, a_token)) + continue; + ret = NULL; + // Get 'out_cond' item from transaction + byte_t *l_item; size_t l_size; int i, l_out_idx = 0; + TX_ITEM_ITER_TX_TYPE(l_item, TX_ITEM_TYPE_OUT_ALL, l_size, i, it->tx) { + if (*l_item == TX_ITEM_TYPE_OUT_COND && + ((dap_chain_tx_out_cond_t *)l_item)->header.subtype == a_subtype) { + ret = (dap_chain_tx_out_cond_t *)l_item; break; } + l_out_idx++; + } + // Don't return regular tx or spent conditions + if (!ret || !dap_hash_fast_is_blank(&it->cache_data.tx_hash_spent_fast[l_out_idx])) + continue; + dap_hash_fast_t l_owner_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, it->tx, a_subtype); + dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_ledger, &l_owner_tx_hash); + if (!l_tx) { + log_it(L_ERROR, "Can't find owner for tx %s", dap_hash_fast_to_str_static(&it->tx_hash_fast)); + continue; + } + // Get sign item from transaction + dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_SIG, NULL); + // Get dap_sign_t from item + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); + // compare public key in transaction with a_public_key + dap_chain_hash_fast_t l_sign_hash = {}; + dap_sign_get_pkey_hash(l_sign, &l_sign_hash); + if (dap_hash_fast_compare(&l_sign_hash, &a_addr->data.hash_fast)) { + if (a_tx_first_hash) + *a_tx_first_hash = it->tx_hash_fast; + if (a_out_idx) + *a_out_idx = l_out_idx; + break; } } - return compare256(l_value_transfer, a_value_need) > -1 && l_list_used_out - ? ({ if (a_value_transfer) *a_value_transfer = l_value_transfer; l_list_used_out; }) - : ( dap_list_free_full(l_list_used_out, NULL), NULL ); + pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock); + return ret; } -dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from, - dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t *a_value_transfer) +dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_subtype, + const char *a_token_ticker, const dap_chain_addr_t *a_addr_from) { dap_list_t *l_list_used_out = NULL; // list of transaction with 'out' items dap_chain_hash_fast_t l_tx_cur_hash = { }; - uint256_t l_value_transfer = { }; - dap_chain_datum_tx_t *l_tx; - while(( l_tx = dap_ledger_tx_find_by_addr(a_ledger, a_token_ticker, a_addr_from, &l_tx_cur_hash) )) { - byte_t *it; size_t l_size; int i, l_out_idx_tmp = -1; - TX_ITEM_ITER_TX_TYPE(it, TX_ITEM_TYPE_OUT_COND, l_size, i, l_tx) { - ++l_out_idx_tmp; - dap_chain_tx_out_cond_t *l_out_cond = (dap_chain_tx_out_cond_t*)it; - if ( a_subtype != l_out_cond->header.subtype || IS_ZERO_256(l_out_cond->header.value) ) - continue; - dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); - *l_item = (dap_chain_tx_used_out_item_t) { l_tx_cur_hash, (uint32_t)l_out_idx_tmp, l_out_cond->header.value }; - l_list_used_out = dap_list_append(l_list_used_out, l_item); - SUM_256_256(l_value_transfer, l_item->value, &l_value_transfer); - } + int l_out_idx; + dap_chain_tx_out_cond_t *l_cond; + while ( (l_cond = dap_ledger_out_cond_unspent_find_by_addr(a_ledger, a_token_ticker, a_subtype, a_addr_from, &l_tx_cur_hash, &l_out_idx)) ) { + dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); + *l_item = (dap_chain_tx_used_out_item_t) { l_tx_cur_hash, (uint32_t)l_out_idx, l_cond->header.value }; + l_list_used_out = dap_list_append(l_list_used_out, l_item); } + return l_list_used_out; +} - return l_list_used_out - ? ({ if (a_value_transfer) *a_value_transfer = l_value_transfer; l_list_used_out; }) - : ( dap_list_free_full(l_list_used_out, NULL), NULL ); +bool dap_ledger_check_condition_owner(dap_ledger_t *a_ledger, dap_hash_fast_t *a_tx_hash, dap_chain_tx_out_cond_subtype_t a_cond_subtype, + int a_out_idx, dap_sign_t *a_owner_sign) +{ + dap_return_val_if_fail(a_ledger && a_tx_hash && a_owner_sign, false); + // Get first tx + dap_chain_datum_tx_t *l_check_tx = dap_ledger_tx_find_by_hash(a_ledger, a_tx_hash); + if (!l_check_tx) { + log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(a_tx_hash)); + return false; + } + dap_hash_fast_t l_first_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, l_check_tx, a_cond_subtype); + if (dap_hash_fast_is_blank(&l_first_tx_hash)) { + log_it(L_ERROR, "Can't find owner for tx %s", dap_hash_fast_to_str_static(a_tx_hash)); + return false; + } + dap_chain_datum_tx_t *l_first_tx = dap_ledger_tx_find_by_hash(a_ledger, &l_first_tx_hash); + if (!l_first_tx) { + log_it(L_ERROR, "Can't find owner tx %s", dap_hash_fast_to_str_static(&l_first_tx_hash)); + return false; + } + dap_chain_tx_sig_t *l_first_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_first_tx, NULL, NULL, TX_ITEM_TYPE_SIG, NULL); + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_first_tx_sig); + if (!l_sign) { + log_it(L_ERROR, "Can't find signature for tx %s", dap_hash_fast_to_str_static(&l_first_tx_hash)); + return false; + } + return dap_sign_compare_pkeys(a_owner_sign, l_sign); } void dap_ledger_tx_add_notify(dap_ledger_t *a_ledger, dap_ledger_tx_add_notify_t a_callback, void *a_arg) { diff --git a/modules/net/include/dap_chain_ledger.h b/modules/net/include/dap_chain_ledger.h index f2e43d962d..059b3142ee 100644 --- a/modules/net/include/dap_chain_ledger.h +++ b/modules/net/include/dap_chain_ledger.h @@ -418,21 +418,11 @@ dap_chain_datum_tx_t* dap_ledger_tx_find_by_addr(dap_ledger_t *a_ledger, const c bool dap_ledger_tx_check_recipient(dap_ledger_t* a_ledger, dap_chain_hash_fast_t* a_tx_prev_hash, dap_chain_addr_t *a_addr); -// Get the transaction in the cache by the public key that signed the transaction, starting with a_tx_first_hash -const dap_chain_datum_tx_t* dap_ledger_tx_find_by_pkey(dap_ledger_t *a_ledger, - char *a_public_key, size_t a_public_key_size, dap_chain_hash_fast_t *a_tx_first_hash); - -// Get the transaction in the cache with the out_cond item -dap_chain_datum_tx_t* dap_ledger_tx_cache_find_out_cond(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type, - dap_chain_hash_fast_t *a_tx_first_hash, dap_chain_tx_out_cond_t **a_out_cond, - int *a_out_cond_idx, char *a_token_ticker); - // Get all transactions from the cache with the specified out_cond items dap_list_t* dap_ledger_tx_cache_find_out_cond_all(dap_ledger_t *a_ledger, dap_chain_net_srv_uid_t a_srv_uid); -// Get the value from all transactions in the cache with out_cond item -uint256_t dap_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_addr_t *a_addr, - dap_chain_tx_out_cond_t **tx_out_cond); +dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t *a_ledger, const char *a_token, dap_chain_tx_out_cond_subtype_t a_subtype, + const dap_chain_addr_t *a_addr, dap_chain_hash_fast_t *a_tx_first_hash, int *a_out_idx); // Get the list of 'out' items from previous transactions with summary value >= than a_value_need // Put this summary value to a_value_transfer @@ -440,12 +430,8 @@ dap_list_t *dap_ledger_get_list_tx_outs_with_val(dap_ledger_t *a_ledger, const c uint256_t a_value_need, uint256_t *a_value_transfer); dap_list_t *dap_ledger_get_list_tx_outs(dap_ledger_t *a_ledger, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from, uint256_t *a_value_transfer); -// Get the list of 'out_cond' items with summary value >= than a_value_need -dap_list_t *dap_ledger_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledger, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from, - dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t a_value_need, uint256_t *a_value_transfer); - -dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from, - dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t *a_value_transfer); +dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_subtype, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from); +bool dap_ledger_check_condition_owner(dap_ledger_t *a_ledger, dap_hash_fast_t *a_tx_hash, dap_chain_tx_out_cond_subtype_t a_cond_subtype, int a_out_idx, dap_sign_t *a_owner_sign); // Add new verificator callback with associated subtype. Returns 1 if callback replaced, overwise returns 0 int dap_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_ledger_verificator_callback_t a_callback, dap_ledger_updater_callback_t a_callback_added, dap_ledger_delete_callback_t a_callback_deleted); diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index c74cf6fd33..3734ed953c 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -290,16 +290,9 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a } dap_hash_fast_t pkey_hash = {}; - int l_item_cnt = 0; - dap_list_t *l_signs_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_SIG, &l_item_cnt); - - if (!l_signs_list) { - log_it(L_WARNING, "Can't get signs from tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); - return -9; - } - dap_chain_tx_sig_t *l_vote_sig = (dap_chain_tx_sig_t *)(dap_list_last(l_signs_list)->data); - dap_sign_get_pkey_hash((dap_sign_t*)l_vote_sig->sig, &pkey_hash); - dap_list_free(l_signs_list); + // Get sign item from transaction + dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(a_tx_in, NULL, NULL, TX_ITEM_TYPE_SIG, NULL); + dap_sign_get_pkey_hash((dap_sign_t *)l_tx_sig->sig, &pkey_hash); if (!a_apply) { if (l_vote_tx_item->answer_idx > dap_list_length(l_voting->voting_params.option_offsets_list)) { @@ -345,25 +338,27 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a dap_tsd_t *l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t*)it->data)->tsd; dap_hash_fast_t l_hash = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->tx_hash; int l_out_idx = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->out_idx; - if (l_tsd->type == VOTING_TSD_TYPE_VOTE_TX_COND) { - if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx)) - continue; - dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash); - dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t*)dap_chain_datum_tx_item_get(l_tx_prev_temp, &l_out_idx, NULL, TX_ITEM_TYPE_OUT_COND, NULL); - if (!l_prev_out || l_prev_out->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK) - continue; - if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) { - log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); - return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW; - } - - dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY); - l_item->tx_hash = l_hash; - l_item->out_idx = l_out_idx; - pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock); - HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item); - pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock); - } + if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND) + return -14; + if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx)) + return -15; + dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash); + dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t*)dap_chain_datum_tx_item_get(l_tx_prev_temp, &l_out_idx, NULL, TX_ITEM_TYPE_OUT_COND, NULL); + if (!l_prev_out || l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) + return -16; + if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, (dap_sign_t *)l_tx_sig->sig)) + return -17; + if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) { + log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW; + } + + dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY); + l_item->tx_hash = l_hash; + l_item->out_idx = l_out_idx; + pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock); + HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item); + pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock); } dap_list_free(l_tsd_list); // check inputs @@ -379,7 +374,7 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash); dap_chain_tx_out_t *l_prev_out_union = (dap_chain_tx_out_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_tx_in->header.tx_out_prev_idx); if (!l_prev_out_union) - continue; + return -18; if ((l_prev_out_union->header.type == TX_ITEM_TYPE_OUT || l_prev_out_union->header.type == TX_ITEM_TYPE_OUT_EXT) && SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) { log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); @@ -1487,14 +1482,11 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal DAP_DEL_Z(l_vote_item); // add stake out conds items - dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, a_net->pub.native_ticker, l_addr_from, - DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, NULL); - dap_list_t *l_temp = l_outs; - while(l_temp){ - dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)l_temp->data; + dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, a_net->pub.native_ticker, l_addr_from); + for (dap_list_t *it = l_outs; it; it = it->next) { + dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data; if (dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_out_item->tx_hash_fast, l_out_item->num_idx_out, NULL) || s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out ) != 0){ - l_temp = l_temp->next; continue; } dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out); @@ -1506,7 +1498,6 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal } dap_chain_datum_tx_add_item(&l_tx, l_item); DAP_DEL_Z(l_item); - l_temp = l_temp->next; } dap_list_free_full(l_outs, NULL); -- GitLab From 34fcfbb3fd337bbacca15e91460fef0d5a258ff8 Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Mon, 3 Mar 2025 18:16:09 +0700 Subject: [PATCH 02/53] [*] Voting with non-native token partial debug --- modules/common/dap_chain_datum_tx_voting.c | 15 + .../include/dap_chain_datum_tx_voting.h | 9 +- .../consensus/esbocs/dap_chain_cs_esbocs.c | 5 +- modules/net/dap_chain_ledger.c | 21 +- modules/net/dap_chain_net_tx.c | 4 +- .../service/voting/dap_chain_net_srv_voting.c | 332 +++++++++++------- .../voting/include/dap_chain_net_srv_voting.h | 6 +- 7 files changed, 246 insertions(+), 146 deletions(-) diff --git a/modules/common/dap_chain_datum_tx_voting.c b/modules/common/dap_chain_datum_tx_voting.c index 2a161dd3a9..eb2ab0320c 100644 --- a/modules/common/dap_chain_datum_tx_voting.c +++ b/modules/common/dap_chain_datum_tx_voting.c @@ -124,6 +124,18 @@ dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_changing_allowed_tsd_create(bool return l_tsd; } +dap_chain_tx_tsd_t *dap_chain_datum_voting_token_tsd_create(const char *a_token_ticker) +{ + dap_return_val_if_fail(a_token_ticker && *a_token_ticker, NULL); + size_t l_ticker_len = strlen(a_token_ticker); + if (l_ticker_len >= DAP_CHAIN_TICKER_SIZE_MAX) { + log_it(L_ERROR, "Ticker len %zu is too big", l_ticker_len); + return NULL; + } + dap_chain_tx_tsd_t *l_tsd = dap_chain_datum_tx_item_tsd_create((char *)a_token_ticker, VOTING_TSD_TYPE_TOKEN, l_ticker_len); + return l_tsd; +} + dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_tx_cond_tsd_create(dap_chain_hash_fast_t a_tx_hash, int a_out_idx) { dap_chain_tx_voting_tx_cond_t l_temp = { @@ -176,6 +188,9 @@ json_object *dap_chain_datum_tx_item_voting_tsd_to_json(dap_chain_datum_tx_t* a_ case VOTING_TSD_TYPE_ANSWER: json_object_array_add(l_answer_array_object, json_object_new_string_len((char*)l_tsd->data, l_tsd->size)); break; + case VOTING_TSD_TYPE_TOKEN: + json_object_object_add(l_object, "token", json_object_new_string_len((char*)l_tsd->data, l_tsd->size)); + break; case VOTING_TSD_TYPE_EXPIRE: json_object_object_add(l_object, "exired", json_object_new_uint64(*(uint64_t*)l_tsd->data)); break; diff --git a/modules/common/include/dap_chain_datum_tx_voting.h b/modules/common/include/dap_chain_datum_tx_voting.h index a87c67824c..add632997a 100644 --- a/modules/common/include/dap_chain_datum_tx_voting.h +++ b/modules/common/include/dap_chain_datum_tx_voting.h @@ -43,7 +43,8 @@ typedef enum dap_chain_datum_voting_tsd_type { VOTING_TSD_TYPE_MAX_VOTES_COUNT, VOTING_TSD_TYPE_DELEGATED_KEY_REQUIRED, VOTING_TSD_TYPE_VOTE_CHANGING_ALLOWED, - VOTING_TSD_TYPE_VOTE_TX_COND + VOTING_TSD_TYPE_VOTE_TX_COND, + VOTING_TSD_TYPE_TOKEN } dap_chain_datum_voting_tsd_type_t; typedef struct dap_chain_tx_voting { @@ -63,13 +64,14 @@ typedef struct dap_chain_tx_vote { typedef struct dap_chain_datum_tx_voting_params { - char *voting_question; + char *voting_question; dap_list_t *answers_list; uint8_t answers_count; dap_time_t voting_expire; uint64_t votes_max_count; bool delegate_key_required; bool vote_changing_allowed; + char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; } dap_chain_datum_tx_voting_params_t; #ifdef __cplusplus @@ -86,6 +88,7 @@ dap_chain_tx_tsd_t* dap_chain_datum_voting_max_votes_count_tsd_create(uint64_t a dap_chain_tx_tsd_t *dap_chain_datum_voting_delegated_key_required_tsd_create(bool a_delegated_key_required); dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_changing_allowed_tsd_create(bool a_vote_changing_allowed); dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_tx_cond_tsd_create(dap_chain_hash_fast_t a_tx_hash, int a_out_idx); +dap_chain_tx_tsd_t *dap_chain_datum_voting_token_tsd_create(const char *a_token_ticker); dap_chain_tx_voting_t *dap_chain_datum_tx_item_voting_create(void); json_object *dap_chain_datum_tx_item_voting_tsd_to_json(dap_chain_datum_tx_t* a_tx); @@ -96,4 +99,4 @@ json_object *dap_chain_datum_tx_item_vote_to_json(dap_chain_tx_vote_t *a_vote, d #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c index 88546b2272..f7c088e54b 100644 --- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c +++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c @@ -837,7 +837,7 @@ static dap_list_t *s_get_validators_list(dap_chain_esbocs_t *a_esbocs, dap_hash_ dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_esbocs); dap_list_t *l_ret = NULL; dap_list_t *l_validators = NULL; - if (!l_esbocs_pvt->poa_mode) { + if (l_esbocs_pvt->poa_mode) { // UNDO it after debug if (a_excluded_list_size) { l_validators = dap_chain_net_srv_stake_get_validators(a_esbocs->chain->net_id, false, NULL); uint16_t l_excluded_num = *a_excluded_list; @@ -2774,6 +2774,9 @@ static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_b static uint64_t s_get_precached_key_hash(dap_list_t **a_precached_keys_list, dap_sign_t *a_source_sign, dap_hash_fast_t *a_result) { + if (DAP_SIGN_GET_PKEY_HASHING_FLAG(a_source_sign->header.hash_type)) + return !dap_sign_get_pkey_hash(a_source_sign, a_result); + bool l_found = false; struct precached_key *l_key = NULL; dap_list_t *l_cur; diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index 03fcb33ba6..deaac956e7 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -5678,10 +5678,13 @@ dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t * // Get 'out_cond' item from transaction byte_t *l_item; size_t l_size; int i, l_out_idx = 0; TX_ITEM_ITER_TX_TYPE(l_item, TX_ITEM_TYPE_OUT_ALL, l_size, i, it->tx) { - if (*l_item == TX_ITEM_TYPE_OUT_COND && - ((dap_chain_tx_out_cond_t *)l_item)->header.subtype == a_subtype) { - ret = (dap_chain_tx_out_cond_t *)l_item; - break; + if (*l_item == TX_ITEM_TYPE_OUT_COND) { + dap_chain_tx_out_cond_subtype_t l_subtype = ((dap_chain_tx_out_cond_t *)l_item)->header.subtype; + if (l_subtype == a_subtype || + (a_subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL && l_subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)) { + ret = (dap_chain_tx_out_cond_t *)l_item; + break; + } } l_out_idx++; } @@ -5689,7 +5692,8 @@ dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t * if (!ret || !dap_hash_fast_is_blank(&it->cache_data.tx_hash_spent_fast[l_out_idx])) continue; dap_hash_fast_t l_owner_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, it->tx, a_subtype); - dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_ledger, &l_owner_tx_hash); + dap_chain_datum_tx_t *l_tx = dap_hash_fast_is_blank(&l_owner_tx_hash) ? it->tx + : dap_ledger_tx_find_by_hash(a_ledger, &l_owner_tx_hash); if (!l_tx) { log_it(L_ERROR, "Can't find owner for tx %s", dap_hash_fast_to_str_static(&it->tx_hash_fast)); continue; @@ -5738,12 +5742,13 @@ bool dap_ledger_check_condition_owner(dap_ledger_t *a_ledger, dap_hash_fast_t *a log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(a_tx_hash)); return false; } - dap_hash_fast_t l_first_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, l_check_tx, a_cond_subtype); - if (dap_hash_fast_is_blank(&l_first_tx_hash)) { + if (!dap_chain_datum_tx_out_cond_get(l_check_tx, a_cond_subtype, NULL)) { log_it(L_ERROR, "Can't find owner for tx %s", dap_hash_fast_to_str_static(a_tx_hash)); return false; } - dap_chain_datum_tx_t *l_first_tx = dap_ledger_tx_find_by_hash(a_ledger, &l_first_tx_hash); + dap_hash_fast_t l_first_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, l_check_tx, a_cond_subtype); + dap_chain_datum_tx_t *l_first_tx = dap_hash_fast_is_blank(&l_first_tx_hash) ? l_check_tx + : dap_ledger_tx_find_by_hash(a_ledger, &l_first_tx_hash); if (!l_first_tx) { log_it(L_ERROR, "Can't find owner tx %s", dap_hash_fast_to_str_static(&l_first_tx_hash)); return false; diff --git a/modules/net/dap_chain_net_tx.c b/modules/net/dap_chain_net_tx.c index addcb27c56..937c0464f5 100644 --- a/modules/net/dap_chain_net_tx.c +++ b/modules/net/dap_chain_net_tx.c @@ -1633,7 +1633,7 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json json_object_object_add(json_obj_item,"type", json_object_new_string("voting")); json_object_object_add(json_obj_item,"voting_question", json_object_new_string(l_voting_params->voting_question)); json_object_object_add(json_obj_item,"answer_options", json_object_new_string("")); - + json_object_object_add(json_obj_item, "token", json_object_new_string(l_voting_params->token_ticker)); dap_list_t *l_temp = l_voting_params->answers_list; uint8_t l_index = 0; while (l_temp) { @@ -1643,7 +1643,7 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json } if (l_voting_params->voting_expire) { dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_voting_params->voting_expire); - json_object_object_add(json_obj_item,"Voting expire", json_object_new_string(l_tmp_buf)); + json_object_object_add(json_obj_item, "Voting expire", json_object_new_string(l_tmp_buf)); } if (l_voting_params->votes_max_count) { json_object_object_add(json_obj_item, "Votes max count", json_object_new_uint64(l_voting_params->votes_max_count)); diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index 3734ed953c..6f55e66960 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -50,6 +50,7 @@ typedef struct dap_chain_net_voting_params_offsets{ uint64_t votes_max_count; bool delegate_key_required; bool vote_changing_allowed; + char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; } dap_chain_net_voting_params_offsets_t; typedef struct dap_chain_net_vote_option { @@ -115,7 +116,8 @@ int dap_chain_net_srv_voting_init() pthread_rwlock_init(&s_votings_rwlock, NULL); dap_chain_ledger_voting_verificator_add(s_datum_tx_voting_verification_callback, s_datum_tx_voting_verification_delete_callback); dap_cli_server_cmd_add("voting", s_cli_voting, "Voting commands.", "" - "voting create -net <net_name> -question <\"Question_string\"> -options <\"Option0\", \"Option1\" ... \"OptionN\"> [-expire <voting_expire_time_in_RCF822>] [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name>\n" + "voting create -net <net_name> -question <\"Question_string\"> -options <\"Option0\", \"Option1\" ... \"OptionN\"> [-expire <voting_expire_time_in_RCF822>]" + " [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name> -token <ticker>\n" "voting vote -net <net_name> -hash <voting_hash> -option_idx <option_index> [-cert <delegate_cert_name>] -fee <value_datoshi> -w <fee_wallet_name>\n" "voting list -net <net_name>\n" "voting dump -net <net_name> -hash <voting_hash>\n"); @@ -218,14 +220,29 @@ static int s_voting_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t dap_list_t* l_tsd_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_TSD, NULL); for (dap_list_t *it = l_tsd_list; it; it = it->next) { - dap_tsd_t* l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t*)it->data)->tsd; + dap_chain_tx_tsd_t *l_tx_tsd = it->data; + dap_tsd_t *l_tsd = (dap_tsd_t *)l_tx_tsd->tsd; + if (l_tx_tsd->header.size < sizeof(dap_tsd_t) || + l_tx_tsd->header.size != dap_tsd_size(l_tsd)) { + log_it(L_WARNING, "Incorrect size %" DAP_UINT64_FORMAT_U " of TX_TSD item for voting %s", + l_tx_tsd->header.size, dap_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INVALID_SIZE; + } dap_chain_net_vote_option_t *l_vote_option = NULL; switch(l_tsd->type){ case VOTING_TSD_TYPE_QUESTION: + if (!l_tsd->size) { + log_it(L_WARNING, "Incorrect size %u of TSD section QUESTION for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INVALID_SIZE; + } l_item->voting_params.voting_question_offset = (size_t)(l_tsd->data - (byte_t*)l_item->voting_params.voting_tx); l_item->voting_params.voting_question_length = l_tsd->size; break; case VOTING_TSD_TYPE_ANSWER: + if (!l_tsd->size) { + log_it(L_WARNING, "Incorrect size %u of TSD section ANSWER for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INVALID_SIZE; + } l_vote_option = DAP_NEW_Z(dap_chain_net_vote_option_t); l_vote_option->vote_option_offset = (size_t)(l_tsd->data - (byte_t*)l_item->voting_params.voting_tx); l_vote_option->vote_option_length = l_tsd->size; @@ -233,41 +250,50 @@ static int s_voting_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t break; case VOTING_TSD_TYPE_EXPIRE: if (l_tsd->size != sizeof(dap_time_t)) { - log_it(L_WARNING, "Incorrect size %u of TSD section EXPIRE vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + log_it(L_WARNING, "Incorrect size %u of TSD section EXPIRE for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); return -DAP_LEDGER_CHECK_INVALID_SIZE; } l_item->voting_params.voting_expire = *(dap_time_t *)l_tsd->data; break; case VOTING_TSD_TYPE_MAX_VOTES_COUNT: if (l_tsd->size != sizeof(uint64_t)) { - log_it(L_WARNING, "Incorrect size %u of TSD section MAX_VOTES_COUNT vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + log_it(L_WARNING, "Incorrect size %u of TSD section MAX_VOTES_COUNT for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); return -DAP_LEDGER_CHECK_INVALID_SIZE; } l_item->voting_params.votes_max_count = *(uint64_t *)l_tsd->data; break; case VOTING_TSD_TYPE_DELEGATED_KEY_REQUIRED: if (l_tsd->size != sizeof(byte_t)) { - log_it(L_WARNING, "Incorrect size %u of TSD section DELEGATED_KEY_REQUIRED vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + log_it(L_WARNING, "Incorrect size %u of TSD section DELEGATED_KEY_REQUIRED for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); return -DAP_LEDGER_CHECK_INVALID_SIZE; } l_item->voting_params.delegate_key_required = *(byte_t *)l_tsd->data; break; case VOTING_TSD_TYPE_VOTE_CHANGING_ALLOWED: if (l_tsd->size != sizeof(byte_t)) { - log_it(L_WARNING, "Incorrect size %u of TSD section VOTE_CHANGING_ALLOWED vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + log_it(L_WARNING, "Incorrect size %u of TSD section VOTE_CHANGING_ALLOWED for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); return -DAP_LEDGER_CHECK_INVALID_SIZE; } l_item->voting_params.vote_changing_allowed = *(byte_t *)l_tsd->data; break; + case VOTING_TSD_TYPE_TOKEN: + if (!l_tsd->size || l_tsd->size >= DAP_CHAIN_TICKER_SIZE_MAX) { + log_it(L_WARNING, "Incorrect size %u of TSD section TOKEN for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INVALID_SIZE; + } + strcpy(l_item->voting_params.token_ticker, (char *)l_tsd->data); default: break; } } dap_list_free(l_tsd_list); + if (!*l_item->voting_params.token_ticker) + strcpy(l_item->voting_params.token_ticker, a_ledger->net->pub.native_ticker); pthread_rwlock_wrlock(&s_votings_rwlock); HASH_ADD(hh, s_votings, voting_hash, sizeof(dap_hash_fast_t), l_item); pthread_rwlock_unlock(&s_votings_rwlock); + log_it(L_NOTICE, "Voting with hash %s succefully added to ledger", dap_hash_fast_to_str_static(a_tx_hash)); return DAP_LEDGER_CHECK_OK; } @@ -340,25 +366,26 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a int l_out_idx = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->out_idx; if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND) return -14; - if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx)) - return -15; dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash); - dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t*)dap_chain_datum_tx_item_get(l_tx_prev_temp, &l_out_idx, NULL, TX_ITEM_TYPE_OUT_COND, NULL); - if (!l_prev_out || l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) + dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_out_idx); + if (!l_prev_out || l_prev_out->header.item_type != TX_ITEM_TYPE_OUT_COND || l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) return -16; if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, (dap_sign_t *)l_tx_sig->sig)) return -17; + if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx)) + return -15; if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) { log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW; } - - dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY); - l_item->tx_hash = l_hash; - l_item->out_idx = l_out_idx; - pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock); - HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item); - pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock); + if (a_apply) { + dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY); + l_item->tx_hash = l_hash; + l_item->out_idx = l_out_idx; + pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock); + HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item); + pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock); + } } dap_list_free(l_tsd_list); // check inputs @@ -369,17 +396,34 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a } for (dap_list_t *it = l_ins_list; it; it = it->next) { dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)it->data; - if (!s_datum_tx_voting_coin_check_spent(a_ledger->net, l_vote_tx_item->voting_hash, + dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash); + dap_chain_tx_out_ext_t *l_prev_out_union = (dap_chain_tx_out_ext_t *)dap_chain_datum_tx_out_get_by_out_idx( + l_tx_prev_temp, l_tx_in->header.tx_out_prev_idx); + if (!l_prev_out_union) + return -18; + const char *l_ticker_in = NULL; + switch (l_prev_out_union->header.type) { + case TX_ITEM_TYPE_OUT: + l_ticker_in = dap_ledger_tx_get_token_ticker_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash); + break; + case TX_ITEM_TYPE_OUT_EXT: + l_ticker_in = l_prev_out_union->token; + break; + default: + log_it(L_WARNING, "Unexpected tx item %d in vote tx %s", l_prev_out_union->header.type, dap_hash_fast_to_str_static(a_tx_hash)); + return -19; + } + if (dap_strcmp(l_ticker_in, l_voting->voting_params.token_ticker)) + continue; + if (s_datum_tx_voting_coin_check_spent(a_ledger->net, l_vote_tx_item->voting_hash, l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx, &pkey_hash)) { - dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash); - dap_chain_tx_out_t *l_prev_out_union = (dap_chain_tx_out_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_tx_in->header.tx_out_prev_idx); - if (!l_prev_out_union) - return -18; - if ((l_prev_out_union->header.type == TX_ITEM_TYPE_OUT || l_prev_out_union->header.type == TX_ITEM_TYPE_OUT_EXT) && - SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) { - log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); - return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW; - } + log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx, + dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash)); + return -20; + } + if (SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) { + log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW; } } dap_list_free(l_ins_list); @@ -436,14 +480,14 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE]; dap_hash_fast_to_str(&((dap_chain_net_vote_t *)it->data)->vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE); DAP_DELETE(it->data); - log_it(L_INFO, "Vote %s of voting %s has been changed", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); + log_it(L_NOTICE, "Vote %s of voting %s has been changed", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); return DAP_LEDGER_CHECK_OK; } } l_voting->votes = dap_list_append(l_voting->votes, l_vote_item); char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE]; dap_hash_fast_to_str(a_tx_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE); - log_it(L_INFO, "Vote %s of voting %s has been accepted", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); + log_it(L_NOTICE, "Vote %s of voting %s has been accepted", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); } return DAP_LEDGER_CHECK_OK; } @@ -503,7 +547,7 @@ static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledge return false; } - dap_chain_net_votings_t * l_voting = NULL; + dap_chain_net_votings_t *l_voting = NULL; pthread_rwlock_wrlock(&s_votings_rwlock); HASH_FIND(hh, s_votings, &l_vote_tx_item->voting_hash, sizeof(dap_hash_fast_t), l_voting); pthread_rwlock_unlock(&s_votings_rwlock); @@ -615,6 +659,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) const char* l_max_votes_count_str = NULL; const char* l_fee_str = NULL; const char* l_wallet_str = NULL; + const char *l_token_str = NULL; dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str); if (!l_question_str){ @@ -647,8 +692,6 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS; } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str); - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str); if (!l_fee_str){ dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID, "Voting requires paramete -fee to be valid."); @@ -662,6 +705,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID; } + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str); dap_time_t l_time_expire = 0; if (l_voting_expire_str) l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str); @@ -670,6 +714,8 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) "Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\""); return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT; } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str); uint64_t l_max_count = 0; if (l_max_votes_count_str) l_max_count = strtoul(l_max_votes_count_str, NULL, 10); @@ -683,8 +729,26 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str); + if (l_token_str && !dap_ledger_token_ticker_check(l_net->pub.ledger, l_token_str)) { + dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN, "Token %s does not exist", l_token_str); + return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN; + } + char *l_hash_ret = NULL; - int res = dap_chain_net_vote_create(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net, l_hash_out_type, &l_hash_ret); + int res = dap_chain_net_vote_create(l_question_str, + l_options_list, + l_time_expire, + l_max_count, + l_value_fee, + l_is_delegated_key, + l_is_vote_changing_allowed, + l_wallet_fee, + l_net, + l_token_str, + l_hash_out_type, + &l_hash_ret); dap_list_free(l_options_list); dap_chain_wallet_close(l_wallet_fee); @@ -812,8 +876,8 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) } const char *c_wallets_path = dap_chain_wallet_get_path(g_config); - dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, c_wallets_path,NULL); - if (!l_wallet_fee) { + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path,NULL); + if (!l_wallet) { dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST, "Wallet %s does not exist", l_wallet_str); return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST; } @@ -822,9 +886,9 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) char *l_hash_tx; - int res = dap_chain_net_vote_voting(l_cert, l_value_fee, l_wallet_fee, l_voting_hash, l_option_idx_count, + int res = dap_chain_net_vote_voting(l_cert, l_value_fee, l_wallet, l_voting_hash, l_option_idx_count, l_net, l_hash_out_type, &l_hash_tx); - dap_chain_wallet_close(l_wallet_fee); + dap_chain_wallet_close(l_wallet); switch (res) { case DAP_CHAIN_NET_VOTE_VOTING_OK: { @@ -918,6 +982,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) char* l_voting_question = (char*)l_voting->voting_params.voting_tx + l_voting->voting_params.voting_question_offset; json_object_object_add( json_obj_vote, "question", json_object_new_string_len(l_voting_question, l_voting->voting_params.voting_question_length) ); + json_object_object_add(json_obj_vote, "token", json_object_new_string(l_voting->voting_params.token_ticker)); json_object_array_add(json_arr_voting_out, json_obj_vote); } pthread_rwlock_unlock(&s_votings_rwlock); @@ -968,6 +1033,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) json_object_object_add(json_vote_out, "question", json_object_new_string_len((char*)l_voting->voting_params.voting_tx + l_voting->voting_params.voting_question_offset, l_voting->voting_params.voting_question_length)); + json_object_object_add(json_vote_out, "token", json_object_new_string(l_voting->voting_params.token_ticker)); if (l_voting->voting_params.voting_expire) { char l_tmp_buf[DAP_TIME_STR_SIZE]; dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_voting->voting_params.voting_expire); @@ -1028,21 +1094,26 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f { int l_coin_is_spent = 0; - - dap_ledger_t *l_ledger = a_net->pub.ledger; - if(!l_ledger){ - log_it(L_ERROR, "Can't find ledger"); + dap_chain_net_votings_t *l_voting = NULL; + pthread_rwlock_wrlock(&s_votings_rwlock); + HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting); + pthread_rwlock_unlock(&s_votings_rwlock); + if (!l_voting) { + log_it(L_ERROR, "Can't find voting %s", dap_hash_fast_to_str_static(&a_voting_hash)); return -1; } + const char *l_token_ticker = l_voting->voting_params.token_ticker; + dap_ledger_t *l_ledger = a_net->pub.ledger; dap_chain_datum_tx_t *l_voting_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_voting_hash); - const char *l_native_ticker = a_net->pub.native_ticker; - - dap_list_t *l_tx_list = NULL; // "stack" for saving txs on up level + if (!l_voting_tx) { + log_it(L_ERROR, "Can't find voting tx %s", dap_hash_fast_to_str_static(&a_voting_hash)); + return -2; + } dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_tx_prev_hash); - if (!l_tx){ - log_it(L_ERROR, "Can't find tx"); - return -1; + if (!l_tx) { + log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(&a_tx_prev_hash)); + return -3; } if (l_tx->header.ts_created < l_voting_tx->header.ts_created){ @@ -1055,25 +1126,18 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f dap_chain_tx_vote_t *l_vote = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL); if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)) { - dap_chain_net_votings_t *l_voting = NULL; - pthread_rwlock_wrlock(&s_votings_rwlock); - HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting); - pthread_rwlock_unlock(&s_votings_rwlock); - if (l_voting) { - for (dap_list_t *it = l_voting->votes; it; it = it->next) { - dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data; - if (dap_hash_fast_compare(&l_vote->vote_hash, &a_tx_prev_hash)) { - if (l_voting->voting_params.vote_changing_allowed && - !dap_hash_fast_is_blank(a_pkey_hash) && - dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash)) - break; // it's vote changing, allow it - return 1; - } + for (dap_list_t *it = l_voting->votes; it; it = it->next) { + dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data; + if (dap_hash_fast_compare(&l_vote->vote_hash, &a_tx_prev_hash)) { + if (l_voting->voting_params.vote_changing_allowed && + !dap_hash_fast_is_blank(a_pkey_hash) && + dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash)) + break; // it's vote changing, allow it + return 1; } } } - dap_list_t *l_ins_list_temp = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL); dap_list_t *l_cond_ins_list = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_COND, NULL); if (!l_ins_list_temp && !l_cond_ins_list){ @@ -1081,12 +1145,9 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f return -1; } - dap_list_t *l_ins_list = NULL; - l_ins_list = dap_list_concat(l_ins_list, l_ins_list_temp); - l_ins_list = dap_list_concat(l_ins_list, l_cond_ins_list); - - l_tx_list = dap_list_append(l_tx_list, l_ins_list); - dap_list_t* l_tx_temp = dap_list_last(l_tx_list); + dap_list_t *l_ins_list = dap_list_concat(l_ins_list_temp, l_cond_ins_list); + dap_list_t *l_tx_list = dap_list_append(NULL, l_ins_list); // "stack" for saving txs on up level + dap_list_t *l_tx_temp = dap_list_last(l_tx_list); while(l_tx_temp && !l_coin_is_spent){ if (l_tx_temp->data == NULL){ @@ -1118,22 +1179,24 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f l_tx_token = l_temp_out->token; }break; case TX_ITEM_TYPE_OUT_COND:{ - dap_chain_tx_out_cond_t *l_temp_out = (dap_chain_tx_out_cond_t*)l_prev_out_union; - if (l_temp_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK || - s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, l_temp_in->header.tx_prev_hash, l_temp_in->header.tx_out_prev_idx) == 0) + dap_chain_tx_out_cond_t *l_temp_out = (dap_chain_tx_out_cond_t *)l_prev_out_union; + if (l_temp_out->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) { + l_tx_token = a_net->pub.native_ticker; break; + } + if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, l_temp_in->header.tx_prev_hash, + l_temp_in->header.tx_out_prev_idx) != 0) { + l_coin_is_spent = 1; + continue; + } + l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_temp_in->header.tx_prev_hash); } default: - l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in); - if (l_tx_temp->data == NULL){ - l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp); - l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL; - } - continue; + break; } if (l_tx_prev_temp->header.ts_created < l_voting_tx->header.ts_created || - dap_strcmp(l_tx_token, l_native_ticker)){ + dap_strcmp(l_tx_token, l_token_ticker)){ l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in); if (l_tx_temp->data == NULL){ l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp); @@ -1142,13 +1205,8 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f continue; } - dap_chain_tx_vote_t *l_vote =(dap_chain_tx_vote_t *) dap_chain_datum_tx_item_get(l_tx_prev_temp, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL); if(l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)){ - dap_chain_net_votings_t *l_voting = NULL; - pthread_rwlock_wrlock(&s_votings_rwlock); - HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting); - pthread_rwlock_unlock(&s_votings_rwlock); dap_list_t *l_temp = NULL; while (l_temp){ dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)l_temp->data; @@ -1160,12 +1218,10 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f } } - l_ins_list = dap_chain_datum_tx_items_get(l_tx_prev_temp, TX_ITEM_TYPE_IN, NULL); l_tx_list = dap_list_append(l_tx_list, l_ins_list); l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in); l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL; - } if(l_tx_list){ @@ -1209,7 +1265,8 @@ static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_has int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, - dap_chain_net_t *a_net, const char *a_hash_out_type, char **a_hash_output) { + dap_chain_net_t *a_net, const char *a_token_ticker, + const char *a_hash_out_type, char **a_hash_output) { if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ return DAP_CHAIN_NET_VOTE_CREATE_LENGTH_QUESTION_OVERSIZE_MAX; @@ -1243,8 +1300,7 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap dap_ledger_t* l_ledger = a_net->pub.ledger; dap_list_t *l_list_used_out = NULL; if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, l_addr_from, &l_list_used_out, l_total_fee, &l_value_transfer) == -101) - l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, - l_addr_from, l_total_fee, &l_value_transfer); + l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, l_addr_from, l_total_fee, &l_value_transfer); if (!l_list_used_out) { return DAP_CHAIN_NET_VOTE_CREATE_NOT_ENOUGH_FUNDS_TO_TRANSFER; } @@ -1327,6 +1383,16 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap DAP_DEL_Z(l_vote_changing_item); } + if (a_token_ticker) { + dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker); + if (!l_voting_token_item) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_TOKEN; + } + dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item); + DAP_DEL_Z(l_voting_token_item); + } + // add 'in' items uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); assert(EQUAL_256(l_value_to_items, l_value_transfer)); @@ -1334,7 +1400,7 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap uint256_t l_value_pack = {}; // Network fee if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) == 1) + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, l_native_ticker) == 1) SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); else { dap_chain_datum_tx_delete(l_tx); @@ -1354,7 +1420,7 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap uint256_t l_value_back; SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); if(!IS_ZERO_256(l_value_back)) { - if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) { + if(dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_native_ticker) != 1) { dap_chain_datum_tx_delete(l_tx); return DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; } @@ -1433,15 +1499,18 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal if (!l_addr_from) return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID; - const char *l_native_ticker = a_net->pub.native_ticker; - uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer; + const char *l_token_ticker = l_voting->voting_params.token_ticker; + uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer; dap_chain_addr_t l_addr_fee = {}; bool l_net_fee_used = dap_chain_net_tx_get_fee(a_net->pub.id, &l_net_fee, &l_addr_fee); - SUM_256_256(l_net_fee, a_fee, &l_total_fee); + if (l_net_fee_used) + SUM_256_256(l_net_fee, a_fee, &l_total_fee); - dap_ledger_t* l_ledger = dap_ledger_by_net_name(a_net->pub.name); - dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs(l_ledger, l_native_ticker, l_addr_from, &l_value_transfer); - if (!l_list_used_out || compare256(l_value_transfer, l_total_fee) <= 0) { + bool l_native_tx = !dap_strcmp(l_token_ticker, a_net->pub.native_ticker); + dap_ledger_t *l_ledger = a_net->pub.ledger; + dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs(l_ledger, l_token_ticker, l_addr_from, &l_value_transfer); + if (!l_list_used_out || (l_native_tx && compare256(l_value_transfer, l_total_fee) < 0)) { + dap_list_free_full(l_list_used_out, NULL); return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER; } @@ -1459,15 +1528,33 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal return DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW; } - if (IS_ZERO_256(l_value_transfer_new) || compare256(l_value_transfer_new, l_total_fee) <= 0){ + if (IS_ZERO_256(l_value_transfer_new) || (l_native_tx && compare256(l_value_transfer_new, l_total_fee) <= 0)) return DAP_CHAIN_NET_VOTE_VOTING_UNSPENT_UTX0_FOR_PARTICIPATION_THIS_VOTING; - } l_value_transfer = l_value_transfer_new; // create empty transaction dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + uint256_t l_value_back = l_value_transfer, l_fee_back = {}; + if (!l_native_tx) { + dap_list_t *l_list_fee_outs = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_net->pub.native_ticker, l_addr_from, l_total_fee, &l_fee_transfer); + if (!l_list_fee_outs) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER; + } + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_outs); + assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); + dap_list_free_full(l_list_fee_outs, NULL); + SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_back); + } else + SUBTRACT_256_256(l_value_transfer, l_total_fee, &l_value_back); + + // add 'in' items + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + // Add vote item if (a_option_idx > dap_list_length(l_voting->voting_params.option_offsets_list)){ dap_chain_datum_tx_delete(l_tx); @@ -1481,14 +1568,12 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal dap_chain_datum_tx_add_item(&l_tx, l_vote_item); DAP_DEL_Z(l_vote_item); - // add stake out conds items - dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, a_net->pub.native_ticker, l_addr_from); + // add out conds items + dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from); for (dap_list_t *it = l_outs; it; it = it->next) { dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data; - if (dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_out_item->tx_hash_fast, l_out_item->num_idx_out, NULL) || - s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out ) != 0){ + if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out) != 0) continue; - } dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out); if(!l_item){ dap_chain_datum_tx_delete(l_tx); @@ -1501,37 +1586,26 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal } dap_list_free_full(l_outs, NULL); - // add 'in' items - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); - assert(EQUAL_256(l_value_to_items, l_value_transfer)); - dap_list_free_full(l_list_used_out, NULL); - uint256_t l_value_pack = {}; // Network fee - if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) == 1) - SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); - else { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; - } + if (l_net_fee_used && dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, a_net->pub.native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; } + // Validator's fee - if (!IS_ZERO_256(a_fee)) { - if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1) - SUM_256_256(l_value_pack, a_fee, &l_value_pack); - else { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; - } + if (!IS_ZERO_256(a_fee) && dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; } + // coin back - uint256_t l_value_back; - SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); - if(!IS_ZERO_256(l_value_back)) { - if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; - } + if (!IS_ZERO_256(l_value_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_token_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; + } + if (!IS_ZERO_256(l_fee_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_fee_back, a_net->pub.native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; } // add 'sign' items with wallet sign diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h index 4bd1f71694..6252b37771 100644 --- a/modules/service/voting/include/dap_chain_net_srv_voting.h +++ b/modules/service/voting/include/dap_chain_net_srv_voting.h @@ -94,13 +94,14 @@ enum DAP_CHAIN_NET_VOTE_CREATE_ERROR { DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID, DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT, - + DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN, + DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_TOKEN, DAP_CHAIN_NET_VOTE_CREATE_UNKNOWN_ERR }; int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, - dap_chain_net_t *a_net, const char *a_hash_out_type, char **a_hash_output); + dap_chain_net_t *a_net, const char *a_token_ticker, const char *a_hash_out_type, char **a_hash_output); enum DAP_CHAIN_NET_VOTE_VOTING_ERROR{ DAP_CHAIN_NET_VOTE_VOTING_OK, @@ -131,7 +132,6 @@ enum DAP_CHAIN_NET_VOTE_VOTING_ERROR{ DAP_CHAIN_NET_VOTE_VOTING_WALLET_PARAM_NOT_VALID, DAP_CHAIN_NET_VOTE_VOTING_OPTION_IDX_PARAM_NOT_VALID, DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST, - DAP_CHAIN_NET_VOTE_VOTING_UNKNOWN_ERR, DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW -- GitLab From 680aaeeb264c584be8f389934fb936900398eb3d Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Tue, 4 Mar 2025 15:52:24 +0700 Subject: [PATCH 03/53] [*] Voting bugfixes --- .../service/voting/dap_chain_net_srv_voting.c | 328 ++++++++---------- .../voting/include/dap_chain_net_srv_voting.h | 1 - 2 files changed, 152 insertions(+), 177 deletions(-) diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index 6f55e66960..a447a584e3 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -61,7 +61,7 @@ typedef struct dap_chain_net_vote_option { typedef struct dap_chain_net_voting_cond_outs { dap_chain_hash_fast_t tx_hash; int out_idx; - + dap_hash_fast_t pkey_hash; UT_hash_handle hh; } dap_chain_net_voting_cond_outs_t; @@ -87,9 +87,10 @@ typedef struct dap_chain_net_votings { static dap_chain_net_votings_t *s_votings; static pthread_rwlock_t s_votings_rwlock; -static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx); +static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx, dap_hash_fast_t *a_vote_hash); /// -1 error, 0 - unspent, 1 - spent -static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash); +static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, + dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash); static int s_datum_tx_voting_verification_callback(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in, dap_hash_fast_t *a_tx_hash, bool a_apply); static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in); static int s_cli_voting(int argc, char **argv, void **a_str_reply); @@ -174,7 +175,6 @@ uint64_t* dap_chain_net_voting_get_result(dap_ledger_t* a_ledger, dap_chain_hash return l_voting_results; } - static int s_voting_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in, dap_hash_fast_t *a_tx_hash, bool a_apply) { if (!a_apply) { @@ -315,79 +315,57 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a return -5; } - dap_hash_fast_t pkey_hash = {}; - // Get sign item from transaction - dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(a_tx_in, NULL, NULL, TX_ITEM_TYPE_SIG, NULL); - dap_sign_get_pkey_hash((dap_sign_t *)l_tx_sig->sig, &pkey_hash); + // Get last sign item from transaction + dap_hash_fast_t l_pkey_hash = {}; + dap_sign_t *l_pkey_sign = NULL; + uint8_t *l_tx_item = NULL; size_t l_size; int i, l_sign_num = 0; + TX_ITEM_ITER_TX_TYPE(l_tx_item, TX_ITEM_TYPE_SIG, l_size, i, a_tx_in) { + l_pkey_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_item); + l_sign_num++; + } + dap_sign_get_pkey_hash(l_pkey_sign, &l_pkey_hash); + if (--l_sign_num && dap_chain_datum_tx_verify_sign(a_tx_in, l_sign_num)) { + log_it(L_WARNING, "Last vote tx %s sign verification failed", dap_chain_hash_fast_to_str_static(a_tx_hash)); + return -22; + } - if (!a_apply) { - if (l_vote_tx_item->answer_idx > dap_list_length(l_voting->voting_params.option_offsets_list)) { - log_it(L_WARNING, "Invalid vote option index %" DAP_UINT64_FORMAT_U " for vote tx %s", - l_vote_tx_item->answer_idx, dap_chain_hash_fast_to_str_static(a_tx_hash)); - return -6; - } - if (l_voting->voting_params.votes_max_count && dap_list_length(l_voting->votes) >= l_voting->voting_params.votes_max_count){ - log_it(L_WARNING, "The required number of votes has been collected for voting %s", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash)); - return -7; - } - if (l_voting->voting_params.voting_expire && l_voting->voting_params.voting_expire <= a_tx_in->header.ts_created) { - log_it(L_WARNING, "The voting %s has been expired", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash)); - return -8; - } + if (l_vote_tx_item->answer_idx > dap_list_length(l_voting->voting_params.option_offsets_list)) { + log_it(L_WARNING, "Invalid vote option index %" DAP_UINT64_FORMAT_U " for vote tx %s", + l_vote_tx_item->answer_idx, dap_chain_hash_fast_to_str_static(a_tx_hash)); + return -6; + } + if (l_voting->voting_params.votes_max_count && dap_list_length(l_voting->votes) >= l_voting->voting_params.votes_max_count){ + log_it(L_WARNING, "The required number of votes has been collected for voting %s", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash)); + return -7; + } + if (l_voting->voting_params.voting_expire && l_voting->voting_params.voting_expire <= a_tx_in->header.ts_created) { + log_it(L_WARNING, "The voting %s has been expired", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash)); + return -8; + } - if (l_voting->voting_params.delegate_key_required && - !dap_chain_net_srv_stake_check_pkey_hash(a_ledger->net->pub.id, &pkey_hash)){ - log_it(L_WARNING, "Voting %s required a delegated key", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash)); - return -10; - } + if (l_voting->voting_params.delegate_key_required && + !dap_chain_net_srv_stake_check_pkey_hash(a_ledger->net->pub.id, &l_pkey_hash)){ + log_it(L_WARNING, "Voting %s required a delegated key", dap_chain_hash_fast_to_str_static(&l_voting->voting_hash)); + return -10; + } - for (dap_list_t *it = l_voting->votes; it; it = it->next) { - if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &pkey_hash)) { - dap_hash_fast_t *l_vote_hash = &((dap_chain_net_vote_t *)it->data)->vote_hash; - if (!l_voting->voting_params.vote_changing_allowed) { - char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE]; - dap_hash_fast_to_str(l_vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE); - log_it(L_WARNING, "The voting %s don't allow change your vote %s", - dap_hash_fast_to_str_static(&l_voting->voting_hash), l_vote_hash_str); - return -11; - } - break; + dap_list_t *l_old_vote = NULL; + for (dap_list_t *it = l_voting->votes; it; it = it->next) { + if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &l_pkey_hash)) { + dap_hash_fast_t *l_vote_hash = &((dap_chain_net_vote_t *)it->data)->vote_hash; + if (!l_voting->voting_params.vote_changing_allowed) { + char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE]; + dap_hash_fast_to_str(l_vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE); + log_it(L_WARNING, "The voting %s don't allow change your vote %s", + dap_hash_fast_to_str_static(&l_voting->voting_hash), l_vote_hash_str); + return -11; } + l_old_vote = it; + break; } } uint256_t l_weight = {}; - - // check out conds - dap_list_t *l_tsd_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_TSD, NULL); - for (dap_list_t *it = l_tsd_list; it; it = it->next) { - dap_tsd_t *l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t*)it->data)->tsd; - dap_hash_fast_t l_hash = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->tx_hash; - int l_out_idx = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->out_idx; - if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND) - return -14; - dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash); - dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_out_idx); - if (!l_prev_out || l_prev_out->header.item_type != TX_ITEM_TYPE_OUT_COND || l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) - return -16; - if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, (dap_sign_t *)l_tx_sig->sig)) - return -17; - if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx)) - return -15; - if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) { - log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); - return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW; - } - if (a_apply) { - dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY); - l_item->tx_hash = l_hash; - l_item->out_idx = l_out_idx; - pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock); - HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item); - pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock); - } - } - dap_list_free(l_tsd_list); // check inputs dap_list_t *l_ins_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_IN, NULL); if (!l_ins_list) { @@ -416,7 +394,7 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a if (dap_strcmp(l_ticker_in, l_voting->voting_params.token_ticker)) continue; if (s_datum_tx_voting_coin_check_spent(a_ledger->net, l_vote_tx_item->voting_hash, - l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx, &pkey_hash)) { + l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx, &l_pkey_hash)) { log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx, dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash)); return -20; @@ -433,62 +411,75 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a return -13; } + // check out conds + dap_list_t *l_tsd_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_TSD, NULL); + for (dap_list_t *it = l_tsd_list; it; it = it->next) { + dap_tsd_t *l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t*)it->data)->tsd; + dap_hash_fast_t l_hash = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->tx_hash; + int l_out_idx = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->out_idx; + if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND) + return -14; + dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash); + dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_out_idx); + if (!l_prev_out || l_prev_out->header.item_type != TX_ITEM_TYPE_OUT_COND || + l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) + return -16; + if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, l_pkey_sign)) + return -17; + if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx, &l_pkey_hash)) + return -15; + if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) { + log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW; + } + } + if (a_apply) { + // Mark conditional outs + pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock); + if (l_old_vote) { + dap_hash_fast_t *l_vote_hash = &((dap_chain_net_vote_t *)l_old_vote->data)->vote_hash; + dap_chain_net_voting_cond_outs_t *it = NULL, *tmp; + HASH_ITER(hh, l_voting->voting_spent_cond_outs, it, tmp) { + if (!dap_hash_fast_compare(l_vote_hash, &it->pkey_hash)) + continue; + HASH_DEL(l_voting->voting_spent_cond_outs, it); + DAP_DELETE(it); + } + } + for (dap_list_t *it = l_tsd_list; it; it = it->next) { + dap_tsd_t *l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t *)it->data)->tsd; + if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND) + continue; + dap_chain_net_voting_cond_outs_t *l_tx_out = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY); + l_tx_out->tx_hash = ((dap_chain_tx_voting_tx_cond_t *)l_tsd->data)->tx_hash; + l_tx_out->out_idx = ((dap_chain_tx_voting_tx_cond_t *)l_tsd->data)->out_idx; + l_tx_out->pkey_hash = l_pkey_hash; + HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_tx_out); + } + pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock); + dap_chain_net_vote_t *l_vote_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_vote_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY); l_vote_item->vote_hash = *a_tx_hash; - l_vote_item->pkey_hash = pkey_hash; + l_vote_item->pkey_hash = l_pkey_hash; l_vote_item->answer_idx = l_vote_tx_item->answer_idx; l_vote_item->weight = l_weight; - // cycle is safe cause return after link deletion - for (dap_list_t *it = l_voting->votes; it; it = it->next) { - if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &pkey_hash)){ - if (!l_voting->voting_params.vote_changing_allowed) { - char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE]; - dap_hash_fast_to_str(a_tx_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE); - log_it(L_WARNING, "The voting %s don't allow change your vote %s", - dap_hash_fast_to_str_static(&l_voting->voting_hash), l_vote_hash_str); - DAP_DELETE(l_vote_item); - return -11; - } - dap_hash_fast_t *l_vote_hash = &((dap_chain_net_vote_t *)it->data)->vote_hash; - //delete conditional outputs - dap_chain_datum_tx_t *l_old_tx = dap_ledger_tx_find_by_hash(a_ledger, l_vote_hash); - if (!l_old_tx) { - char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE]; - dap_hash_fast_to_str(l_vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE); - log_it(L_ERROR, "Can't find old vote %s of voting %s in ledger", - l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); - } - dap_list_t* l_tsd_list = dap_chain_datum_tx_items_get(l_old_tx, TX_ITEM_TYPE_TSD, NULL); - for (dap_list_t *it_tsd = l_tsd_list; it_tsd; it_tsd = it_tsd->next) { - dap_tsd_t* l_tsd = (dap_tsd_t*)((dap_chain_tx_tsd_t*)it_tsd->data)->tsd; - dap_hash_fast_t *l_hash = &((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->tx_hash; - if (l_tsd->type == VOTING_TSD_TYPE_VOTE_TX_COND) { - dap_chain_net_voting_cond_outs_t *l_tx_outs = NULL; - pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock); - HASH_FIND(hh, l_voting->voting_spent_cond_outs, l_hash, sizeof(dap_hash_fast_t), l_tx_outs); - if(l_tx_outs) - HASH_DELETE(hh, l_voting->voting_spent_cond_outs, l_tx_outs); - pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock); - } - } - dap_list_free(l_tsd_list); - // change vote & move it to the end of list - l_voting->votes = dap_list_remove_link(l_voting->votes, it); - l_voting->votes = dap_list_append(l_voting->votes, l_vote_item); - char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE]; - dap_hash_fast_to_str(&((dap_chain_net_vote_t *)it->data)->vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE); - DAP_DELETE(it->data); - log_it(L_NOTICE, "Vote %s of voting %s has been changed", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); - return DAP_LEDGER_CHECK_OK; - } + if (l_old_vote) { + // change vote & move it to the end of list + const char *l_vote_hash_str = dap_hash_fast_to_str_static(&((dap_chain_net_vote_t *)l_old_vote->data)->vote_hash); + DAP_DELETE(l_old_vote->data); + l_voting->votes = dap_list_delete_link(l_voting->votes, l_old_vote); + log_it(L_NOTICE, "Vote %s of voting %s has been changed", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); + } else { + const char *l_vote_hash_str = dap_hash_fast_to_str_static(a_tx_hash); + log_it(L_NOTICE, "Vote %s of voting %s has been accepted", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); } + l_voting->votes = dap_list_append(l_voting->votes, l_vote_item); - char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE]; - dap_hash_fast_to_str(a_tx_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE); - log_it(L_NOTICE, "Vote %s of voting %s has been accepted", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); } + dap_list_free(l_tsd_list); + return DAP_LEDGER_CHECK_OK; } @@ -916,11 +907,6 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED, "This voting required a delegated key. Parameter -cert must contain a valid certificate name"); } break; - case DAP_CHAIN_NET_VOTE_VOTING_NO_PUBLIC_KEY_IN_CERT: { - dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_NO_PUBLIC_KEY_IN_CERT, - "Can't serialize public key of certificate \"%s\"", - l_cert_name); - } break; case DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED: { dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED, "Your key is not delegated."); } break; @@ -1090,7 +1076,8 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) return 0; } -static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash) +static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, + dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash) { int l_coin_is_spent = 0; @@ -1120,7 +1107,7 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f return 0; } - if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, a_tx_prev_hash, a_out_idx) != 0){ + if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, a_tx_prev_hash, a_out_idx, a_pkey_hash) != 0){ return 1; } @@ -1140,10 +1127,8 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f dap_list_t *l_ins_list_temp = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL); dap_list_t *l_cond_ins_list = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_COND, NULL); - if (!l_ins_list_temp && !l_cond_ins_list){ - log_it(L_ERROR, "Can't get inputs from tx"); - return -1; - } + if (!l_ins_list_temp && !l_cond_ins_list) // it's emisssion or reward TX, not marked yet + return 0; dap_list_t *l_ins_list = dap_list_concat(l_ins_list_temp, l_cond_ins_list); dap_list_t *l_tx_list = dap_list_append(NULL, l_ins_list); // "stack" for saving txs on up level @@ -1185,7 +1170,7 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f break; } if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, l_temp_in->header.tx_prev_hash, - l_temp_in->header.tx_out_prev_idx) != 0) { + l_temp_in->header.tx_out_prev_idx, a_pkey_hash) != 0) { l_coin_is_spent = 1; continue; } @@ -1205,16 +1190,18 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f continue; } - dap_chain_tx_vote_t *l_vote =(dap_chain_tx_vote_t *) dap_chain_datum_tx_item_get(l_tx_prev_temp, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL); - if(l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)){ - dap_list_t *l_temp = NULL; - while (l_temp){ - dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)l_temp->data; - if (dap_hash_fast_compare(&l_vote->vote_hash, &l_temp_in->header.tx_prev_hash)){ + dap_chain_tx_vote_t *l_vote = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(l_tx_prev_temp, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL); + if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)) { + for (dap_list_t *it = l_voting->votes; it; it = it->next) { + dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data; + if (dap_hash_fast_compare(&l_vote->vote_hash, &l_temp_in->header.tx_prev_hash)) { + if (l_voting->voting_params.vote_changing_allowed && + !dap_hash_fast_is_blank(a_pkey_hash) && + dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash)) + break; // it's vote changing, allow it l_coin_is_spent = 1; break; } - l_temp = l_temp->next; } } @@ -1237,7 +1224,9 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f return l_coin_is_spent; } -static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx) +static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, + dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx, + dap_hash_fast_t *a_pkey_hash) { dap_chain_net_votings_t * l_voting = NULL; @@ -1250,16 +1239,15 @@ static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_has return -1; } - dap_chain_net_voting_cond_outs_t *l_tx_outs = NULL; + dap_chain_net_voting_cond_outs_t *l_tx_out = NULL; pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock); - HASH_FIND(hh, l_voting->voting_spent_cond_outs, &a_tx_cond_hash, sizeof(dap_hash_fast_t), l_tx_outs); + HASH_FIND(hh, l_voting->voting_spent_cond_outs, &a_tx_cond_hash, sizeof(dap_hash_fast_t), l_tx_out); pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock); - if (!l_tx_outs || l_tx_outs->out_idx != a_cond_out_idx){ - return 0; - } + if (l_tx_out && l_tx_out->out_idx == a_cond_out_idx) + return a_pkey_hash ? !dap_hash_fast_compare(a_pkey_hash, &l_tx_out->pkey_hash) : 1; - return 1; + return 0; } int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, @@ -1467,37 +1455,25 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal if (l_voting->voting_params.voting_expire && dap_time_now() > l_voting->voting_params.voting_expire) return DAP_CHAIN_NET_VOTE_VOTING_ALREADY_EXPIRED; - dap_hash_fast_t l_pkey_hash = {0}; + dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, a_net->pub.id); + if (!l_addr_from) + return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID; + dap_hash_fast_t l_pkey_hash = {0}; if (l_voting->voting_params.delegate_key_required) { if (!a_cert) return DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED; - if (!a_cert->enc_key) + if (dap_cert_get_pkey_hash(a_cert, &l_pkey_hash)) return DAP_CHAIN_NET_VOTE_VOTING_NO_KEY_FOUND_IN_CERT; - // Get publivc key hash - size_t l_pub_key_size = 0; - uint8_t *l_pub_key = dap_enc_key_serialize_pub_key(a_cert->enc_key, &l_pub_key_size);; - if (l_pub_key == NULL) - return DAP_CHAIN_NET_VOTE_VOTING_NO_PUBLIC_KEY_IN_CERT; - - dap_hash_fast(l_pub_key, l_pub_key_size, &l_pkey_hash); - DAP_DELETE(l_pub_key); if (!dap_chain_net_srv_stake_check_pkey_hash(a_net->pub.id, &l_pkey_hash)) return DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED; - for (dap_list_t *it = l_voting->votes; it; it = it->next) - if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &l_pkey_hash) && - !l_voting->voting_params.vote_changing_allowed) - return DAP_CHAIN_NET_VOTE_VOTING_DOES_NOT_ALLOW_CHANGE_YOUR_VOTE; - } - - dap_enc_key_t *l_priv_key = NULL; - - l_priv_key = dap_chain_wallet_get_key(a_wallet, 0); - - const dap_chain_addr_t *l_addr_from = (const dap_chain_addr_t *) dap_chain_wallet_get_addr(a_wallet, a_net->pub.id); + } else + l_pkey_hash = l_addr_from->data.hash_fast; - if (!l_addr_from) - return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID; + for (dap_list_t *it = l_voting->votes; it; it = it->next) + if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &l_pkey_hash) && + !l_voting->voting_params.vote_changing_allowed) + return DAP_CHAIN_NET_VOTE_VOTING_DOES_NOT_ALLOW_CHANGE_YOUR_VOTE; const char *l_token_ticker = l_voting->voting_params.token_ticker; uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer; @@ -1519,9 +1495,8 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal dap_list_t *it, *tmp; DL_FOREACH_SAFE(l_list_used_out, it, tmp) { dap_chain_tx_used_out_item_t *l_out = (dap_chain_tx_used_out_item_t *)it->data; - if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out, &l_pkey_hash) && - !l_voting->voting_params.vote_changing_allowed) { - dap_list_delete_link(l_list_used_out, it); + if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out, &l_pkey_hash)) { + l_list_used_out = dap_list_delete_link(l_list_used_out, it); continue; } if (SUM_256_256(l_value_transfer_new, l_out->value, &l_value_transfer_new)) @@ -1572,7 +1547,7 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from); for (dap_list_t *it = l_outs; it; it = it->next) { dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data; - if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out) != 0) + if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out, &l_pkey_hash) != 0) continue; dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out); if(!l_item){ @@ -1608,18 +1583,19 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; } + dap_enc_key_t *l_priv_key = dap_chain_wallet_get_key(a_wallet, 0); // add 'sign' items with wallet sign - if(dap_chain_datum_tx_add_sign_item(&l_tx, l_priv_key) != 1) { + if (dap_chain_datum_tx_add_sign_item(&l_tx, l_priv_key) != 1) { dap_chain_datum_tx_delete(l_tx); + dap_enc_key_delete(l_priv_key); return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX; } + dap_enc_key_delete(l_priv_key); // add 'sign' items with delegated key if needed - if(a_cert){ - if(dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX; - } + if (a_cert && dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX; } size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx); diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h index 6252b37771..8c61bc51d1 100644 --- a/modules/service/voting/include/dap_chain_net_srv_voting.h +++ b/modules/service/voting/include/dap_chain_net_srv_voting.h @@ -109,7 +109,6 @@ enum DAP_CHAIN_NET_VOTE_VOTING_ERROR{ DAP_CHAIN_NET_VOTE_VOTING_THIS_VOTING_HAVE_MAX_VALUE_VOTES, DAP_CHAIN_NET_VOTE_VOTING_ALREADY_EXPIRED, DAP_CHAIN_NET_VOTE_VOTING_NO_KEY_FOUND_IN_CERT, - DAP_CHAIN_NET_VOTE_VOTING_NO_PUBLIC_KEY_IN_CERT, DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED, DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED, DAP_CHAIN_NET_VOTE_VOTING_DOES_NOT_ALLOW_CHANGE_YOUR_VOTE, -- GitLab From 4e94194671c71d524645cf9b67b87842a455705b Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Tue, 4 Mar 2025 16:10:32 +0700 Subject: [PATCH 04/53] [-] Debug code --- modules/consensus/esbocs/dap_chain_cs_esbocs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c index f7c088e54b..dea80a38fd 100644 --- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c +++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c @@ -837,7 +837,7 @@ static dap_list_t *s_get_validators_list(dap_chain_esbocs_t *a_esbocs, dap_hash_ dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_esbocs); dap_list_t *l_ret = NULL; dap_list_t *l_validators = NULL; - if (l_esbocs_pvt->poa_mode) { // UNDO it after debug + if (!l_esbocs_pvt->poa_mode) { if (a_excluded_list_size) { l_validators = dap_chain_net_srv_stake_get_validators(a_esbocs->chain->net_id, false, NULL); uint16_t l_excluded_num = *a_excluded_list; -- GitLab From 0203d211c22944dfa41c5b217c30916bcd344a9b Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Tue, 4 Mar 2025 16:31:59 +0700 Subject: [PATCH 05/53] [*] Help clarification --- modules/service/voting/dap_chain_net_srv_voting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index a447a584e3..bc69703081 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -118,7 +118,7 @@ int dap_chain_net_srv_voting_init() dap_chain_ledger_voting_verificator_add(s_datum_tx_voting_verification_callback, s_datum_tx_voting_verification_delete_callback); dap_cli_server_cmd_add("voting", s_cli_voting, "Voting commands.", "" "voting create -net <net_name> -question <\"Question_string\"> -options <\"Option0\", \"Option1\" ... \"OptionN\"> [-expire <voting_expire_time_in_RCF822>]" - " [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name> -token <ticker>\n" + " [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name> [-token <ticker>]\n" "voting vote -net <net_name> -hash <voting_hash> -option_idx <option_index> [-cert <delegate_cert_name>] -fee <value_datoshi> -w <fee_wallet_name>\n" "voting list -net <net_name>\n" "voting dump -net <net_name> -hash <voting_hash>\n"); -- GitLab From ee46625e37570f59ba4c26202a78332d45be63be Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Wed, 5 Mar 2025 13:42:14 +0700 Subject: [PATCH 06/53] [*] Cond out list compound fix --- dap-sdk | 2 +- .../consensus/esbocs/dap_chain_cs_esbocs.c | 2 +- modules/net/dap_chain_ledger.c | 5 ++-- .../service/voting/dap_chain_net_srv_voting.c | 30 ++++++++++++------- .../voting/include/dap_chain_net_srv_voting.h | 1 + 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/dap-sdk b/dap-sdk index 3491640b76..a7b6da64ee 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit 3491640b76de5715eb3936ccd377abd51d88b99e +Subproject commit a7b6da64ee24a3aba64dcbbd5f3f356069d853ad diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c index dea80a38fd..c54ba27b9f 100644 --- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c +++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c @@ -837,7 +837,7 @@ static dap_list_t *s_get_validators_list(dap_chain_esbocs_t *a_esbocs, dap_hash_ dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_esbocs); dap_list_t *l_ret = NULL; dap_list_t *l_validators = NULL; - if (!l_esbocs_pvt->poa_mode) { + if (l_esbocs_pvt->poa_mode) { if (a_excluded_list_size) { l_validators = dap_chain_net_srv_stake_get_validators(a_esbocs->chain->net_id, false, NULL); uint16_t l_excluded_num = *a_excluded_list; diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index deaac956e7..49b6f840a8 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -5670,11 +5670,10 @@ dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t * l_iter_start = l_iter_start->hh.next; } else l_iter_start = l_ledger_pvt->ledger_items; - for (it = l_iter_start; it; it = it->hh.next) { + for (it = l_iter_start; it; it = it->hh.next, ret = NULL) { // If a_token is setup we check if its not our token - miss it if (*it->cache_data.token_ticker && dap_strcmp(it->cache_data.token_ticker, a_token)) continue; - ret = NULL; // Get 'out_cond' item from transaction byte_t *l_item; size_t l_size; int i, l_out_idx = 0; TX_ITEM_ITER_TX_TYPE(l_item, TX_ITEM_TYPE_OUT_ALL, l_size, i, it->tx) { @@ -5699,7 +5698,7 @@ dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t * continue; } // Get sign item from transaction - dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_SIG, NULL); + dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_SIG, NULL); // Get dap_sign_t from item dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); // compare public key in transaction with a_public_key diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index bc69703081..3e057d8856 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -394,7 +394,8 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a if (dap_strcmp(l_ticker_in, l_voting->voting_params.token_ticker)) continue; if (s_datum_tx_voting_coin_check_spent(a_ledger->net, l_vote_tx_item->voting_hash, - l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx, &l_pkey_hash)) { + l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx, + l_old_vote ? &l_pkey_hash : NULL)) { log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx, dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash)); return -20; @@ -426,7 +427,8 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a return -16; if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, l_pkey_sign)) return -17; - if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx, &l_pkey_hash)) + if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx, + l_old_vote ? &l_pkey_hash : NULL)) return -15; if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) { log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); @@ -830,10 +832,11 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) } dap_hash_fast_t l_voting_hash = {}; - dap_chain_hash_fast_from_str(l_hash_str, &l_voting_hash); - + if (dap_chain_hash_fast_from_str(l_hash_str, &l_voting_hash)) { + dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID, "Hash string is not recognozed as hex of base58 hash"); + return -DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID; + } - dap_chain_hash_fast_t l_pkey_hash; dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_name); dap_cert_t * l_cert = dap_cert_find_by_name(l_cert_name); if (l_cert_name){ @@ -1067,7 +1070,6 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) const char *l_tw_coins, *l_tw_datoshi = dap_uint256_to_char(l_total_weight, &l_tw_coins); json_object_object_add(json_vote_out, "total_sum", json_object_new_string(l_tw_coins)); json_object_object_add(json_vote_out, "total_sum_datoshi", json_object_new_string(l_tw_datoshi)); - json_object_object_add(json_vote_out, "ticker", json_object_new_string(l_net->pub.native_ticker)); json_object_array_add(*json_arr_reply, json_vote_out); } break; default: @@ -1470,10 +1472,14 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal } else l_pkey_hash = l_addr_from->data.hash_fast; + bool l_vote_changed = false; for (dap_list_t *it = l_voting->votes; it; it = it->next) - if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &l_pkey_hash) && - !l_voting->voting_params.vote_changing_allowed) - return DAP_CHAIN_NET_VOTE_VOTING_DOES_NOT_ALLOW_CHANGE_YOUR_VOTE; + if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)it->data)->pkey_hash, &l_pkey_hash)) { + if (!l_voting->voting_params.vote_changing_allowed) + return DAP_CHAIN_NET_VOTE_VOTING_DOES_NOT_ALLOW_CHANGE_YOUR_VOTE; + l_vote_changed = true; + break; + } const char *l_token_ticker = l_voting->voting_params.token_ticker; uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer; @@ -1495,7 +1501,8 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal dap_list_t *it, *tmp; DL_FOREACH_SAFE(l_list_used_out, it, tmp) { dap_chain_tx_used_out_item_t *l_out = (dap_chain_tx_used_out_item_t *)it->data; - if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out, &l_pkey_hash)) { + if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out, + l_vote_changed ? &l_pkey_hash : NULL)) { l_list_used_out = dap_list_delete_link(l_list_used_out, it); continue; } @@ -1547,7 +1554,8 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from); for (dap_list_t *it = l_outs; it; it = it->next) { dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data; - if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out, &l_pkey_hash) != 0) + if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out, + l_vote_changed ? &l_pkey_hash : NULL) != 0) continue; dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out); if(!l_item){ diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h index 8c61bc51d1..7efdd2d656 100644 --- a/modules/service/voting/include/dap_chain_net_srv_voting.h +++ b/modules/service/voting/include/dap_chain_net_srv_voting.h @@ -125,6 +125,7 @@ enum DAP_CHAIN_NET_VOTE_VOTING_ERROR{ DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING, DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_NOT_VALID, DAP_CHAIN_NET_VOTE_VOTING_HASH_NOT_FOUND, + DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID, DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_FIND_CERT, DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_NOT_VALID, DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_BAD_TYPE, -- GitLab From bdccd2ffe867f59a5d72a34c50cab225353788e5 Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Wed, 5 Mar 2025 14:07:51 +0700 Subject: [PATCH 07/53] [+] Owner wallet address for delegation txs --- modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c index 59320cec6d..7655ee5239 100644 --- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c +++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c @@ -3523,6 +3523,9 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply) json_object_object_add(l_json_obj_tx, "node_address", json_object_new_string(l_node_address_text_block)); json_object_object_add(l_json_obj_tx, "value_coins", json_object_new_string(l_coins)); json_object_object_add(l_json_obj_tx, "value_datoshi", json_object_new_string(l_balance)); + dap_sign_t *l_owner_sign = dap_chain_datum_tx_get_sign(l_datum_tx, 0); + dap_chain_addr_t l_owner_addr; dap_chain_addr_fill_from_sign(&l_owner_addr, l_owner_sign, l_net->pub.id); + json_object_object_add(l_json_obj_tx, "owner_addr", json_object_new_string(dap_chain_addr_to_str_static(&l_owner_addr))); json_object_array_add(l_json_arr_tx, l_json_obj_tx); DAP_DELETE(l_node_address_text_block); } -- GitLab From d8a622c72189648642480fc2b64c2ccc2f9e6a18 Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Wed, 5 Mar 2025 14:20:26 +0700 Subject: [PATCH 08/53] [*] Onwage definition fix for delegation txs --- .../service/stake/dap_chain_net_srv_stake_pos_delegate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c index 7655ee5239..6339b40935 100644 --- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c +++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c @@ -3523,7 +3523,11 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply) json_object_object_add(l_json_obj_tx, "node_address", json_object_new_string(l_node_address_text_block)); json_object_object_add(l_json_obj_tx, "value_coins", json_object_new_string(l_coins)); json_object_object_add(l_json_obj_tx, "value_datoshi", json_object_new_string(l_balance)); - dap_sign_t *l_owner_sign = dap_chain_datum_tx_get_sign(l_datum_tx, 0); + dap_hash_fast_t l_owner_hash = dap_ledger_get_first_chain_tx_hash(l_net->pub.ledger, l_datum_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE); + dap_chain_datum_tx_t *l_owner_tx = dap_hash_fast_is_blank(&l_owner_hash) ? l_datum_tx + : dap_ledger_tx_find_datum_by_hash(l_net->pub.ledger, &l_owner_hash, NULL, false); + assert(l_owner_tx); + dap_sign_t *l_owner_sign = dap_chain_datum_tx_get_sign(l_owner_tx, 0); dap_chain_addr_t l_owner_addr; dap_chain_addr_fill_from_sign(&l_owner_addr, l_owner_sign, l_net->pub.id); json_object_object_add(l_json_obj_tx, "owner_addr", json_object_new_string(dap_chain_addr_to_str_static(&l_owner_addr))); json_object_array_add(l_json_arr_tx, l_json_obj_tx); -- GitLab From 07a967211d7cc2812597629333c114fd513ce8d5 Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Wed, 5 Mar 2025 15:20:36 +0700 Subject: [PATCH 09/53] [-] Debug code --- modules/consensus/esbocs/dap_chain_cs_esbocs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c index c54ba27b9f..dea80a38fd 100644 --- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c +++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c @@ -837,7 +837,7 @@ static dap_list_t *s_get_validators_list(dap_chain_esbocs_t *a_esbocs, dap_hash_ dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_esbocs); dap_list_t *l_ret = NULL; dap_list_t *l_validators = NULL; - if (l_esbocs_pvt->poa_mode) { + if (!l_esbocs_pvt->poa_mode) { if (a_excluded_list_size) { l_validators = dap_chain_net_srv_stake_get_validators(a_esbocs->chain->net_id, false, NULL); uint16_t l_excluded_num = *a_excluded_list; -- GitLab From d9ac93979d88c7145f1dac3ce136fee67a6fb666 Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Thu, 6 Mar 2025 16:06:21 +0700 Subject: [PATCH 10/53] [+] Printing unspent OUT_CONDs for wallet --- modules/net/dap_chain_node_cli.c | 2 +- modules/net/dap_chain_node_cli_cmd.c | 53 +++++++++++++++++----------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c index 5faac29320..85b96544b5 100644 --- a/modules/net/dap_chain_node_cli.c +++ b/modules/net/dap_chain_node_cli.c @@ -159,7 +159,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config) "wallet info {-addr <addr> | -w <wallet_name>} -net <net_name>\n" "wallet activate -w <wallet_name> -password <password> [-ttl <password_ttl_in_minutes>]\n" "wallet deactivate -w <wallet_name>>\n" - "wallet outputs {-addr <addr> | -w <wallet_name>} -net <net_name> -token <token_tiker> [-value <uint256_value>]\n" + "wallet outputs {-addr <addr> | -w <wallet_name>} -net <net_name> -token <token_tiker> [{-cond | -value <uint256_value>}]\n" "wallet convert -w <wallet_name> {-password <password> | -remove_password }\n"); diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index a5db76bcfe..a057b6f560 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -1799,45 +1799,56 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; return DAP_CHAIN_NODE_CLI_COM_TX_WALLET_PARAM_ERR; } json_object * json_obj_wall = json_object_new_object(); - const char* l_value_str = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); + const char *l_cond_str, *l_value_str = NULL; + uint256_t l_value_datoshi = uint256_0, l_value_sum = uint256_0; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cond", &l_cond_str); + if (!l_cond_str) { + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); + if (l_value_str) { + l_value_datoshi = dap_chain_balance_scan(l_value_str); + if (IS_ZERO_256(l_value_datoshi)) { + dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_TX_WALLET_PARAM_ERR, + "Can't convert -value param to 256bit integer"); + json_object_put(json_arr_out); + return DAP_CHAIN_NODE_CLI_COM_TX_WALLET_PARAM_ERR; + } + } + } dap_list_t *l_outs_list = NULL; - uint256_t l_value_sum = uint256_0; - - - if (l_value_str){ - uint256_t l_value_datoshi = dap_chain_balance_scan(l_value_str); + if (l_value_str) { if (dap_chain_wallet_cache_tx_find_outs_with_val(l_net, l_token_tiker, l_addr, &l_outs_list, l_value_datoshi, &l_value_sum)) l_outs_list = dap_ledger_get_list_tx_outs_with_val(l_net->pub.ledger, l_token_tiker, l_addr, l_value_datoshi, &l_value_sum); + } else if (l_cond_str) { + l_outs_list = dap_ledger_get_list_tx_cond_outs(l_net->pub.ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_tiker, l_addr); } else { if (dap_chain_wallet_cache_tx_find_outs(l_net, l_token_tiker, l_addr, &l_outs_list, &l_value_sum)) l_outs_list = dap_ledger_get_list_tx_outs(l_net->pub.ledger, l_token_tiker, l_addr, &l_value_sum); } json_object_object_add(json_obj_wall, "wallet_addr", json_object_new_string(dap_chain_addr_to_str_static(l_addr))); - const char *l_out_total_value_str = dap_chain_balance_print(l_value_sum); - const char *l_out_total_value_coins_str = dap_chain_balance_to_coins(l_value_sum); - json_object_object_add(json_obj_wall, "total_value_coins", json_object_new_string(l_out_total_value_coins_str)); - json_object_object_add(json_obj_wall, "total_value_datoshi", json_object_new_string(l_out_total_value_str)); - DAP_DEL_Z(l_out_total_value_str); - DAP_DEL_Z(l_out_total_value_coins_str); struct json_object *l_json_outs_arr = json_object_new_array(); - for (dap_list_t *l_temp = l_outs_list; l_temp; l_temp = l_temp->next){ + if (!l_json_outs_arr) + return json_object_put(json_arr_out), DAP_CHAIN_NODE_CLI_COM_TX_WALLET_MEMORY_ERR; + for (dap_list_t *l_temp = l_outs_list; l_temp; l_temp = l_temp->next) { + json_object *json_obj_item = json_object_new_object(); + if (!json_obj_item) + return json_object_put(json_arr_out), DAP_CHAIN_NODE_CLI_COM_TX_WALLET_MEMORY_ERR; dap_chain_tx_used_out_item_t *l_item = l_temp->data; - json_object* json_obj_item = json_object_new_object(); - const char *l_out_value_str = dap_chain_balance_print(l_item->value); - const char *l_out_value_coins_str = dap_chain_balance_to_coins(l_item->value); + const char *l_out_value_coins_str, *l_out_value_str = dap_uint256_to_char(l_item->value, &l_out_value_coins_str); json_object_object_add(json_obj_item,"item_type", json_object_new_string("unspent_out")); json_object_object_add(json_obj_item,"value_coins", json_object_new_string(l_out_value_coins_str)); json_object_object_add(json_obj_item,"value_datosi", json_object_new_string(l_out_value_str)); - json_object_object_add(json_obj_item,"prev_hash", json_object_new_string(dap_hash_fast_to_str_static(&l_item->tx_hash_fast))); - json_object_object_add(json_obj_item,"out_prev_idx", json_object_new_int64(l_item->num_idx_out)); + json_object_object_add(json_obj_item,"prev_hash", json_object_new_string(dap_hash_fast_to_str_static(&l_item->tx_hash_fast))); + json_object_object_add(json_obj_item,"out_prev_idx", json_object_new_int64(l_item->num_idx_out)); json_object_array_add(l_json_outs_arr, json_obj_item); - DAP_DEL_Z(l_out_value_str); - DAP_DEL_Z(l_out_value_coins_str); + if (l_cond_str) + SUM_256_256(l_value_sum, l_item->value, &l_value_sum); } dap_list_free_full(l_outs_list, NULL); + const char * l_out_total_value_coins_str, *l_out_total_value_str = dap_uint256_to_char(l_value_sum, &l_out_total_value_coins_str); + json_object_object_add(json_obj_wall, "total_value_coins", json_object_new_string(l_out_total_value_coins_str)); + json_object_object_add(json_obj_wall, "total_value_datoshi", json_object_new_string(l_out_total_value_str)); json_object_object_add(json_obj_wall, "outs", l_json_outs_arr); json_object_array_add(json_arr_out, json_obj_wall); } break; -- GitLab From 4a754aa1de646b23e0bdf3d37fec0a9b5f96d918 Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Fri, 7 Mar 2025 14:13:43 +0700 Subject: [PATCH 11/53] [*] History assertion fix --- modules/net/dap_chain_node_cli_cmd.c | 4 ++-- modules/net/dap_chain_node_cli_cmd_tx.c | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index a057b6f560..4d23819b9a 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -1799,7 +1799,7 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; return DAP_CHAIN_NODE_CLI_COM_TX_WALLET_PARAM_ERR; } json_object * json_obj_wall = json_object_new_object(); - const char *l_cond_str, *l_value_str = NULL; + const char *l_cond_str = NULL, *l_value_str = NULL; uint256_t l_value_datoshi = uint256_0, l_value_sum = uint256_0; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cond", &l_cond_str); if (!l_cond_str) { @@ -1836,7 +1836,7 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; return json_object_put(json_arr_out), DAP_CHAIN_NODE_CLI_COM_TX_WALLET_MEMORY_ERR; dap_chain_tx_used_out_item_t *l_item = l_temp->data; const char *l_out_value_coins_str, *l_out_value_str = dap_uint256_to_char(l_item->value, &l_out_value_coins_str); - json_object_object_add(json_obj_item,"item_type", json_object_new_string("unspent_out")); + json_object_object_add(json_obj_item,"item_type", json_object_new_string(l_cond_str ? "unspent_cond_out" : "unspent_out")); json_object_object_add(json_obj_item,"value_coins", json_object_new_string(l_out_value_coins_str)); json_object_object_add(json_obj_item,"value_datosi", json_object_new_string(l_out_value_str)); json_object_object_add(json_obj_item,"prev_hash", json_object_new_string(dap_hash_fast_to_str_static(&l_item->tx_hash_fast))); diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index 0748ba83ce..edf553a80b 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -429,7 +429,7 @@ json_object* dap_db_history_addr(json_object* a_json_arr_reply, dap_chain_addr_t int l_src_subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_UNDEFINED; uint8_t *l_tx_item = NULL; size_t l_size; int i, q = 0; - // Проход по входам + // Inputs iteration TX_ITEM_ITER_TX_TYPE(l_tx_item, TX_ITEM_TYPE_IN_ALL, l_size, i, l_tx) { dap_chain_hash_fast_t *l_tx_prev_hash = NULL; int l_tx_prev_out_idx; @@ -562,7 +562,7 @@ json_object* dap_db_history_addr(json_object* a_json_arr_reply, dap_chain_addr_t if (l_src_addr && l_dst_addr && dap_chain_addr_compare(l_dst_addr, l_src_addr) && - dap_strcmp(l_noaddr_token, l_dst_token)) + l_noaddr_token && dap_strcmp(l_noaddr_token, l_dst_token)) continue; // sent to self (coinback) if (l_dst_addr && l_net_fee_used && dap_chain_addr_compare(&l_net_fee_addr, l_dst_addr)) @@ -698,9 +698,7 @@ json_object* dap_db_history_addr(json_object* a_json_arr_reply, dap_chain_addr_t json_object_object_add(l_corr_object, "recv_datoshi", json_object_new_string(l_value_str)); } if (l_send_to_same_cond) { - json_object *l_cond_recv_value_obj = json_object_object_get(l_cond_recv_object, "recv_datoshi"); - const char *l_cond_recv_value_str = json_object_get_string(l_cond_recv_value_obj); - uint256_t l_cond_recv_value = dap_uint256_scan_uninteger(l_cond_recv_value_str); + uint256_t l_cond_recv_value = l_cond_value; json_object *l_cond_send_value_obj = json_object_object_get(l_cond_send_object, "send_datoshi"); const char *l_cond_send_value_str = json_object_get_string(l_cond_send_value_obj); uint256_t l_cond_send_value = dap_uint256_scan_uninteger(l_cond_send_value_str); -- GitLab From c28457db3fe5e08c305820d07d0b792ea709bad1 Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Fri, 7 Mar 2025 17:18:30 +0700 Subject: [PATCH 12/53] [*] Check spent recursion vs indefinite cycle --- modules/net/dap_chain_ledger.c | 12 +- .../service/voting/dap_chain_net_srv_voting.c | 175 +++++++----------- 2 files changed, 74 insertions(+), 113 deletions(-) diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index 49b6f840a8..0d4530aca7 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -4188,13 +4188,14 @@ static int s_tx_cache_check(dap_ledger_t *a_ledger, debug_if(s_debug_more, L_WARNING, "Verificator check error for voting item"); l_err_num = DAP_LEDGER_TX_CHECK_NO_VERIFICATOR_SET; } - // if (a_tag) + // if (a_tag) // a_tag->uint64 = DAP_CHAIN_TX_TAG_ACTION_VOTING; - if (a_action) + if (a_action) *a_action = DAP_CHAIN_TX_TAG_ACTION_VOTING; } else if ( dap_chain_datum_tx_item_get(a_tx, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL) ) { if (s_voting_callbacks.voting_callback) { - if ((l_err_num = s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, a_tx_hash, false))) { + if (!s_check_hal(a_ledger, a_tx_hash) && + (l_err_num = s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, a_tx_hash, false))) { debug_if(s_debug_more, L_WARNING, "Verificator check error %d for vote", l_err_num); l_err_num = DAP_LEDGER_TX_CHECK_VERIFICATOR_CHECK_FAILURE; } @@ -4202,8 +4203,6 @@ static int s_tx_cache_check(dap_ledger_t *a_ledger, debug_if(s_debug_more, L_WARNING, "Verificator check error for vote item"); l_err_num = DAP_LEDGER_TX_CHECK_NO_VERIFICATOR_SET; } - // if (a_tag) - // a_tag->uint64 = DAP_CHAIN_TX_TAG_ACTION_VOTE; if (a_action) *a_action = DAP_CHAIN_TX_TAG_ACTION_VOTE; } @@ -4614,7 +4613,8 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha else if (l_action == DAP_CHAIN_TX_TAG_ACTION_VOTE) l_err_num = s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, a_tx_hash, true); } - assert(!l_err_num); + if (!s_check_hal(a_ledger, a_tx_hash)) + assert(!l_err_num); // add transaction to the cache list dap_ledger_tx_item_t *l_tx_item = DAP_NEW_Z_SIZE(dap_ledger_tx_item_t, sizeof(dap_ledger_tx_item_t) + l_outs_count * sizeof(dap_chain_hash_fast_t)); diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index 3e057d8856..d962667961 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -398,7 +398,8 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a l_old_vote ? &l_pkey_hash : NULL)) { log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx, dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash)); - return -20; + log_it(L_ATT, "Datum hash for HAL posssible: %s", dap_hash_fast_to_str_static(a_tx_hash)); + //return -20; } if (SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) { log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); @@ -426,7 +427,8 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) return -16; if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, l_pkey_sign)) - return -17; + log_it(L_ATT, "Datum hash for HAL: %s", dap_hash_fast_to_str_static(a_tx_hash)); + //return -17; if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx, l_old_vote ? &l_pkey_hash : NULL)) return -15; @@ -1078,47 +1080,24 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) return 0; } -static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, - dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash) +static int s_tx_is_spent(dap_ledger_t *a_ledger, dap_hash_fast_t *a_tx_hash, dap_hash_fast_t *a_voting_hash, + dap_hash_fast_t *a_pkey_hash, dap_chain_net_votings_t *a_voting, dap_time_t a_voting_ts) { - int l_coin_is_spent = 0; - - dap_chain_net_votings_t *l_voting = NULL; - pthread_rwlock_wrlock(&s_votings_rwlock); - HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting); - pthread_rwlock_unlock(&s_votings_rwlock); - if (!l_voting) { - log_it(L_ERROR, "Can't find voting %s", dap_hash_fast_to_str_static(&a_voting_hash)); - return -1; - } - const char *l_token_ticker = l_voting->voting_params.token_ticker; - - dap_ledger_t *l_ledger = a_net->pub.ledger; - dap_chain_datum_tx_t *l_voting_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_voting_hash); - if (!l_voting_tx) { - log_it(L_ERROR, "Can't find voting tx %s", dap_hash_fast_to_str_static(&a_voting_hash)); - return -2; - } - dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_tx_prev_hash); + dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_ledger, a_tx_hash); if (!l_tx) { - log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(&a_tx_prev_hash)); + log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(a_tx_hash)); return -3; } - if (l_tx->header.ts_created < l_voting_tx->header.ts_created){ + if (l_tx->header.ts_created < a_voting_ts) return 0; - } - - if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, a_tx_prev_hash, a_out_idx, a_pkey_hash) != 0){ - return 1; - } dap_chain_tx_vote_t *l_vote = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL); - if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)) { - for (dap_list_t *it = l_voting->votes; it; it = it->next) { + if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting->voting_hash)) { + for (dap_list_t *it = a_voting->votes; it; it = it->next) { dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data; - if (dap_hash_fast_compare(&l_vote->vote_hash, &a_tx_prev_hash)) { - if (l_voting->voting_params.vote_changing_allowed && + if (dap_hash_fast_compare(&l_vote->vote_hash, a_tx_hash)) { + if (a_voting->voting_params.vote_changing_allowed && !dap_hash_fast_is_blank(a_pkey_hash) && dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash)) break; // it's vote changing, allow it @@ -1127,103 +1106,85 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f } } - dap_list_t *l_ins_list_temp = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL); - dap_list_t *l_cond_ins_list = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_COND, NULL); - if (!l_ins_list_temp && !l_cond_ins_list) // it's emisssion or reward TX, not marked yet + dap_list_t *l_ins_list = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL); + l_ins_list = dap_list_concat(l_ins_list, dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_COND, NULL)); + if (!l_ins_list) // it's emisssion or reward TX, not marked yet return 0; - dap_list_t *l_ins_list = dap_list_concat(l_ins_list_temp, l_cond_ins_list); - dap_list_t *l_tx_list = dap_list_append(NULL, l_ins_list); // "stack" for saving txs on up level - dap_list_t *l_tx_temp = dap_list_last(l_tx_list); - - while(l_tx_temp && !l_coin_is_spent){ - if (l_tx_temp->data == NULL){ - l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp); - l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL; - continue; + dap_hash_fast_t l_prev_hash = {}; + for (dap_list_t *it = l_ins_list; it; it = it->next) { + uint32_t l_prev_idx = -1; + if (*(byte_t *)it->data == TX_ITEM_TYPE_IN_COND) { + dap_chain_tx_in_cond_t *in = it->data; + l_prev_hash = in->header.tx_prev_hash; + l_prev_idx = in->header.tx_out_prev_idx; + } else { + dap_chain_tx_in_t *in = it->data; + l_prev_hash = in->header.tx_prev_hash; + l_prev_idx = in->header.tx_out_prev_idx; } - dap_list_t *l_ins_list = (dap_list_t*)l_tx_temp->data; - dap_chain_tx_in_t* l_temp_in = (dap_chain_tx_in_t*)l_ins_list->data; - dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(l_ledger, &l_temp_in->header.tx_prev_hash); + dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, &l_prev_hash); const char* l_tx_token = NULL; - dap_chain_tx_out_t *l_prev_out_union = (dap_chain_tx_out_t*)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_temp_in->header.tx_out_prev_idx); - if (!l_prev_out_union){ - l_tx_temp->data = dap_list_remove(l_tx_temp->data, l_temp_in); - if (l_tx_temp->data == NULL){ - l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp); - l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL; - } - continue; - } - - switch (l_prev_out_union->header.type) { + byte_t *l_prev_out_union = dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev, l_prev_idx); + switch (*l_prev_out_union) { case TX_ITEM_TYPE_OUT:{ - l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_temp_in->header.tx_prev_hash); + dap_chain_tx_out_t *l_out = (dap_chain_tx_out_t *)l_prev_out_union; + l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(a_ledger, &l_prev_hash); }break; case TX_ITEM_TYPE_OUT_EXT:{ - dap_chain_tx_out_ext_t *l_temp_out = (dap_chain_tx_out_ext_t *)l_prev_out_union; - l_tx_token = l_temp_out->token; + dap_chain_tx_out_ext_t *l_out = (dap_chain_tx_out_ext_t *)l_prev_out_union; + l_tx_token = l_out->token; }break; case TX_ITEM_TYPE_OUT_COND:{ - dap_chain_tx_out_cond_t *l_temp_out = (dap_chain_tx_out_cond_t *)l_prev_out_union; - if (l_temp_out->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) { - l_tx_token = a_net->pub.native_ticker; + dap_chain_tx_out_cond_t *l_out = (dap_chain_tx_out_cond_t *)l_prev_out_union; + if (l_out->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) { + l_tx_token = a_ledger->net->pub.native_ticker; break; } - if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, l_temp_in->header.tx_prev_hash, - l_temp_in->header.tx_out_prev_idx, a_pkey_hash) != 0) { - l_coin_is_spent = 1; - continue; + if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, *a_voting_hash, l_prev_hash, l_prev_idx, a_pkey_hash) != 0) { + dap_list_free(l_ins_list); + return 1; } - l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_temp_in->header.tx_prev_hash); + l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(a_ledger, &l_prev_hash); } default: break; } - - if (l_tx_prev_temp->header.ts_created < l_voting_tx->header.ts_created || - dap_strcmp(l_tx_token, l_token_ticker)){ - l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in); - if (l_tx_temp->data == NULL){ - l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp); - l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL; - } + if (dap_strcmp(l_tx_token, a_voting->voting_params.token_ticker)) continue; - } + } - dap_chain_tx_vote_t *l_vote = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(l_tx_prev_temp, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL); - if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)) { - for (dap_list_t *it = l_voting->votes; it; it = it->next) { - dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data; - if (dap_hash_fast_compare(&l_vote->vote_hash, &l_temp_in->header.tx_prev_hash)) { - if (l_voting->voting_params.vote_changing_allowed && - !dap_hash_fast_is_blank(a_pkey_hash) && - dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash)) - break; // it's vote changing, allow it - l_coin_is_spent = 1; - break; - } - } - } + return s_tx_is_spent(a_ledger, &l_prev_hash, a_voting_hash, a_pkey_hash, a_voting, a_voting_ts); +} + + +static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, + dap_hash_fast_t a_tx_prev_hash, int a_out_idx, dap_hash_fast_t *a_pkey_hash) +{ + int l_coin_is_spent = 0; - l_ins_list = dap_chain_datum_tx_items_get(l_tx_prev_temp, TX_ITEM_TYPE_IN, NULL); - l_tx_list = dap_list_append(l_tx_list, l_ins_list); - l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in); - l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL; + dap_chain_net_votings_t *l_voting = NULL; + pthread_rwlock_wrlock(&s_votings_rwlock); + HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting); + pthread_rwlock_unlock(&s_votings_rwlock); + if (!l_voting) { + log_it(L_ERROR, "Can't find voting %s", dap_hash_fast_to_str_static(&a_voting_hash)); + return -1; } - if(l_tx_list){ - l_tx_temp = l_tx_list; - while(l_tx_temp){ - if (l_tx_temp->data) - dap_list_free((dap_list_t*)l_tx_temp->data); - l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp); - l_tx_temp = dap_list_first(l_tx_list); - } + dap_ledger_t *l_ledger = a_net->pub.ledger; + dap_chain_datum_tx_t *l_voting_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_voting_hash); + if (!l_voting_tx) { + log_it(L_ERROR, "Can't find voting tx %s", dap_hash_fast_to_str_static(&a_voting_hash)); + return -2; } - return l_coin_is_spent; + if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, a_tx_prev_hash, a_out_idx, a_pkey_hash) != 0) + return 1; + + return s_tx_is_spent(l_ledger, &a_tx_prev_hash, &a_voting_hash, a_pkey_hash, l_voting, l_voting_tx->header.ts_created); + } static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, -- GitLab From 730a53de647f429e3a4996734308297dd6337b69 Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Fri, 7 Mar 2025 18:15:10 +0700 Subject: [PATCH 13/53] [*] Last bugs fixes --- modules/net/dap_chain_node_cli_cmd.c | 19 +++++++++---------- .../service/voting/dap_chain_net_srv_voting.c | 6 ++---- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index 4d23819b9a..fa3c41d20b 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -1799,10 +1799,10 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; return DAP_CHAIN_NODE_CLI_COM_TX_WALLET_PARAM_ERR; } json_object * json_obj_wall = json_object_new_object(); - const char *l_cond_str = NULL, *l_value_str = NULL; + const char *l_value_str = NULL; uint256_t l_value_datoshi = uint256_0, l_value_sum = uint256_0; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cond", &l_cond_str); - if (!l_cond_str) { + bool l_cond_outs = dap_cli_server_cmd_check_option(a_argv, l_arg_index, a_argc, "-cond") != -1; + if (!l_cond_outs) { dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); if (l_value_str) { l_value_datoshi = dap_chain_balance_scan(l_value_str); @@ -1816,12 +1816,11 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; } dap_list_t *l_outs_list = NULL; - - if (l_value_str) { - if (dap_chain_wallet_cache_tx_find_outs_with_val(l_net, l_token_tiker, l_addr, &l_outs_list, l_value_datoshi, &l_value_sum)) - l_outs_list = dap_ledger_get_list_tx_outs_with_val(l_net->pub.ledger, l_token_tiker, l_addr, l_value_datoshi, &l_value_sum); - } else if (l_cond_str) { + if (l_cond_outs) l_outs_list = dap_ledger_get_list_tx_cond_outs(l_net->pub.ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_tiker, l_addr); + else if (l_value_str) { + if (dap_chain_wallet_cache_tx_find_outs_with_val(l_net, l_token_tiker, l_addr, &l_outs_list, l_value_datoshi, &l_value_sum)) + l_outs_list = dap_ledger_get_list_tx_outs_with_val(l_net->pub.ledger, l_token_tiker, l_addr, l_value_datoshi, &l_value_sum); } else { if (dap_chain_wallet_cache_tx_find_outs(l_net, l_token_tiker, l_addr, &l_outs_list, &l_value_sum)) l_outs_list = dap_ledger_get_list_tx_outs(l_net->pub.ledger, l_token_tiker, l_addr, &l_value_sum); @@ -1836,13 +1835,13 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; return json_object_put(json_arr_out), DAP_CHAIN_NODE_CLI_COM_TX_WALLET_MEMORY_ERR; dap_chain_tx_used_out_item_t *l_item = l_temp->data; const char *l_out_value_coins_str, *l_out_value_str = dap_uint256_to_char(l_item->value, &l_out_value_coins_str); - json_object_object_add(json_obj_item,"item_type", json_object_new_string(l_cond_str ? "unspent_cond_out" : "unspent_out")); + json_object_object_add(json_obj_item,"item_type", json_object_new_string(l_cond_outs ? "unspent_cond_out" : "unspent_out")); json_object_object_add(json_obj_item,"value_coins", json_object_new_string(l_out_value_coins_str)); json_object_object_add(json_obj_item,"value_datosi", json_object_new_string(l_out_value_str)); json_object_object_add(json_obj_item,"prev_hash", json_object_new_string(dap_hash_fast_to_str_static(&l_item->tx_hash_fast))); json_object_object_add(json_obj_item,"out_prev_idx", json_object_new_int64(l_item->num_idx_out)); json_object_array_add(l_json_outs_arr, json_obj_item); - if (l_cond_str) + if (l_cond_outs) SUM_256_256(l_value_sum, l_item->value, &l_value_sum); } dap_list_free_full(l_outs_list, NULL); diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index d962667961..f07f8e0f99 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -398,8 +398,7 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a l_old_vote ? &l_pkey_hash : NULL)) { log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx, dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash)); - log_it(L_ATT, "Datum hash for HAL posssible: %s", dap_hash_fast_to_str_static(a_tx_hash)); - //return -20; + return -20; } if (SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) { log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); @@ -427,8 +426,7 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) return -16; if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, l_pkey_sign)) - log_it(L_ATT, "Datum hash for HAL: %s", dap_hash_fast_to_str_static(a_tx_hash)); - //return -17; + return -17; if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx, l_old_vote ? &l_pkey_hash : NULL)) return -15; -- GitLab From 81136f326e01a7808a5a59ccbd9d89fbf6e0ed63 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Fri, 14 Mar 2025 12:42:39 +0700 Subject: [PATCH 14/53] [*] tx to json --- dap-sdk | 2 +- modules/net/dap_chain_net_tx.c | 30 +++++++++++++------ .../service/voting/dap_chain_net_srv_voting.c | 4 +-- .../voting/include/dap_chain_net_srv_voting.h | 2 +- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/dap-sdk b/dap-sdk index d9b03ffb93..a7b6da64ee 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit d9b03ffb93d4003cb1a33c6470612a7f88ad6005 +Subproject commit a7b6da64ee24a3aba64dcbbd5f3f356069d853ad diff --git a/modules/net/dap_chain_net_tx.c b/modules/net/dap_chain_net_tx.c index addcb27c56..2882d01ccd 100644 --- a/modules/net/dap_chain_net_tx.c +++ b/modules/net/dap_chain_net_tx.c @@ -1551,9 +1551,13 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json json_object_object_add(json_obj_item, "sig_b64", json_object_new_string(l_sign_b64)); } break; case TX_ITEM_TYPE_TSD: { - json_object_object_add(json_obj_item,"type", json_object_new_string("data")); - json_object_object_add(json_obj_item,"type", json_object_new_uint64(((dap_chain_tx_tsd_t*)item)->header.type)); - json_object_object_add(json_obj_item,"size", json_object_new_uint64(((dap_chain_tx_tsd_t*)item)->header.size)); + json_object_object_add(json_obj_item,"type", json_object_new_string("TX_ITEM_TYPE_TSD")); + json_object_object_add(json_obj_item,"type_tsd", json_object_new_string("data")); + json_object_object_add(json_obj_item,"size", json_object_new_uint64(((dap_chain_tx_tsd_t*)item)->header.size)); + char *l_tsd_str = DAP_NEW_Z_SIZE(char, ((dap_chain_tx_tsd_t*)item)->header.size + 1); + memcpy(l_tsd_str, ((dap_chain_tx_tsd_t*)item)->tsd, ((dap_chain_tx_tsd_t*)item)->header.size); + json_object_object_add(json_obj_item, "data", json_object_new_string(l_tsd_str)); + DAP_DEL_Z(l_tsd_str); } break; case TX_ITEM_TYPE_IN_COND: json_object_object_add(json_obj_item,"type", json_object_new_string("in_cond")); @@ -1602,15 +1606,15 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json const char *l_rate_str, *l_tmp_str = dap_uint256_to_char( (((dap_chain_tx_out_cond_t*)item)->subtype.srv_xchange.rate), &l_rate_str ); sprintf(l_tmp_buff,"0x%016"DAP_UINT64_FORMAT_x"",((dap_chain_tx_out_cond_t*)item)->subtype.srv_xchange.buy_net_id.uint64); - json_object_object_add(json_obj_item,"net_id", json_object_new_string(l_tmp_buff)); + json_object_object_add(json_obj_item,"net", json_object_new_string(l_tmp_buff)); json_object_object_add(json_obj_item,"token", json_object_new_string(((dap_chain_tx_out_cond_t*)item)->subtype.srv_xchange.buy_token)); json_object_object_add(json_obj_item,"rate", json_object_new_string(l_rate_str)); json_object_object_add(json_obj_item,"subtype", json_object_new_string("srv_xchange")); } break; case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK: { dap_time_t l_ts_unlock = ((dap_chain_tx_out_cond_t*)item)->subtype.srv_stake_lock.time_unlock; - dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_ts_unlock); - json_object_object_add(json_obj_item,"time_unlock", json_object_new_string(l_tmp_buf)); + const char * l_date_str = dap_time_to_str_simplified(l_ts_unlock); + json_object_object_add(json_obj_item,"time_staking", json_object_new_string(l_date_str)); json_object_object_add(json_obj_item,"subtype", json_object_new_string("srv_stake_lock")); } break; default: break; @@ -1618,11 +1622,18 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json } break; case TX_ITEM_TYPE_OUT_EXT: { const char *l_coins_str, *l_value_str = dap_uint256_to_char( ((dap_chain_tx_out_ext_t*)item)->header.value, &l_coins_str ); - json_object_object_add(json_obj_item,"type", json_object_new_string("out_ext")); + json_object_object_add(json_obj_item,"type", json_object_new_string("out")); json_object_object_add(json_obj_item,"addr", json_object_new_string(dap_chain_addr_to_str_static(&((dap_chain_tx_out_ext_t*)item)->addr))); json_object_object_add(json_obj_item,"token", json_object_new_string(((dap_chain_tx_out_ext_t*)item)->token)); json_object_object_add(json_obj_item,"value", json_object_new_string(l_value_str)); + } break; + case TX_ITEM_TYPE_IN_EMS: { + json_object_object_add(json_obj_item,"type", json_object_new_string("in_ems")); + json_object_object_add(json_obj_item,"chain_id", json_object_new_uint64(((dap_chain_tx_in_ems_t*)item)->header.token_emission_chain_id.uint64)); + json_object_object_add(json_obj_item,"token", json_object_new_string(((dap_chain_tx_in_ems_t*)item)->header.ticker)); + json_object_object_add(json_obj_item,"token_ems_hash", json_object_new_string( dap_hash_fast_to_str_static(&((dap_chain_tx_in_ems_t*)item)->header.token_emission_hash))); + } break; case TX_ITEM_TYPE_VOTING:{ size_t l_tsd_size = 0; @@ -1632,15 +1643,16 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json dap_chain_datum_tx_voting_params_t *l_voting_params = dap_chain_voting_parse_tsd(a_tx); json_object_object_add(json_obj_item,"type", json_object_new_string("voting")); json_object_object_add(json_obj_item,"voting_question", json_object_new_string(l_voting_params->voting_question)); - json_object_object_add(json_obj_item,"answer_options", json_object_new_string("")); + json_object *l_json_array = json_object_new_array(); dap_list_t *l_temp = l_voting_params->answers_list; uint8_t l_index = 0; while (l_temp) { - json_object_object_add(json_obj_item, dap_itoa(l_index), json_object_new_string((char *)l_temp->data)); + json_object_array_add(l_json_array, json_object_new_string((char *)l_temp->data)); l_index++; l_temp = l_temp->next; } + json_object_object_add(json_obj_item, "answer_options", l_json_array); if (l_voting_params->voting_expire) { dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_voting_params->voting_expire); json_object_object_add(json_obj_item,"Voting expire", json_object_new_string(l_tmp_buf)); diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index c74cf6fd33..37f0ba80f4 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -532,7 +532,7 @@ static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledge return true; } -static dap_list_t* s_get_options_list_from_str(const char* a_str) +dap_list_t* dap_get_options_list_from_str(const char* a_str) { dap_list_t* l_ret = NULL; char * l_options_str_dup = strdup(a_str); @@ -640,7 +640,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) return -DAP_CHAIN_NET_VOTE_CREATE_OPTION_PARAM_MISSING; } // Parse options list - l_options_list = s_get_options_list_from_str(l_options_list_str); + l_options_list = dap_get_options_list_from_str(l_options_list_str); if(!l_options_list || dap_list_length(l_options_list) < 2){ dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR, "Number of options must be 2 or greater."); return -DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR; diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h index 4bd1f71694..36c681188d 100644 --- a/modules/service/voting/include/dap_chain_net_srv_voting.h +++ b/modules/service/voting/include/dap_chain_net_srv_voting.h @@ -152,4 +152,4 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal dap_list_t *dap_chain_net_vote_list(dap_chain_net_t *a_net); dap_chain_net_vote_info_t *dap_chain_net_vote_extract_info(dap_chain_net_t *a_net, dap_hash_fast_t *a_vote_hash); void dap_chain_net_vote_info_free(dap_chain_net_vote_info_t *a_info); - +dap_list_t* dap_get_options_list_from_str(const char* a_str); -- GitLab From aa61ae0928ab0d8114916a9739cfaa2095d98aea Mon Sep 17 00:00:00 2001 From: "roman.padenkov" <roman.padenkov@demlabs.net> Date: Wed, 19 Mar 2025 22:00:10 +0700 Subject: [PATCH 15/53] ... --- CMakeLists.txt | 7 +++++++ modules/CMakeLists.txt | 5 +++++ modules/net/include/dap_chain_net_tx.h | 6 +----- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bfb08ee2e4..22001f9388 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,13 @@ if (CELLFRAME_MODULES MATCHES "network") dap_stream dap_stream_ch dap_client dap_cli_server dap_stream_ch_chain_net dap_chain_net dap_chain_net_srv dap_chain_mempool) endif() +# Compose +if (CELLFRAME_MODULES MATCHES "compose") + message("[+] Module 'compose'") + set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_compose dap_json_rpc dap_enc_server dap_notify_srv dap_http_server dap_session + dap_stream dap_stream_ch dap_client dap_cli_server dap_stream_ch_chain_net dap_chain_net dap_chain_net_srv dap_chain_mempool) +endif() + # Chain net services if (CELLFRAME_MODULES MATCHES "srv-" ) set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_stream_ch_chain_net_srv) diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index fef7978aab..de7713fd24 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -108,3 +108,8 @@ endif() if (CELLFRAME_MODULES MATCHES "srv-emit-delegate") add_subdirectory(service/emit-delegate) endif() + +# compose service +if (CELLFRAME_MODULES MATCHES "compose") + add_subdirectory(compose) +endif() diff --git a/modules/net/include/dap_chain_net_tx.h b/modules/net/include/dap_chain_net_tx.h index 0447fcb165..fe57215d18 100644 --- a/modules/net/include/dap_chain_net_tx.h +++ b/modules/net/include/dap_chain_net_tx.h @@ -98,10 +98,6 @@ dap_list_t * dap_chain_net_get_tx_cond_all_by_srv_uid(dap_chain_net_t * a_net, c dap_list_t * dap_chain_net_get_tx_cond_all_for_addr(dap_chain_net_t * a_net, dap_chain_addr_t * a_addr, dap_chain_net_srv_uid_t a_srv_uid); dap_list_t * dap_chain_net_get_tx_all_from_tx(dap_chain_net_t * a_net, dap_hash_fast_t * l_tx_hash); - - - - dap_chain_datum_tx_spends_items_t * dap_chain_net_get_tx_cond_all_with_spends_by_srv_uid(dap_chain_net_t * a_net, const dap_chain_net_srv_uid_t a_srv_uid, const dap_time_t a_time_from, const dap_time_t a_time_to, const dap_chain_net_tx_search_type_t a_search_type); @@ -137,4 +133,4 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json #ifdef __cplusplus } -#endif \ No newline at end of file +#endif -- GitLab From 27d4eff9b8d4d692784feaa75d683737ac132035 Mon Sep 17 00:00:00 2001 From: "roman.padenkov" <roman.padenkov@demlabs.net> Date: Thu, 20 Mar 2025 13:10:49 +0700 Subject: [PATCH 16/53] ... --- dap-sdk | 2 +- modules/compose/CMakeLists.txt | 21 +++++++++++++++++++ modules/compose/dap_chain_tx_compose.c | 1 + .../compose/include/dap_chain_tx_compose.h | 1 + 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 modules/compose/CMakeLists.txt create mode 100644 modules/compose/dap_chain_tx_compose.c create mode 100644 modules/compose/include/dap_chain_tx_compose.h diff --git a/dap-sdk b/dap-sdk index ff8478aa04..dafe5ac222 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit ff8478aa04fa94540016fee0038db4b63965d0d1 +Subproject commit dafe5ac222f390aed78fc60528d04d2905555361 diff --git a/modules/compose/CMakeLists.txt b/modules/compose/CMakeLists.txt new file mode 100644 index 0000000000..e03c3e95bb --- /dev/null +++ b/modules/compose/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.10) +project (dap_compose) + +file(GLOB DAP_CHAIN_COMPOSE_SRCS *.c) +file(GLOB DAP_CHAIN_COMPOSE_HEADERS include/*.h) + +add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_COMPOSE_SRCS} ${DAP_CHAIN_COMPOSE_HEADERS}) + + +target_include_directories(${PROJECT_NAME} PUBLIC include/ ) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../dap-sdk/3rdparty/json-c) + + +if (INSTALL_SDK) +set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${DAP_CHAIN_COMPOSE_HEADERS}") +INSTALL(TARGETS ${PROJECT_NAME} + LIBRARY DESTINATION lib/modules/compose/ + ARCHIVE DESTINATION lib/modules/compose/ + PUBLIC_HEADER DESTINATION include/modules/compose/ +) +endif() diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/modules/compose/dap_chain_tx_compose.c @@ -0,0 +1 @@ + diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -0,0 +1 @@ + -- GitLab From b6b6b884db866e26d8c2de147d4388804874ae72 Mon Sep 17 00:00:00 2001 From: "roman.padenkov" <roman.padenkov@demlabs.net> Date: Thu, 20 Mar 2025 17:05:33 +0700 Subject: [PATCH 17/53] ... --- modules/compose/CMakeLists.txt | 4 +- modules/compose/dap_chain_tx_compose.c | 2350 +++++++++++++++++ .../compose/include/dap_chain_tx_compose.h | 96 + 3 files changed, 2449 insertions(+), 1 deletion(-) diff --git a/modules/compose/CMakeLists.txt b/modules/compose/CMakeLists.txt index e03c3e95bb..2943e6fb03 100644 --- a/modules/compose/CMakeLists.txt +++ b/modules/compose/CMakeLists.txt @@ -6,7 +6,9 @@ file(GLOB DAP_CHAIN_COMPOSE_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_COMPOSE_SRCS} ${DAP_CHAIN_COMPOSE_HEADERS}) - +target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_client dap_io dap_notify_srv dap_cli_server dap_chain dap_chain_wallet + dap_chain_net_srv dap_chain_net_srv_voting dap_chain_mempool dap_global_db dap_chain_net_srv_xchange dap_chain_cs_none + dap_stream_ch_chain_net dap_chain_cs_esbocs dap_json_rpc ) target_include_directories(${PROJECT_NAME} PUBLIC include/ ) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../dap-sdk/3rdparty/json-c) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 8b13789179..f86c15f7c3 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -1 +1,2351 @@ +/* + * Authors: + * Roman Padenkov <roman.padenkov@demlabs.net> + * Olzhas Zharasbaev <oljas.jarasbaev@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * DeM Labs Open source community https://github.com/demlabsinc + * Copyright (c) 2025-2026 + * All rights reserved. + + This file is part of DAP (Distributed Applications Platform) the open source project + + DAP (Distributed Applications Platform) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "dap_common.h" +#include "dap_chain_tx_compose.h" +#include "dap_chain_datum_tx_voting.h" +#include "dap_chain_net_srv_stake_lock.h" +#include "dap_chain_net_srv_voting.h" + +#include <curl/curl.h> + + +static const char* s_get_native_ticker(const char* name) { + for (int i = 0; i < NET_COUNT; i++) { + if (strcmp(netinfo[i].name, name) == 0) { + return netinfo[i].native_ticker; + } + } + return NULL; +} + +static dap_chain_net_id_t s_get_net_id(const char* name) { + for (int i = 0; i < NET_COUNT; i++) { + if (strcmp(netinfo[i].name, name) == 0) { + return netinfo[i].net_id; + } + } + dap_chain_net_id_t empty_id = {.uint64 = 0}; + return empty_id; +} + +void bad_option(){ + printf("Usage: %s {{-w, --wallet <path_to_wallet_file> | -z, --seed <seed_phrase> -s <sign_type>} [OPTIONS] | {-c -w <wallet_name> -d <path_to_save_wallet_file> -s <sign_type> -z <seed_phrase>} | {-a {-w <path_to_wallet_file> | -z, --seed <seed_phrase> -s <sign_type>} -i 0x<net_id>}} \n\r \ + stake_lock hold -net <net_name> -w <wallet_name> -time_staking <YYMMDD> -token <ticker> -value <value> -fee <value> -chain_id <chain_id> [-reinvest <percentage>] \n\r \ + stake_lock take -net <net_name> -w <wallet_name> -tx <transaction_hash> -fee <value> -chain_id <chain_id> \ + \t\tstake_lock command doesn't support old stake command", + + dap_get_appname()); + exit(EXIT_FAILURE); +} + + +size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userdata) { + size_t total_size = size * nmemb; + char **response = (char **)userdata; + *response = realloc(*response, total_size + 1); + if (*response == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + memcpy(*response, ptr, total_size); + (*response)[total_size] = '\0'; + return total_size; +} + +json_object* request_command_to_rpc_by_curl(const char * request){ + CURL *curl; + CURLcode res; + char *response = NULL; + + curl_global_init(CURL_GLOBAL_DEFAULT); + curl = curl_easy_init(); + json_object * result = NULL; + + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, RPC_NODES_URL); + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Content-Type: application/json"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + res = curl_easy_perform(curl); + + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } else { + json_object *json = json_tokener_parse(response); + if (json == NULL) { + fprintf(stderr, "Failed to parse JSON response\n"); + } else { + if (!json_object_object_get_ex(json, "result", &result)) { + fprintf(stderr, "Result field not found in JSON response\n"); + } else { + json_object_get(result); + } + json_object_put(json); + } + } + + curl_easy_cleanup(curl); + curl_slist_free_all(headers); + free(response); + } + + curl_global_cleanup(); + return result; +} + +struct options { + char *cmd; + char *subcmd[5]; + int count_of_subcommands; + int (*handler) (int argc, char **argv); +} s_opts[] = { +{ "tx_create", {"compose"}, 1, dap_tx_create_compose }, +{ "xchange_create", {"compose"}, 1, dap_tx_create_xchange_compose }, +{ "tx_cond_create", {"compose"}, 1, dap_tx_cond_create_compose }, +{ "stake_lock", {"hold"}, 1, dap_cli_hold_compose }, +{ "stake_lock", {"take"}, 1, dap_cli_take_compose }, +{ "voting", {"create"}, 1, dap_cli_voting_compose } +}; +/* +int main(int argc, char **argv) +{ + int l_argv_start = 1, l_argvi, l_err = -2, l_ret_cmd = -1; + dap_set_appname("cellframe-tool-compose"); + + if (argc == 1){ + bad_option(); + } + + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + c_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif + } else { + c_wallets_path = dap_strdup(l_wallet_path); + } + + size_t i, l_size = sizeof(s_opts) / sizeof(struct options); + for (i = 0; i < l_size; ++i) { + l_argvi = l_argv_start; + if (argc >= l_argvi && !strncmp(s_opts[i].cmd, argv[l_argvi], strlen (argv[l_argvi]) + 1)) { + l_err = 0; + for (int isub = 0; isub < s_opts[i].count_of_subcommands; isub++) { + if ( argc - 1 < ++l_argvi || strncmp(s_opts[i].subcmd[isub], argv[l_argvi], strlen(argv[l_argvi]) + 1) ) { + l_err = -1; + break; + } + } + if ( !l_err ) { + l_ret_cmd = s_opts[i].handler(argc, argv); + break; + } + } + } + switch ( l_err ) { + case -2: + printf("Command \"%s\" not found.\n", argv[1]); + bad_option(); + break; + case -1: + printf("No subcommand was found for command \"%s\".\n", argv[1]); + bad_option(); + break; + default: break; + } + return l_err ? l_err : l_ret_cmd; +} +*/ +int dap_tx_create_xchange_compose(int argc, char ** argv) { + int arg_index = 1; + const char *l_net_name = NULL; + const char *l_token_sell = NULL; + const char *l_token_buy = NULL; + const char *l_wallet_name = NULL; + const char *l_value_str = NULL; + const char *l_rate_str = NULL; + const char *l_fee_str = NULL; + + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_sell", &l_token_sell); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_buy", &l_token_buy); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-rate", &l_rate_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee_str); + + if (!l_net_name) { + printf("xchange_create requires parameter '-net'"); + return -1; + } + + if (!l_token_buy) { + printf("xchange_create requires parameter '-token_buy'"); + return -1; + } + + if (!l_token_sell) { + printf("xchange_create requires parameter '-token_sell'"); + return -1; + } + + if (!l_wallet_name) { + printf("xchange_create requires parameter '-w'"); + return -1; + } + + if (!l_value_str) { + printf("xchange_create requires parameter '-value'"); + return -1; + } + + if (!l_rate_str) { + printf("xchange_create requires parameter '-rate'"); + return -1; + } + + if (!l_fee_str) { + printf("xchange_create requires parameter '-fee'"); + return -1; + } + + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, c_wallets_path, NULL); + if(!l_wallet) { + printf("wallet %s does not exist", l_wallet_name); + return -1; + } + + + uint256_t l_value = dap_chain_balance_scan(l_value_str); + uint256_t l_rate = dap_chain_balance_scan(l_rate_str); + uint256_t l_fee = dap_chain_balance_scan(l_fee_str); + if (IS_ZERO_256(l_value) || IS_ZERO_256(l_rate) || IS_ZERO_256(l_fee)) { + printf("Invalid parameter value, rate or fee is 0, use required format 1.0e+18 ot in datoshi"); + return -1; + } + + dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_net_name, l_token_buy, + l_token_sell, l_value, l_rate, l_fee, l_wallet); + json_object *l_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_ret); + printf("%s", json_object_to_json_string(l_ret)); + json_object_put(l_ret); + dap_chain_datum_tx_delete(l_tx); + return 0; +} + + + +int dap_tx_create_compose(int argc, char ** argv) { + int arg_index = 1; + const char *addr_base58_to = NULL; + const char *str_tmp = NULL; + const char * l_from_wallet_name = NULL; + const char * l_wallet_fee_name = NULL; + const char * l_token_ticker = NULL; + const char * l_net_name = NULL; + const char * l_chain_name = NULL; + const char * l_emission_chain_name = NULL; + const char * l_tx_num_str = NULL; + const char *l_emission_hash_str = NULL; + const char *l_cert_str = NULL; + dap_cert_t *l_cert = NULL; + dap_enc_key_t *l_priv_key = NULL; + dap_chain_hash_fast_t l_emission_hash = {}; + size_t l_tx_num = 0; + dap_chain_wallet_t * l_wallet_fee = NULL; + + const char * l_hash_out_type = NULL; + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type); + if(!l_hash_out_type) + l_hash_out_type = "hex"; + if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) { + printf("Invalid parameter -H, valid values: -H <hex | base58>"); + return -1; + } + + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); + if (!l_net_name) { + printf("tx_create requires parameter '-net'"); + return -1; + } + + uint256_t *l_value = NULL; + uint256_t l_value_fee = {}; + dap_chain_addr_t **l_addr_to = NULL; + size_t l_addr_el_count = 0; + size_t l_value_el_count = 0; + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-wallet_fee", &l_wallet_fee_name); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-tx_num", &l_tx_num_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str); + + if(l_tx_num_str) + l_tx_num = strtoul(l_tx_num_str, NULL, 10); + + // Validator's fee + if (dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) { + if (!str_tmp) { + printf("tx_create requires parameter '-fee'"); + return -1; + } + l_value_fee = dap_chain_balance_scan(str_tmp); + } + if (IS_ZERO_256(l_value_fee) && (str_tmp && strcmp(str_tmp, "0"))) { + printf("tx_create requires parameter '-fee' to be valid uint256"); + return -2; + } + + if (!l_from_wallet_name) { + printf("tx_create requires parameter '-from_wallet'"); + return -3; + } + + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker); + if (!l_token_ticker) { + printf("tx_create requires parameter '-token'"); + return -4; + } + + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp); + if (!addr_base58_to) { + printf("tx_create requires parameter '-to_addr'"); + return -5; + } + if (!str_tmp) { + printf("tx_create requires parameter '-value' to be valid uint256 value"); + return -6; + } + l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1; + l_value_el_count = dap_str_symbol_count(str_tmp, ',') + 1; + + if (l_addr_el_count != l_value_el_count) { + printf("num of '-to_addr' and '-value' should be equal"); + return -5; + } + + l_value = DAP_NEW_Z_COUNT(uint256_t, l_value_el_count); + if (!l_value) { + printf("Can't allocate memory"); + return -6; + } + char **l_value_array = dap_strsplit(str_tmp, ",", l_value_el_count); + if (!l_value_array) { + DAP_DELETE(l_value); + printf("Can't read '-to_addr' arg"); + return -7; + } + for (size_t i = 0; i < l_value_el_count; ++i) { + l_value[i] = dap_chain_balance_scan(l_value_array[i]); + if(IS_ZERO_256(l_value[i])) { + DAP_DEL_MULTY(l_value_array, l_value); + printf("tx_create requires parameter '-value' to be valid uint256 value"); + return -8; + } + } + DAP_DELETE(l_value_array); + + l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count); + if (!l_addr_to) { + printf("Can't allocate memory"); + DAP_DELETE(l_value); + return -9; + } + char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count); + if (!l_addr_base58_to_array) { + DAP_DEL_MULTY(l_addr_to, l_value); + printf("Can't read '-to_addr' arg"); + return -10; + } + for (size_t i = 0; i < l_addr_el_count; ++i) { + l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]); + if(!l_addr_to[i]) { + for (size_t j = 0; j < i; ++j) { + DAP_DELETE(l_addr_to[j]); + } + DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value); + printf("destination address is invalid"); + return -11; + } + } + DAP_DELETE(l_addr_base58_to_array); + + dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, c_wallets_path, NULL); + if(!l_wallet) { + printf("Can't open wallet %s", l_from_wallet_name); + return -12; + } + + + dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)); + for (size_t i = 0; i < l_addr_el_count; ++i) { + if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) { + printf("The transaction cannot be directed to the same address as the source."); + for (size_t j = 0; j < l_addr_el_count; ++j) { + DAP_DELETE(l_addr_to[j]); + } + DAP_DEL_MULTY(l_addr_to, l_value); + return -13; + } + } + + + + l_priv_key = dap_chain_wallet_get_key(l_wallet, 0); + dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count); + + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); + dap_chain_datum_tx_delete(l_tx); + DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from); + return 0; +} + +bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee) { + char data[512]; + snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name); + json_object *l_json_get_fee = request_command_to_rpc_by_curl(data); + if (!l_json_get_fee) { + return false; + } + + json_object *l_first_result = json_object_array_get_idx(l_json_get_fee, 0); + if (!l_first_result || !json_object_is_type(l_first_result, json_type_object)) { + json_object_put(l_json_get_fee); + return false; + } + + json_object *l_fees = NULL; + if (!json_object_object_get_ex(l_first_result, "fees", &l_fees) || + !json_object_is_type(l_fees, json_type_object)) { + json_object_put(l_json_get_fee); + return false; + } + + json_object *l_network = NULL; + if (!json_object_object_get_ex(l_fees, "network", &l_network) || + !json_object_is_type(l_network, json_type_object)) { + json_object_put(l_json_get_fee); + return false; + } + + json_object *l_balance = NULL; + if (!json_object_object_get_ex(l_network, "balance", &l_balance) || + !json_object_is_type(l_balance, json_type_string)) { + json_object_put(l_json_get_fee); + return false; + } + *a_net_fee = dap_chain_balance_scan(json_object_get_string(l_balance)); + + json_object *l_addr = NULL; + if (!json_object_object_get_ex(l_network, "addr", &l_addr) || + !json_object_is_type(l_addr, json_type_string)) { + json_object_put(l_json_get_fee); + return false; + } + *l_addr_fee = dap_chain_addr_from_str(json_object_get_string(l_addr)); + + json_object_put(l_json_get_fee); + return true; +} + +bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count) { + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name); + json_object *l_json_outs = request_command_to_rpc_by_curl(data); + if (!l_json_outs) { + return false; + } + + if (!json_object_is_type(l_json_outs, json_type_array)) { + json_object_put(l_json_outs); + return false; + } + + if (json_object_array_length(l_json_outs) == 0) { + json_object_put(l_json_outs); + return false; + } + + json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0); + if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) { + json_object_put(l_json_outs); + return false; + } + + json_object *l_first_item = json_object_array_get_idx(l_first_array, 0); + if (!l_first_item) { + json_object_put(l_json_outs); + return false; + } + + if (!json_object_object_get_ex(l_first_item, "outs", l_outs) || + !json_object_is_type(*l_outs, json_type_array)) { + json_object_put(l_json_outs); + return false; + } + + *l_outputs_count = json_object_array_length(*l_outs); + json_object_get(*l_outs); + json_object_put(l_json_outs); // Clean up the JSON object + return true; +} + + +dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, + const char* a_token_ticker, + uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num) +{ + if (!a_addr_from || !a_token_ticker || !a_value || !a_tx_num) { + return NULL; + } + + if (dap_chain_addr_check_sum(a_addr_from)) { + return NULL; + } + + for (size_t i = 0; i < a_tx_num; ++i) { + if (!a_addr_to || !a_addr_to[i]) { + return NULL; + } + if (dap_chain_addr_check_sum(a_addr_to[i])) { + return NULL; + } + if (IS_ZERO_256(a_value[i])) { + return NULL; + } + } + const char * l_native_ticker = s_get_native_ticker(l_net_name); + bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker); + + uint256_t l_value_transfer = {}; // how many coins to transfer + uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {}; + for (size_t i = 0; i < a_tx_num; ++i) { + SUM_256_256(l_value_total, a_value[i], &l_value_total); + } + uint256_t l_value_need = l_value_total; + + dap_list_t *l_list_fee_out = NULL; + uint256_t l_net_fee = {}; + dap_chain_addr_t *l_addr_fee = NULL; + if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee)) { + return NULL; + } + + bool l_net_fee_used = !IS_ZERO_256(l_net_fee); + SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); + json_object *l_outs = NULL; + int l_outputs_count = 0; + if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count)) { + return NULL; + } + + if (l_single_channel) + SUM_256_256(l_value_need, l_total_fee, &l_value_need); + else if (!IS_ZERO_256(l_total_fee)) { + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_total_fee, + &l_fee_transfer); + if (!l_list_fee_out) { + printf("Not enough funds to pay fee"); + json_object_put(l_outs); + return NULL; + } + } + dap_list_t *l_list_used_out = NULL; + l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_value_need, + &l_value_transfer); + json_object_put(l_outs); + if (!l_list_used_out) { + printf("Not enough funds to transfer"); + return NULL; + } + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // add 'in' items + { + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + if (l_list_fee_out) { + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); + dap_list_free_full(l_list_fee_out, NULL); + } + + } + if (a_tx_num > 1) { + uint32_t l_tx_num = a_tx_num; + dap_chain_tx_tsd_t *l_out_count = dap_chain_datum_tx_item_tsd_create(&l_tx_num, DAP_CHAIN_DATUM_TRANSFER_TSD_TYPE_OUT_COUNT, sizeof(uint32_t)); + dap_chain_datum_tx_add_item(&l_tx, l_out_count); + } + + if (l_single_channel) { // add 'out' items + uint256_t l_value_pack = {}; // how much datoshi add to 'out' items + for (size_t i = 0; i < a_tx_num; ++i) { + if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) == 1) { + SUM_256_256(l_value_pack, a_value[i], &l_value_pack); + } else { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // Network fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) + SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) + SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // coin back + uint256_t l_value_back; + SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); + if(!IS_ZERO_256(l_value_back)) { + if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + } else { // add 'out_ext' items + for (size_t i = 0; i < a_tx_num; ++i) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // coin back + uint256_t l_value_back; + SUBTRACT_256_256(l_value_transfer, l_value_total, &l_value_back); + if(!IS_ZERO_256(l_value_back)) { + if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // Network fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // fee coin back + SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back); + if(!IS_ZERO_256(l_value_back)) { + if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + } + DAP_DELETE(l_addr_fee); + return l_tx; +} + +dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer) +{ + dap_list_t *l_list_used_out = NULL; + uint256_t l_value_transfer = {}; + + for (int i = 0; i < a_outputs_count; i++) { + json_object *l_output = json_object_array_get_idx(a_outputs_array, i); + + json_object *l_value_datosi_obj = NULL; + json_object_object_get_ex(l_output, "value_datosi", &l_value_datosi_obj); + if (!l_value_datosi_obj) { + continue; + } + const char *l_value_str = json_object_get_string(l_value_datosi_obj); + uint256_t l_value = dap_chain_balance_scan(l_value_str); + + if (IS_ZERO_256(l_value)) { + continue; + } + + json_object *l_prev_hash_obj = NULL; + json_object_object_get_ex(l_output, "prev_hash", &l_prev_hash_obj); + if (!l_prev_hash_obj) { + continue; + } + const char *l_prev_hash_str = json_object_get_string(l_prev_hash_obj); + + json_object *l_out_prev_idx_obj = NULL; + json_object_object_get_ex(l_output, "out_prev_idx", &l_out_prev_idx_obj); + if (!l_out_prev_idx_obj) { + continue; + } + int l_out_idx = json_object_get_int(l_out_prev_idx_obj); + + dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); + if (!l_item) { + continue; + } + + dap_chain_hash_fast_from_str(l_prev_hash_str, &l_item->tx_hash_fast); + l_item->num_idx_out = l_out_idx; + l_item->value = l_value; + + l_list_used_out = dap_list_append(l_list_used_out, l_item); + + SUM_256_256(l_value_transfer, l_value, &l_value_transfer); + + if (compare256(l_value_transfer, a_value_need) >= 0) { + break; + } + } + + if (compare256(l_value_transfer, a_value_need) >= 0 && l_list_used_out) { + if (a_value_transfer) { + *a_value_transfer = l_value_transfer; + } + return l_list_used_out; + } else { + dap_list_free_full(l_list_used_out, NULL); + return NULL; + } +} + +uint256_t get_balance_from_json(json_object *l_json_outs, const char *a_token_sell) { + uint256_t l_value = {}; + if (l_json_outs && json_object_is_type(l_json_outs, json_type_array)) { + for (size_t i = 0; i < json_object_array_length(l_json_outs); i++) { + json_object *outer_array = json_object_array_get_idx(l_json_outs, i); + if (json_object_is_type(outer_array, json_type_array)) { + for (size_t j = 0; j < json_object_array_length(outer_array); j++) { + json_object *addr_obj = json_object_array_get_idx(outer_array, j); + if (json_object_is_type(addr_obj, json_type_object)) { + json_object *tokens = NULL; + if (json_object_object_get_ex(addr_obj, "tokens", &tokens) && json_object_is_type(tokens, json_type_array)) { + for (size_t k = 0; k < json_object_array_length(tokens); k++) { + json_object *token_obj = json_object_array_get_idx(tokens, k); + json_object *token = NULL; + if (json_object_object_get_ex(token_obj, "token", &token) && json_object_is_type(token, json_type_object)) { + json_object *ticker = NULL; + if (json_object_object_get_ex(token, "ticker", &ticker) && json_object_is_type(ticker, json_type_string)) { + const char *ticker_str = json_object_get_string(ticker); + if (strcmp(ticker_str, a_token_sell) == 0) { + json_object *datoshi = NULL; + if (json_object_object_get_ex(token_obj, "datoshi", &datoshi) && json_object_is_type(datoshi, json_type_string)) { + const char *datoshi_str = json_object_get_string(datoshi); + l_value = dap_uint256_scan_uninteger(datoshi_str); + break; + } + } + } + } + } + } + } + } + } + } + } + return l_value; +} + +bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) { + if (json_object_is_type(l_json_coins, json_type_array)) { + for (size_t i = 0; i < json_object_array_length(l_json_coins); i++) { + json_object *token_array = json_object_array_get_idx(l_json_coins, i); + if (json_object_is_type(token_array, json_type_array)) { + for (size_t j = 0; j < json_object_array_length(token_array); j++) { + json_object *token_obj = json_object_array_get_idx(token_array, j); + json_object *token_name = NULL; + if (json_object_object_get_ex(token_obj, "-->Token name", &token_name) && json_object_is_type(token_name, json_type_string)) { + const char *token_name_str = json_object_get_string(token_name); + if (strcmp(token_name_str, a_token) == 0) { + return true; + } + } + } + } + } + } + return false; +} + +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, + const char *a_token_sell, uint256_t a_datoshi_sell, + uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet){ + if (!a_net_name || !a_token_buy || !a_token_sell || !a_wallet) { + return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMENT + } + if (IS_ZERO_256(a_rate)) { + return NULL; // XCHANGE_CREATE_ERROR_RATE_IS_ZERO + } + if (IS_ZERO_256(a_fee)) { + return NULL; // XCHANGE_CREATE_ERROR_FEE_IS_ZERO + } + if (IS_ZERO_256(a_datoshi_sell)) { + return NULL; // XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO + } + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name); + json_object *l_json_coins = request_command_to_rpc_by_curl(data); + if (!l_json_coins) { + return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS + } + if (!check_token_in_ledger(l_json_coins, a_token_sell) || !check_token_in_ledger(l_json_coins, a_token_buy)) { + json_object_put(l_json_coins); + return NULL; // XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER + } + json_object_put(l_json_coins); + dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name)); + snprintf(data, sizeof(data), + "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", + dap_chain_addr_to_str(l_wallet_addr), a_net_name); + DAP_DEL_Z(l_wallet_addr); + json_object *l_json_outs = request_command_to_rpc_by_curl(data); + uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell); + + uint256_t l_value_sell = a_datoshi_sell; + if (!dap_strcmp(s_get_native_ticker(a_net_name), a_token_sell)) { + if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) { + return NULL; // XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE + } + } else { // sell non-native ticker + uint256_t l_fee_value = get_balance_from_json(l_json_outs, s_get_native_ticker(a_net_name)); + if (compare256(l_fee_value, a_fee) == -1) { + return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET + } + } + if (compare256(l_value, l_value_sell) == -1) { + return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET + } + // Create the price + dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); + if (!l_price) { + return NULL; // XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED + } + dap_stpcpy(l_price->token_sell, a_token_sell); + dap_stpcpy(l_price->token_buy, a_token_buy); + l_price->datoshi_sell = a_datoshi_sell; + l_price->rate = a_rate; + l_price->fee = a_fee; + dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name); + return l_tx; +} + +json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_name, dap_chain_addr_t * a_addr) { + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name); + json_object *l_json_outs = request_command_to_rpc_by_curl(data); + if (!l_json_outs) { + return NULL; + } + + if (!json_object_is_type(l_json_outs, json_type_array)) { + json_object_put(l_json_outs); + return NULL; + } + + if (json_object_array_length(l_json_outs) == 0) { + json_object_put(l_json_outs); + return NULL; + } + + json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0); + if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) { + json_object_put(l_json_outs); + return NULL; + } + + json_object *l_first_item = json_object_array_get_idx(l_first_array, 0); + if (!l_first_item) { + json_object_put(l_json_outs); + return NULL; + } + + json_object *l_outs = NULL; + if (!json_object_object_get_ex(l_first_item, "outs", &l_outs) || + !json_object_is_type(l_outs, json_type_array)) { + json_object_put(l_json_outs); + return NULL; + } + json_object_get(l_outs); + json_object_put(l_json_outs); + return l_outs; +} + + +static dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, + const char *a_native_ticker, const char *a_net_name) +{ + if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) { + return NULL; + } + const char *l_native_ticker = s_get_native_ticker(a_net_name); + bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker); + // find the transactions from which to take away coins + uint256_t l_value_transfer; // how many coins to transfer + uint256_t l_value_need = a_price->datoshi_sell, + l_net_fee, + l_total_fee = a_price->fee, + l_fee_transfer; + dap_chain_addr_t * l_addr_net_fee = NULL; + dap_list_t *l_list_fee_out = NULL; + + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee); + if (l_net_fee_used) + SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); + + dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name)); + dap_chain_addr_t l_seller_addr = *l_wallet_addr; + json_object *l_outs_native = get_tx_outs_by_curl(a_native_ticker, a_net_name, l_wallet_addr); + if (!l_outs_native) { + return NULL; + } + + json_object *l_outs = NULL; + if (!dap_strcmp(a_price->token_sell, a_native_ticker)) { + l_outs = l_outs_native; + } else { + l_outs = get_tx_outs_by_curl(a_price->token_sell, a_net_name, l_wallet_addr); + } + DAP_DELETE(l_wallet_addr); + int l_out_native_count = json_object_array_length(l_outs_native); + int l_out_count = json_object_array_length(l_outs); + + if (l_single_channel) + SUM_256_256(l_value_need, l_total_fee, &l_value_need); + else if (!IS_ZERO_256(l_total_fee)) { + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, + l_total_fee, + &l_fee_transfer); + if (!l_list_fee_out) { + printf("Not enough funds to pay fee"); + json_object_put(l_outs_native); + json_object_put(l_outs); + return NULL; + } + } + dap_list_t *l_list_used_out = NULL; + l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_out_count, + l_value_need, + &l_value_transfer); + if (!l_list_used_out) { + printf("Not enough funds to transfer"); + json_object_put(l_outs_native); + json_object_put(l_outs); + return NULL; + } + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // add 'in' items to sell + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + dap_list_free_full(l_list_used_out, NULL); + if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) { + dap_chain_datum_tx_delete(l_tx); + printf("Can't compose the transaction input\n"); + return NULL; + } + if (!l_single_channel) { + // add 'in' items to fee + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) { + dap_chain_datum_tx_delete(l_tx); + printf("Can't compose the transaction input\n"); + return NULL; + } + } + + // add 'out_cond' & 'out' items + + { + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID }; + dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(l_uid, s_get_net_id(a_net_name), a_price->datoshi_sell, + s_get_net_id(a_net_name), a_price->token_buy, a_price->rate, + &l_seller_addr, NULL, 0); + if (!l_tx_out) { + dap_chain_datum_tx_delete(l_tx); + printf("Can't compose the transaction conditional output\n"); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); + DAP_DELETE(l_tx_out); + // Network fee + if (l_net_fee_used) { + if ((l_single_channel && + dap_chain_datum_tx_add_out_item(&l_tx, l_addr_net_fee, l_net_fee) != 1) || + (!l_single_channel && + dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add network fee output\n"); + return NULL; + } + } + DAP_DELETE(l_addr_net_fee); + // Validator's fee + if (!IS_ZERO_256(a_price->fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add validator's fee output\n"); + return NULL; + } + } + // coin back + uint256_t l_value_back = {}; + SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if ((l_single_channel && + dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) || + (!l_single_channel && + dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_value_back, a_price->token_sell) != 1)) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add coin back output\n"); + return NULL; + } + } + // Fee coinback + if (!l_single_channel) { + uint256_t l_fee_coinback = {}; + SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback); + if (!IS_ZERO_256(l_fee_coinback)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add fee back output\n"); + return NULL; + } + } + } + } + + // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); + // // add 'sign' item + // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) { + // dap_chain_datum_tx_delete(l_tx); + // dap_enc_key_delete(l_seller_key); + // printf("Can't add sign output\n"); + // return NULL; + // } + // dap_enc_key_delete(l_seller_key); + return l_tx; +} + +// tx_cond_create -net <net_name> -token <token_ticker> -w <wallet_name> -cert <pub_cert_name> -value <value_datoshi> -fee <value> -unit {B | SEC} -srv_uid <numeric_uid> +int dap_tx_cond_create_compose(int argc, char ** argv) +{ + int arg_index = 1; + const char * l_token_ticker = NULL; + const char * l_wallet_str = NULL; + const char * l_cert_str = NULL; + const char * l_value_datoshi_str = NULL; + const char * l_value_fee_str = NULL; + const char * l_net_name = NULL; + const char * l_unit_str = NULL; + const char * l_srv_uid_str = NULL; + uint256_t l_value_datoshi = {}; + uint256_t l_value_fee = {}; + const char * l_hash_out_type = NULL; + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type); + if(!l_hash_out_type) + l_hash_out_type = "hex"; + if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) { + printf("Invalid parameter -H, valid values: -H <hex | base58>\n"); + return -1; + } + + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_datoshi_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_value_fee_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str); + + if(!l_token_ticker) { + printf("tx_cond_create requires parameter '-token'\n"); + return -2; + } + if (!l_wallet_str) { + printf("tx_cond_create requires parameter '-w'\n"); + return -3; + } + if (!l_cert_str) { + printf("tx_cond_create requires parameter '-cert'\n"); + return -4; + } + if(!l_value_datoshi_str) { + printf("tx_cond_create requires parameter '-value'\n"); + return -5; + } + if(!l_value_fee_str){ + printf("tx_cond_create requires parameter '-fee'\n"); + return -6; + } + if(!l_net_name) { + printf("tx_cond_create requires parameter '-net'\n"); + return -7; + } + if(!l_unit_str) { + printf("tx_cond_create requires parameter '-unit'\n"); + return -8; + } + + if(!l_srv_uid_str) { + printf("tx_cond_create requires parameter '-srv_uid'\n"); + return -9; + } + dap_chain_net_srv_uid_t l_srv_uid = {}; + l_srv_uid.uint64 = strtoll(l_srv_uid_str, NULL, 10); + if (!l_srv_uid.uint64) { + printf("Can't find service UID %s\n", l_srv_uid_str); + return -10; + } + + dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)l_unit_str)}; + + if(l_price_unit.enm == SERV_UNIT_UNDEFINED) { + printf("Can't recognize unit '%s'. Unit must look like { B | SEC }\n", l_unit_str); + return -11; + } + + l_value_datoshi = dap_chain_balance_scan(l_value_datoshi_str); + if(IS_ZERO_256(l_value_datoshi)) { + printf("Can't recognize value '%s' as a number\n", l_value_datoshi_str); + return -12; + } + + l_value_fee = dap_chain_balance_scan(l_value_fee_str); + if(IS_ZERO_256(l_value_fee)) { + printf("Can't recognize value '%s' as a number\n", l_value_fee_str); + return -13; + } + + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path, NULL); + if(!l_wallet) { + printf("Can't open wallet '%s'\n", l_wallet_str); + return -15; + } + + dap_cert_t *l_cert_cond = dap_cert_find_by_name(l_cert_str); + if(!l_cert_cond) { + dap_chain_wallet_close(l_wallet); + printf("Can't find cert '%s'\n", l_cert_str); + return -16; + } + + dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet, 0); + dap_pkey_t *l_key_cond = dap_pkey_from_enc_key(l_cert_cond->enc_key); + if (!l_key_cond) { + dap_chain_wallet_close(l_wallet); + dap_enc_key_delete(l_key_from); + printf("Cert '%s' doesn't contain a valid public key\n", l_cert_str); + return -17; + } + + uint256_t l_value_per_unit_max = {}; + dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker, + l_value_datoshi, l_value_per_unit_max, l_price_unit, + l_srv_uid, l_value_fee, NULL, 0, l_hash_out_type); + + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); + dap_chain_datum_tx_delete(l_tx); + dap_chain_wallet_close(l_wallet); + dap_enc_key_delete(l_key_from); + DAP_DELETE(l_key_cond); + return 0; +} + + +dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name, + dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, + const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], + uint256_t a_value, uint256_t a_value_per_unit_max, + dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, + uint256_t a_value_fee, const void *a_cond, + size_t a_cond_size, const char *a_hash_out_type) +{ + // check valid param + if (!a_net_name || !a_key_from || !a_key_cond || + !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value)) + return NULL; + + if (dap_strcmp(s_get_native_ticker(a_net_name), a_token_ticker)) { + printf("Pay for service should be only in native token ticker\n"); + return NULL; + } + + uint256_t l_net_fee = {}; + dap_chain_addr_t* l_addr_fee = NULL; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee); + // find the transactions from which to take away coins + uint256_t l_value_transfer = {}; // how many coins to transfer + uint256_t l_value_need = {}; + SUM_256_256(a_value, a_value_fee, &l_value_need); + if (l_net_fee_used) { + SUM_256_256(l_value_need, l_net_fee, &l_value_need); + } + // where to take coins for service + dap_chain_addr_t l_addr_from; + dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, s_get_net_id(a_net_name)); + // list of transaction with 'out' items + json_object *l_outs = NULL; + int l_outputs_count = 0; + if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count)) { + return NULL; + } + dap_list_t *l_list_used_out = NULL; + l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_value_need, + &l_value_transfer); + json_object_put(l_outs); + + + // dap_list_t *l_list_used_out = NULL; + // if (dap_chain_wallet_cache_tx_find_outs_with_val(l_ledger->net, a_token_ticker, &l_addr_from, &l_list_used_out, l_value_need, &l_value_transfer) == -101) + // l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_token_ticker, + // &l_addr_from, l_value_need, &l_value_transfer); + if(!l_list_used_out) { + printf("Nothing to transfer (not enough funds)\n"); + return NULL; + } + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // add 'in' items + { + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + } + // add 'out_cond' and 'out' items + { + uint256_t l_value_pack = {}; // how much coin add to 'out' items + if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond, + a_cond_size) == 1) { + SUM_256_256(l_value_pack, a_value, &l_value_pack); + } else { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add conditional output\n"); + return NULL; + } + // Network fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) + SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) + SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // coin back + uint256_t l_value_back = {}; + SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add coin back output\n"); + return NULL; + } + } + } + + // // add 'sign' items + // if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) { + // dap_chain_datum_tx_delete(l_tx); + // printf("Can't add sign output\n"); + // return NULL; + // } + // size_t l_tx_size = dap_chain_datum_tx_get_size( l_tx ); + // dap_chain_datum_t *l_datum = dap_chain_datum_create( DAP_CHAIN_DATUM_TX, l_tx, l_tx_size ); + // dap_chain_datum_tx_delete(l_tx); + // dap_chain_t *l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX); + // char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, a_hash_out_type); + // DAP_DELETE(l_datum); + + return l_tx; +} + +// stake_lock hold -net <net_name> -w <wallet_name> -time_staking <YYMMDD> -token <ticker> -value <value> -fee <value>[-chain <chain_name>] [-reinvest <percentage>] +int dap_cli_hold_compose(int a_argc, char **a_argv) +{ + int arg_index = 1; + const char *l_net_name = NULL, *l_ticker_str = NULL, *l_coins_str = NULL, + *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL, + *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL; + + const char *l_wallets_path = c_wallets_path; + char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; + dap_time_t l_time_staking = 0; + uint256_t l_reinvest_percent = {}; + uint256_t l_value_delegated = {}; + uint256_t l_value_fee = {}; + uint256_t l_value; + dap_enc_key_t *l_key_from; + dap_chain_wallet_t *l_wallet; + dap_chain_addr_t *l_addr_holder; + + + const char *l_hash_out_type = NULL; + dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); + if(!l_hash_out_type) + l_hash_out_type = "hex"; + if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type, "base58")) { + printf("Error: Invalid hash type argument\n"); + return -1; + } + + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_name) || NULL == l_net_name) { + printf("Error: Missing or invalid network argument\n"); + return -2; + } + + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_ticker_str) || NULL == l_ticker_str || dap_strlen(l_ticker_str) > 8) { + printf("Error: Missing or invalid token argument\n"); + return -3; + } + + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name); + json_object *l_json_coins = request_command_to_rpc_by_curl(data); + if (!l_json_coins) { + return -4; + } + if (!check_token_in_ledger(l_json_coins, l_ticker_str)) { + printf("Error: Invalid token '%s'\n", l_ticker_str); + return -4; + } + + if ((!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-coins", &l_coins_str) || NULL == l_coins_str) && + (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-value", &l_coins_str) || NULL == l_coins_str)) { + printf("Error: Missing coins or value argument\n"); + return -5; + } + + if (IS_ZERO_256((l_value = dap_chain_balance_scan(l_coins_str)))) { + printf("Error: Invalid coins format\n"); + return -6; + } + + dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str); + + if (!check_token_in_ledger(l_json_coins, l_delegated_ticker_str)) { + printf("Error: No delegated token found\n"); + return -7; + } + json_object_put(l_json_coins); + + uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001"); // TODO 16126 + // uint256_t l_emission_rate = dap_ledger_token_get_emission_rate(l_ledger, l_delegated_ticker_str); + // if (IS_ZERO_256(l_emission_rate)) { + // printf("Error: Invalid token emission rate\n"); + // return -8; + // } + + if (MULT_256_COIN(l_value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) { + printf("Error: Invalid coins format\n"); + return -9; + } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_str); + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str); + if (!l_chain_id_str) { + printf("Error: Missing or invalid chain_id argument\n"); + return -10; + } + + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) { + printf("Error: Missing wallet argument\n"); + return -11; + } + + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) { + printf("Error: Missing fee argument\n"); + return -12; + } + + if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) { + printf("Error: Invalid fee format\n"); + return -13; + } + + // Read time staking + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-time_staking", &l_time_staking_str) || !l_time_staking_str) { + printf("Error: Missing time staking argument\n"); + return -14; + } + + if (dap_strlen(l_time_staking_str) != 6) { + printf("Error: Invalid time staking format\n"); + return -15; + } + + char l_time_staking_month_str[3] = {l_time_staking_str[2], l_time_staking_str[3], 0}; + int l_time_staking_month = atoi(l_time_staking_month_str); + if (l_time_staking_month < 1 || l_time_staking_month > 12) { + printf("Error: Invalid time staking month\n"); + return -16; + } + + char l_time_staking_day_str[3] = {l_time_staking_str[4], l_time_staking_str[5], 0}; + int l_time_staking_day = atoi(l_time_staking_day_str); + if (l_time_staking_day < 1 || l_time_staking_day > 31) { + printf("Error: Invalid time staking day\n"); + return -17; + } + + l_time_staking = dap_time_from_str_simplified(l_time_staking_str); + if (0 == l_time_staking) { + printf("Error: Invalid time staking\n"); + return -18; + } + dap_time_t l_time_now = dap_time_now(); + if (l_time_staking < l_time_now) { + printf("Error: Time staking is in the past\n"); + return -19; + } + l_time_staking -= l_time_now; + + if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-reinvest", &l_reinvest_percent_str) && NULL != l_reinvest_percent_str) { + l_reinvest_percent = dap_chain_coins_to_balance(l_reinvest_percent_str); + if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1) { + printf("Error: Invalid reinvest percentage\n"); + return -20; + } + if (IS_ZERO_256(l_reinvest_percent)) { + int l_reinvest_percent_int = atoi(l_reinvest_percent_str); + if (l_reinvest_percent_int < 0 || l_reinvest_percent_int > 100) { + printf("Error: Invalid reinvest percentage\n"); + return -21; + } + l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int); + MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent); + } + } + + if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallets_path, NULL))) { + printf("Error: Unable to open wallet '%s'\n", l_wallet_str); + return -22; + } + + + if (NULL == (l_addr_holder = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)))) { + dap_chain_wallet_close(l_wallet); + printf("Error: Unable to get wallet address for '%s'\n", l_wallet_str); + return -24; + } + + snprintf(data, sizeof(data), + "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", + dap_chain_addr_to_str(l_addr_holder), l_net_name); + DAP_DEL_Z(l_addr_holder); + + json_object *l_json_outs = request_command_to_rpc_by_curl(data); + uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str); + json_object_put(l_json_outs); + if (compare256(l_value_balance, l_value) == -1) { + dap_chain_wallet_close(l_wallet); + printf("Error: Insufficient funds in wallet\n"); + return -23; + } + + l_key_from = dap_chain_wallet_get_key(l_wallet, 0); + + // Make transfer transaction + dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_net_name, l_key_from, + l_ticker_str, l_value, l_value_fee, + l_time_staking, l_reinvest_percent, + l_delegated_ticker_str, l_value_delegated, l_chain_id_str); + + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); + dap_chain_datum_tx_delete(l_tx); + + dap_chain_wallet_close(l_wallet); + dap_enc_key_delete(l_key_from); + + return 0; +} + + +dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, + const char *a_main_ticker, + uint256_t a_value, uint256_t a_value_fee, + dap_time_t a_time_staking, uint256_t a_reinvest_percent, + const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * l_chain_id_str) +{ + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID }; + // check valid param + if (!a_net_name || !a_key_from || + !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value)) + return NULL; + + const char *l_native_ticker = s_get_native_ticker(a_net_name); + bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker); + // find the transactions from which to take away coins + uint256_t l_value_transfer = {}; // how many coins to transfer + uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {}; + dap_chain_addr_t * l_addr_fee = NULL; + dap_chain_addr_t l_addr = {}; + + dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name)); + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee); + SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); + + json_object *l_outs_native = get_tx_outs_by_curl(l_native_ticker, a_net_name, &l_addr); + if (!l_outs_native) { + return NULL; + } + + json_object *l_outs_main = NULL; + if (!dap_strcmp(a_main_ticker, l_native_ticker)) { + l_outs_main = l_outs_native; + } else { + l_outs_main = get_tx_outs_by_curl(a_main_ticker, a_net_name, &l_addr); + } + int l_out_native_count = json_object_array_length(l_outs_native); + int l_out_main_count = json_object_array_length(l_outs_main); + + dap_list_t *l_list_fee_out = NULL; + if (l_main_native) + SUM_256_256(l_value_need, l_total_fee, &l_value_need); + else if (!IS_ZERO_256(l_total_fee)) { + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, + l_total_fee, + &l_fee_transfer); + if (!l_list_fee_out) { + printf("Not enough funds to pay fee"); + json_object_put(l_outs_native); + json_object_put(l_outs_main); + return NULL; + } + } + // list of transaction with 'out' items + dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_main, l_out_main_count, + l_value_need, + &l_value_transfer); + if (!l_list_used_out) { + printf("Not enough funds to transfer"); + json_object_put(l_outs_native); + json_object_put(l_outs_main); + return NULL; + } + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + + // add 'in' items + { + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + if (l_list_fee_out) { + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); + dap_list_free_full(l_list_fee_out, NULL); + } + } + + // add 'in_ems' item + { + dap_chain_id_t l_chain_id = { }; + dap_chain_id_parse(l_chain_id_str, &l_chain_id); + dap_hash_fast_t l_blank_hash = {}; + dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(l_chain_id, &l_blank_hash, a_delegated_ticker_str); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems); + } + + // add 'out_cond' and 'out_ext' items + { + uint256_t l_value_pack = {}, l_native_pack = {}; // how much coin add to 'out_ext' items + dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock( + l_uid, a_value, a_time_staking, a_reinvest_percent); + if (l_tx_out_cond) { + SUM_256_256(l_value_pack, a_value, &l_value_pack); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond); + DAP_DEL_Z(l_tx_out_cond); + } else { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Cant add conditional output\n"); + return NULL; + } + + uint256_t l_value_back = {}; + // Network fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Cant add network fee output\n"); + return NULL; + } + if (l_main_native) + SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); + else + SUM_256_256(l_native_pack, l_net_fee, &l_native_pack); + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Cant add validator's fee output\n"); + return NULL; + } + if (l_main_native) + SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); + else + SUM_256_256(l_native_pack, a_value_fee, &l_native_pack); + } + // coin back + SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Cant add coin back output for main ticker\n"); + return NULL; + } + } + // fee coin back + if (!IS_ZERO_256(l_fee_transfer)) { + SUBTRACT_256_256(l_fee_transfer, l_native_pack, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Cant add coin back output for native ticker\n"); + return NULL; + } + } + } + } + + // add delegated token emission 'out_ext' + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_delegated_value, a_delegated_ticker_str) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Cant add delegated token emission output\n"); + return NULL; + } + + return l_tx; + // // add 'sign' item + // if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) { + // dap_chain_datum_tx_delete(l_tx); + // printf("Error: Can't add sign output\n"); + // return NULL; + // } + + // size_t l_tx_size = dap_chain_datum_tx_get_size( l_tx ); + // dap_chain_datum_t *l_datum = dap_chain_datum_create( DAP_CHAIN_DATUM_TX, l_tx, l_tx_size ); + + // return l_datum; +} + + +int dap_cli_take_compose(int a_argc, char **a_argv) +{ + int arg_index = 1; + const char *l_net_str, *l_ticker_str, *l_wallet_str, *l_tx_str, *l_tx_burning_str, *l_chain_id_str, *l_value_fee_str; + l_net_str = l_ticker_str = l_wallet_str = l_tx_str = l_tx_burning_str = l_chain_id_str = l_value_fee_str = NULL; + char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; + int l_prev_cond_idx = 0; + uint256_t l_value_delegated = {}; + uint256_t l_value_fee = {}; + dap_chain_wallet_t *l_wallet; + dap_hash_fast_t l_tx_hash; + dap_chain_tx_out_cond_t *l_cond_tx = NULL; + dap_enc_key_t *l_owner_key; + + + const char *l_hash_out_type = NULL; + dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); + if (!l_hash_out_type) + l_hash_out_type = "hex"; + if (dap_strcmp(l_hash_out_type, "hex") && dap_strcmp(l_hash_out_type, "base58")) { + printf("Error: Invalid hash type argument\n"); + return -1; + } + + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str) || NULL == l_net_str) { + printf("Error: Missing or invalid network argument\n"); + return -2; + } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str); + if (!l_chain_id_str) { + printf("Error: Missing or invalid chain_id argument\n"); + return -10; + } + + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_str) || NULL == l_tx_str) { + printf("Error: Missing or invalid transaction argument\n"); + return -5; + } + + if (dap_chain_hash_fast_from_str(l_tx_str, &l_tx_hash)) { + printf("Error: Invalid transaction hash\n"); + return -6; + } + + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + l_tx_str, l_net_str); + + json_object *response = request_command_to_rpc_by_curl(data); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return -15; + } + + json_object *items = NULL; + json_object *items_array = json_object_array_get_idx(response, 0); + if (items_array) { + items = json_object_object_get(items_array, "ITEMS"); + } + if (!items) { + printf("Error: No items found in response\n"); + return -16; + } + int items_count = json_object_array_length(items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (dap_strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK")) { + l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); + l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; + l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); + l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK; + l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); + l_cond_tx->subtype.srv_stake_lock.time_unlock = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "time_unlock"))); + break; + } + } + } + if (!l_cond_tx) { + printf("Error: No transaction output condition found\n"); + return -7; + } + + + json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); + const char *spent_outs_value = json_object_get_string(spent_outs); + if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { + printf("Error: Transaction output item already used\n"); + return -9; + } + + json_object *response_header_array = json_object_array_get_idx(response, 0); + if (!response_header_array) { + printf("Error: Failed to get items array from response\n"); + return -10; + } + + json_object *token_ticker_obj = json_object_object_get(response_header_array, "token ticker"); + if (!token_ticker_obj) { + printf("Error: Token ticker not found in response\n"); + return -11; + } + l_ticker_str = json_object_get_string(token_ticker_obj); + + + + dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str); + + uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001"); + + if (IS_ZERO_256(l_emission_rate) || + MULT_256_COIN(l_cond_tx->header.value, l_emission_rate, &l_value_delegated) || + IS_ZERO_256(l_value_delegated)) { + printf("Error: Invalid coins format\n"); + return -12; + } + + + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) { + printf("Error: Missing or invalid wallet argument\n"); + return -13; + } + + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) { + printf("Error: Missing or invalid fee argument\n"); + return -14; + } + + if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) { + printf("Error: Invalid fee format\n"); + return -15; + } + + if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path, NULL))) { + printf("Error: Unable to open wallet\n"); + return -16; + } + + if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) { + dap_chain_wallet_close(l_wallet); + printf("Error: Owner key not found\n"); + return -17; + } + + if (l_cond_tx->subtype.srv_stake_lock.time_unlock > dap_time_now()) { + dap_chain_wallet_close(l_wallet); + dap_enc_key_delete(l_owner_key); + printf("Error: Not enough time has passed for unlocking\n"); + return -19; + } + dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_net_str, l_owner_key, &l_tx_hash, l_prev_cond_idx, + l_ticker_str, l_cond_tx->header.value, l_value_fee, + l_delegated_ticker_str, l_value_delegated); + + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); + + + dap_chain_datum_tx_delete(l_tx); + dap_enc_key_delete(l_owner_key); + + return 0; +} + + +dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, + dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, + const char *a_main_ticker, uint256_t a_value, + uint256_t a_value_fee, + const char *a_delegated_ticker_str, uint256_t a_delegated_value) +{ + // check valid param + if (!a_net_name | !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) { + printf("Error: Invalid parameters\n"); + return NULL; + } + + const char *l_native_ticker = s_get_native_ticker(a_net_name); + bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker); + // find the transactions from which to take away coins + uint256_t l_value_transfer = {}; // how many coins to transfer + uint256_t l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {}; + dap_chain_addr_t* l_addr_fee = NULL; + dap_chain_addr_t l_addr = {}; + + dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name)); + dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL; + + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee); + + json_object *l_outs_native = get_tx_outs_by_curl(l_native_ticker, a_net_name, &l_addr); + if (!l_outs_native) { + return NULL; + } + + json_object *l_outs_delegated = get_tx_outs_by_curl(a_delegated_ticker_str, a_net_name, &l_addr); + int l_out_native_count = json_object_array_length(l_outs_native); + int l_out_delegated_count = json_object_array_length(l_outs_delegated); + + SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); + if (!IS_ZERO_256(l_total_fee)) { + if (!l_main_native) { + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, + l_total_fee, + &l_fee_transfer); + if (!l_list_fee_out) { + printf("Not enough funds to pay fee"); + json_object_put(l_outs_native); + json_object_put(l_outs_delegated); + return NULL; + } + } else if (compare256(a_value, l_total_fee) == -1) { + printf("Error: Total fee more than stake\n"); + return NULL; + } + } + if (!IS_ZERO_256(a_delegated_value)) { + l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count, + a_delegated_value, + &l_value_transfer); + if (!l_list_used_out) { + printf("Not enough funds to pay fee"); + json_object_put(l_outs_native); + json_object_put(l_outs_delegated); + return NULL; + } + } + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + + // add 'in_cond' & 'in' items + { + dap_chain_datum_tx_add_in_cond_item(&l_tx, a_stake_tx_hash, a_prev_cond_idx, 0); + if (l_list_used_out) { + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + } + if (l_list_fee_out) { + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); + dap_list_free_full(l_list_fee_out, NULL); + } + } + + // add 'out_ext' items + uint256_t l_value_back; + { + uint256_t l_value_pack = {}; // how much datoshi add to 'out' items + // Network fee + if(l_net_fee_used){ + if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker)){ + dap_chain_datum_tx_delete(l_tx); + printf("Error: Can't add network fee output\n"); + return NULL; + } + SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) + { + SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); + } + else { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Can't add validator's fee output\n"); + return NULL; + } + } + // coin back + //SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back); + if(l_main_native){ + if (SUBTRACT_256_256(a_value, l_value_pack, &l_value_back)) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Can't subtract value pack from value\n"); + return NULL; + } + if(!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker)!=1) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Can't add coin back output for main ticker\n"); + return NULL; + } + } + } else { + SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back); + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_value, a_main_ticker)!=1) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Can't add coin back output for main ticker\n"); + return NULL; + } + else + { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker)!=1) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Can't add coin back output for native ticker\n"); + return NULL; + } + } + } + } + + // add burning 'out_ext' + if (!IS_ZERO_256(a_delegated_value)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &c_dap_chain_addr_blank, + a_delegated_value, a_delegated_ticker_str) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Can't add burning output for delegated value\n"); + return NULL; + } + // delegated token coin back + SUBTRACT_256_256(l_value_transfer, a_delegated_value, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_delegated_ticker_str) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Error: Can't add coin back output for delegated ticker\n"); + return NULL; + } + } + } + + return l_tx; +} +uint256_t s_get_key_delegating_min_value(const char *a_net_str){ + uint256_t l_key_delegating_min_value = uint256_0; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", + a_net_str); + + json_object *response = request_command_to_rpc_by_curl(data); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return l_key_delegating_min_value; + } + + json_object *response_array = json_object_array_get_idx(response, 0); + if (!response_array) { + printf("Error: Invalid response format\n"); + return l_key_delegating_min_value; + } + + json_object *summary_obj = json_object_array_get_idx(response_array, json_object_array_length(response_array) - 1); + if (!summary_obj) { + printf("Error: Summary object not found in response\n"); + return l_key_delegating_min_value; + } + + json_object *key_delegating_min_value_obj = json_object_object_get(summary_obj, "key_delegating_min_value"); + if (!key_delegating_min_value_obj) { + printf("Error: key_delegating_min_value not found in summary\n"); + return l_key_delegating_min_value; + } + + const char *key_delegating_min_value_str = json_object_get_string(key_delegating_min_value_obj); + if (!key_delegating_min_value_str) { + printf("Error: Invalid key_delegating_min_value format\n"); + return l_key_delegating_min_value; + } + + l_key_delegating_min_value = dap_chain_balance_scan(key_delegating_min_value_str); + if (IS_ZERO_256(l_key_delegating_min_value)) { + printf("Error: Unrecognized number in key_delegating_min_value\n"); + return l_key_delegating_min_value; + } + + return l_key_delegating_min_value; +} + + +int dap_cli_voting_compose(int a_argc, char **a_argv) +{ + int arg_index = 1; + const char* l_question_str = NULL; + const char* l_options_list_str = NULL; + const char* l_voting_expire_str = NULL; + const char* l_max_votes_count_str = NULL; + const char* l_fee_str = NULL; + const char* l_wallet_str = NULL; + const char* l_net_str = NULL; + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); + // Select chain network + if(!l_net_str) { + printf("Voting requires parameter '-net' to be valid.\n"); + return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING; + } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str); + if (!l_question_str){ + printf("Voting requires a question parameter to be valid.\n"); + return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_PARAM_MISSING; + } + + if (strlen(l_question_str) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ + printf("The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH); + return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_CONTAIN_MAX_CHARACTERS; + } + + dap_list_t *l_options_list = NULL; + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-options", &l_options_list_str); + if (!l_options_list_str){ + printf("Voting requires a question parameter to be valid.\n"); + return -DAP_CHAIN_NET_VOTE_CREATE_OPTION_PARAM_MISSING; + } + // Parse options list + l_options_list = dap_get_options_list_from_str(l_options_list_str); + if(!l_options_list || dap_list_length(l_options_list) < 2){ + printf("Number of options must be 2 or greater.\n"); + return -DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR; + } + + if(dap_list_length(l_options_list)>DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){ + printf("The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT); + return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS; + } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str); + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str); + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str); + if (!l_fee_str){ + printf("Voting requires parameter -fee to be valid.\n"); + return -DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID; + } + uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str); + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str); + if (!l_wallet_str){ + printf("Voting requires parameter -w to be valid.\n"); + return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID; + } + + dap_time_t l_time_expire = 0; + if (l_voting_expire_str) + l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str); + if (l_voting_expire_str && !l_time_expire){ + printf("Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"\n"); + return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT; + } + uint64_t l_max_count = 0; + if (l_max_votes_count_str) + l_max_count = strtoul(l_max_votes_count_str, NULL, 10); + + bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false; + bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false; + dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, c_wallets_path,NULL); + if (!l_wallet_fee) { + printf("Wallet %s does not exist\n", l_wallet_str); + return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; + } + + dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net_str); + dap_list_free(l_options_list); + dap_chain_wallet_close(l_wallet_fee); + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); + return 0; +} + + +dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, + uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, + bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, + const char *a_net_str) { + + if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ + return NULL; + } + + // Parse options list + + if(dap_list_length(a_options) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){ + return NULL; + } + + if (IS_ZERO_256(a_fee)) { + return NULL; + } + + dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str)); + + if(!l_addr_from) { + return NULL; + } + + const char *l_native_ticker = s_get_native_ticker(a_net_str); + uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer; + dap_chain_addr_t *l_addr_fee = NULL; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee); + SUM_256_256(l_net_fee, a_fee, &l_total_fee); + + json_object *l_outs = NULL; + int l_outputs_count = 0; + if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count)) { + return NULL; + } + + dap_list_t *l_list_used_out = NULL; + l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_total_fee, + &l_value_transfer); + + json_object_put(l_outs); + if (!l_list_used_out) { + printf("Not enough funds to transfer"); + return NULL; + } + + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + + // Add Voting item + dap_chain_tx_voting_t* l_voting_item = dap_chain_datum_tx_item_voting_create(); + + dap_chain_datum_tx_add_item(&l_tx, l_voting_item); + DAP_DELETE(l_voting_item); + + // Add question to tsd data + dap_chain_tx_tsd_t* l_question_tsd = dap_chain_datum_voting_question_tsd_create(a_question, strlen(a_question)); + dap_chain_datum_tx_add_item(&l_tx, l_question_tsd); + + // Add options to tsd + dap_list_t *l_temp = a_options; + while(l_temp){ + if(strlen((char*)l_temp->data) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + dap_chain_tx_tsd_t* l_option = dap_chain_datum_voting_answer_tsd_create((char*)l_temp->data, strlen((char*)l_temp->data)); + if(!l_option){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_option); + DAP_DEL_Z(l_option); + + l_temp = l_temp->next; + } + + // add voting expire time if needed + if(a_expire_vote != 0){ + dap_time_t l_expired_vote = a_expire_vote; + if (l_expired_vote < dap_time_now()){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + + dap_chain_tx_tsd_t* l_expired_item = dap_chain_datum_voting_expire_tsd_create(l_expired_vote); + if(!l_expired_item){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_expired_item); + DAP_DEL_Z(l_expired_item); + } + + // Add vote max count if needed + if (a_max_vote != 0) { + dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote); + if(!l_max_votes_item){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_max_votes_item); + DAP_DEL_Z(l_max_votes_item); + } + + if (a_delegated_key_required) { + dap_chain_tx_tsd_t* l_delegated_key_req_item = dap_chain_datum_voting_delegated_key_required_tsd_create(true); + if(!l_delegated_key_req_item){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_delegated_key_req_item); + DAP_DEL_Z(l_delegated_key_req_item); + } + + if(a_vote_changing_allowed){ + dap_chain_tx_tsd_t* l_vote_changing_item = dap_chain_datum_voting_vote_changing_allowed_tsd_create(true); + if(!l_vote_changing_item){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item); + DAP_DEL_Z(l_vote_changing_item); + } + + // add 'in' items + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + uint256_t l_value_pack = {}; + // Network fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) + SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1) + SUM_256_256(l_value_pack, a_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // coin back + uint256_t l_value_back; + SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); + if(!IS_ZERO_256(l_value_back)) { + if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + + + return l_tx; +} diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 8b13789179..41c05c0e90 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -1 +1,97 @@ +/* + * Authors: + * Roman Padenkov <roman.padenkov@demlabs.net> + * Olzhas Zharasbaev <oljas.jarasbaev@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * DeM Labs Open source community https://github.com/demlabsinc + * Copyright (c) 2025-2026 + * All rights reserved. + This file is part of DAP (Distributed Applications Platform) the open source project + + DAP (Distributed Applications Platform) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + */ + + #pragma once + #include "dap_chain_common.h" + #include "dap_list.h" + #include "dap_math_ops.h" + #include "dap_chain_datum_tx.h" + #include "dap_chain_wallet.h" + #include "dap_chain_net_srv_xchange.h" + + #include <json-c/json.h> + + + + + // #define RPC_NODES_URL "http://rpc.cellframe.net" +#define RPC_NODES_URL "45.76.140.191:8081" + +#define NET_COUNT 6 + +const char *c_wallets_path = NULL; + +typedef struct { + char name[20]; + char native_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; + dap_chain_net_id_t net_id; +} NetInfo; + +static NetInfo netinfo[NET_COUNT] = { + {"riemann", "tKEL", {.uint64 = 0x000000000000dddd}}, + {"raiden", "tCELL", {.uint64 = 0x000000000000bbbb}}, + {"KelVPN", "KEL", {.uint64 = 0x1807202300000000}}, + {"Backbone", "CELL", {.uint64 = 0x0404202200000000}}, + {"mileena", "tMIL", {.uint64 = 0x000000000000cccc}}, + {"subzero", "tCELL", {.uint64 = 0x000000000000acca}} +}; + +int dap_tx_create_compose(int argc, char ** argv); +int dap_tx_create_xchange_compose(int argc, char ** argv); +int dap_tx_cond_create_compose(int argc, char ** argv); +int dap_cli_hold_compose(int a_argc, char **a_argv); +int dap_cli_take_compose(int a_argc, char **a_argv); +int dap_cli_voting_compose(int a_argc, char **a_argv); +dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer); +dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, + const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num); +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,const char *a_token_sell, + uint256_t a_datoshi_sell, uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet); +static dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, + const char *a_native_ticker, const char *a_net_name); +dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name, + dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, + const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], + uint256_t a_value, uint256_t a_value_per_unit_max, + dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, + uint256_t a_value_fee, const void *a_cond, + size_t a_cond_size, const char *a_hash_out_type); +bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee); +bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count); +dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, + const char *a_main_ticker, + uint256_t a_value, uint256_t a_value_fee, + dap_time_t a_time_staking, uint256_t a_reinvest_percent, + const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * l_chain_id_str); +bool check_token_in_ledger(json_object *l_json_coins, const char *a_token); +dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, + dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, + const char *a_main_ticker, uint256_t a_value, + uint256_t a_value_fee, + const char *a_delegated_ticker_str, uint256_t a_delegated_value); +dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, + uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, + bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, + const char *a_net_str); -- GitLab From 1112c71b19b871ab35311dcc8f8b7a1450727a56 Mon Sep 17 00:00:00 2001 From: Konstantin <konstatin.kuharenko@demlabs.net> Date: Mon, 24 Mar 2025 12:37:06 +0700 Subject: [PATCH 18/53] [*] link compose --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22001f9388..a7908ac9a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ endif() if(NOT DEFINED CELLFRAME_MODULES) include (dap-sdk/cmake/OS_Detection.cmake) - set(CELLFRAME_MODULES "core chains mining network cs-dag-poa cs-esbocs cs-none srv-stake srv-voting srv-bridge srv-xchange srv-emit-delegate") + set(CELLFRAME_MODULES "core chains mining network cs-dag-poa cs-esbocs cs-none srv-stake srv-voting srv-bridge srv-xchange srv-emit-delegate compose") if(LINUX OR DARWIN) set(CELLFRAME_MODULES "${CELLFRAME_MODULES} srv-vpn") -- GitLab From 63817e695b823d2ee8364bf7cc5e2ce1f5f47049 Mon Sep 17 00:00:00 2001 From: Konstantin <konstatin.kuharenko@demlabs.net> Date: Mon, 24 Mar 2025 14:52:52 +0700 Subject: [PATCH 19/53] [*] fix build wallet --- modules/net/srv/CMakeLists.txt | 2 +- modules/net/srv/{ => include}/dap_chain_net_srv_countries.h | 0 modules/net/srv/{ => include}/dap_chain_net_srv_geoip.h | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename modules/net/srv/{ => include}/dap_chain_net_srv_countries.h (100%) rename modules/net/srv/{ => include}/dap_chain_net_srv_geoip.h (100%) diff --git a/modules/net/srv/CMakeLists.txt b/modules/net/srv/CMakeLists.txt index d48b0f9a3b..818863316a 100644 --- a/modules/net/srv/CMakeLists.txt +++ b/modules/net/srv/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project (dap_chain_net_srv) file(GLOB DAP_CHAIN_NET_SRV_SRCS *.c) -file(GLOB DAP_CHAIN_NET_SRV_HEADERS *.h) +file(GLOB DAP_CHAIN_NET_SRV_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_SRCS} ${DAP_CHAIN_NET_SRV_HEADERS}) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/libmaxminddb ${CMAKE_CURRENT_BINARY_DIR}/../../../3rdparty/libmaxminddb) diff --git a/modules/net/srv/dap_chain_net_srv_countries.h b/modules/net/srv/include/dap_chain_net_srv_countries.h similarity index 100% rename from modules/net/srv/dap_chain_net_srv_countries.h rename to modules/net/srv/include/dap_chain_net_srv_countries.h diff --git a/modules/net/srv/dap_chain_net_srv_geoip.h b/modules/net/srv/include/dap_chain_net_srv_geoip.h similarity index 100% rename from modules/net/srv/dap_chain_net_srv_geoip.h rename to modules/net/srv/include/dap_chain_net_srv_geoip.h -- GitLab From 9cc1644961e32d1728282cd5414ce6a38ba2d226 Mon Sep 17 00:00:00 2001 From: Konstantin <konstatin.kuharenko@demlabs.net> Date: Mon, 24 Mar 2025 15:31:16 +0700 Subject: [PATCH 20/53] [*] more fix --- modules/chain/include/dap_chain_policy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/chain/include/dap_chain_policy.h b/modules/chain/include/dap_chain_policy.h index 883e8469c5..5ef6f54dd2 100644 --- a/modules/chain/include/dap_chain_policy.h +++ b/modules/chain/include/dap_chain_policy.h @@ -104,6 +104,6 @@ DAP_STATIC_INLINE const char *dap_chain_policy_to_str(dap_chain_policy_t *a_poli */ DAP_STATIC_INLINE bool dap_chain_policy_num_is_valid(uint64_t a_num) { - uint32_t l_num = dap_maxval(l_num); + uint32_t l_num = UINT32_MAX; return (a_num && a_num <= l_num); } \ No newline at end of file -- GitLab From 5ab4733ae3c1d6fe040295961dee3953686546e3 Mon Sep 17 00:00:00 2001 From: Konstantin <konstatin.kuharenko@demlabs.net> Date: Mon, 24 Mar 2025 17:39:26 +0700 Subject: [PATCH 21/53] [8] new fix --- modules/net/srv/include/dap_chain_net_srv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/net/srv/include/dap_chain_net_srv.h b/modules/net/srv/include/dap_chain_net_srv.h index c8b252b9af..cc697439b7 100755 --- a/modules/net/srv/include/dap_chain_net_srv.h +++ b/modules/net/srv/include/dap_chain_net_srv.h @@ -50,7 +50,7 @@ typedef struct { typedef struct dap_chain_net_srv_abstract { - uint8_t class; //Class of service (once or permanent) + uint8_t c; //Class of service (once or permanent) dap_chain_net_srv_uid_t type_id; //Type of service union { struct { -- GitLab From 78bed9171fb2ecaf6d20c8bfef5c237534469cfa Mon Sep 17 00:00:00 2001 From: Konstantin <konstatin.kuharenko@demlabs.net> Date: Tue, 25 Mar 2025 13:25:11 +0700 Subject: [PATCH 22/53] [*] add extern C --- modules/compose/include/dap_chain_tx_compose.h | 8 ++++++++ .../service/voting/include/dap_chain_net_srv_voting.h | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 41c05c0e90..2e626778d0 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -58,6 +58,10 @@ static NetInfo netinfo[NET_COUNT] = { {"subzero", "tCELL", {.uint64 = 0x000000000000acca}} }; +#ifdef __cplusplus +extern "C" { +#endif + int dap_tx_create_compose(int argc, char ** argv); int dap_tx_create_xchange_compose(int argc, char ** argv); int dap_tx_cond_create_compose(int argc, char ** argv); @@ -95,3 +99,7 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, const char *a_net_str); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h index 70509562bd..7ec943e6c4 100644 --- a/modules/service/voting/include/dap_chain_net_srv_voting.h +++ b/modules/service/voting/include/dap_chain_net_srv_voting.h @@ -146,11 +146,20 @@ enum DAP_CHAIN_NET_VOTE_DUMP_ERROR{ DAP_CHAIN_NET_VOTE_DUMP_MEMORY_ERR }; +#if defined(__cplusplus) +extern "C" { +#endif + int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wallet_t *a_wallet, dap_hash_fast_t a_hash, uint64_t a_option_idx, dap_chain_net_t *a_net, const char *a_hash_out_type, char **a_hash_tx_out); dap_list_t *dap_chain_net_vote_list(dap_chain_net_t *a_net); +dap_list_t* dap_get_options_list_from_str(const char* a_str); dap_chain_net_vote_info_t *dap_chain_net_vote_extract_info(dap_chain_net_t *a_net, dap_hash_fast_t *a_vote_hash); void dap_chain_net_vote_info_free(dap_chain_net_vote_info_t *a_info); +#if defined(__cplusplus) +} +#endif + -- GitLab From 06dd70822ac46fb839c103b19406464e47160918 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Wed, 26 Mar 2025 13:06:07 +0700 Subject: [PATCH 23/53] [*] port all in sdk --- modules/compose/CMakeLists.txt | 2 +- modules/compose/dap_chain_tx_compose.c | 2089 +++++++++++++++-- .../compose/include/dap_chain_tx_compose.h | 33 +- .../service/voting/dap_chain_net_srv_voting.c | 5 - .../voting/include/dap_chain_net_srv_voting.h | 1 - 5 files changed, 1877 insertions(+), 253 deletions(-) diff --git a/modules/compose/CMakeLists.txt b/modules/compose/CMakeLists.txt index 456054471c..82f0ea9189 100644 --- a/modules/compose/CMakeLists.txt +++ b/modules/compose/CMakeLists.txt @@ -6,7 +6,7 @@ file(GLOB DAP_CHAIN_COMPOSE_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_COMPOSE_SRCS} ${DAP_CHAIN_COMPOSE_HEADERS}) -target_link_libraries(${PROJECT_NAME} dap_cli_server dap_chain_net dap_chain_net_srv dap_enc_server dap_json_rpc dap_chain_net_srv_xchange dap_chain_net_srv_voting) +target_link_libraries(${PROJECT_NAME} dap_cli_server dap_chain_net dap_chain_net_srv dap_enc_server dap_json_rpc dap_chain_net_srv_xchange dap_chain_net_srv_voting dap_app_cli dap_cli_server) target_include_directories(${PROJECT_NAME} PUBLIC include/ ) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../dap-sdk/3rdparty/json-c) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 3b035cf1ad..ce082f0782 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -29,9 +29,20 @@ #include "dap_chain_datum_tx_voting.h" #include "dap_chain_net_srv_stake_lock.h" #include "dap_chain_net_srv_voting.h" +#include "dap_chain_net_tx.h" +#include "dap_net.h" +#include "dap_app_cli.h" +#include "dap_json_rpc.h" +#include "dap_app_cli_net.h" +#include "dap_cli_server.h" -#include <curl/curl.h> +#include <netdb.h> +#include <json-c/json.h> +static json_object* s_request_command_to_rpc(const char *request); + + +const char *arg_wallets_path = NULL; static const char* s_get_native_ticker(const char* name) { for (int i = 0; i < NET_COUNT; i++) { @@ -52,6 +63,251 @@ static dap_chain_net_id_t s_get_net_id(const char* name) { return empty_id; } + +int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add) { + json_object *items_array; + if (!json_object_object_get_ex(json_tx, "items", &items_array)) { + fprintf(stderr, "Failed to get 'items' array\n"); + return 1; + } + json_object_array_add(items_array, json_add); + return 0; +} + + +static json_object* s_request_command_to_rpc(const char *request) { + struct addrinfo hints, *res = NULL, *p = NULL; + int sockfd = -1; + struct sockaddr_storage l_saddr = { }; + char l_ip[INET6_ADDRSTRLEN] = { '\0' }; + uint16_t l_port = 0; + char path[256] = "/"; + json_object *response_json = NULL; + dap_json_rpc_response_t* response = NULL; + + if (strchr(RPC_NODES_URL, ':') != NULL && strchr(RPC_NODES_URL, '/') == NULL) { + if (dap_net_parse_config_address(RPC_NODES_URL, l_ip, &l_port, &l_saddr, NULL) < 0) { + printf("Incorrect address \"%s\" format\n", RPC_NODES_URL); + return NULL; + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + char port_str[6]; + snprintf(port_str, sizeof(port_str), "%u", l_port); + + if (getaddrinfo(l_ip, port_str, &hints, &res) != 0) { + fprintf(stderr, "Failed to resolve IP address\n"); + return NULL; + } + } else { + const char *host_start = strstr(RPC_NODES_URL, "://"); + if (!host_start) { + fprintf(stderr, "Invalid URL format\n"); + return NULL; + } + host_start += 3; // Move past "://" + + char host[256] = {0}; + const char *path_start = strchr(host_start, '/'); + size_t host_len = path_start ? (size_t)(path_start - host_start) : strlen(host_start); + if (host_len >= sizeof(host)) host_len = sizeof(host) - 1; + strncpy(host, host_start, host_len); + host[host_len] = '\0'; // Ensure null termination + + printf("Extracted host: %s\n", host); // Debugging output + + struct addrinfo hints = {0}, *res = NULL; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(host, "80", &hints, &res) != 0) { + fprintf(stderr, "Failed to resolve hostname: %s\n", host); + return NULL; + } + } + + for (p = res; p != NULL; p = p->ai_next) { + sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (sockfd == -1) continue; + + if (connect(sockfd, p->ai_addr, p->ai_addrlen) == 0) { + break; + } + + close(sockfd); + sockfd = -1; + } + + freeaddrinfo(res); + + if (sockfd == -1) { + fprintf(stderr, "Failed to connect to host\n"); + return NULL; + } + + char http_request[1024]; + snprintf(http_request, sizeof(http_request), + "POST %s HTTP/1.1\r\n" + "Host: %s\r\n" + "Content-Type: application/json\r\n" + "Content-Length: %zu\r\n" + "Connection: close\r\n\r\n" + "%s", + path, l_ip, strlen(request), request); + + if (send(sockfd, http_request, strlen(http_request), 0) < 0) { + fprintf(stderr, "Failed to send request\n"); + close(sockfd); + return NULL; + } + + dap_app_cli_cmd_state_t cmd = { + .cmd_res = DAP_NEW_Z_SIZE(char, MAX_RESPONSE_SIZE), + .cmd_res_cur = 0, + .hdr_len = 0 // Ensure this is initialized + }; + + if (!cmd.cmd_res) { + fprintf(stderr, "Memory allocation failed\n"); + close(sockfd); + return NULL; + } + + int l_status = 1; + while (l_status > 0) { + l_status = dap_app_cli_http_read(sockfd, &cmd, l_status); + } + + close(sockfd); + + response = dap_json_rpc_response_from_string(cmd.cmd_res + cmd.hdr_len); + DAP_DELETE(cmd.cmd_res); + + if (!response) { + return NULL; + } + + response_json = response->result_json_object; + json_object_get(response_json); // Prevent early free + + json_object *errors_array; + if (json_object_is_type(response_json, json_type_array) && json_object_array_length(response_json) > 0) { + json_object *first_element = json_object_array_get_idx(response_json, 0); + if (json_object_object_get_ex(first_element, "errors", &errors_array)) { + int errors_len = json_object_array_length(errors_array); + for (int j = 0; j < errors_len; j++) { + json_object *error_obj = json_object_array_get_idx(errors_array, j); + json_object *error_code, *error_message; + if (json_object_object_get_ex(error_obj, "code", &error_code) && + json_object_object_get_ex(error_obj, "message", &error_message)) { + printf("Error %d: %s\n", json_object_get_int(error_code), json_object_get_string(error_message)); + } + } + json_object_put(response_json); // Free memory + response_json = NULL; + } + } + + dap_json_rpc_response_free(response); + return response_json; +} + + +bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee) { + char data[512]; + snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name); + json_object *l_json_get_fee = s_request_command_to_rpc(data); + if (!l_json_get_fee) { + return false; + } + + json_object *l_first_result = json_object_array_get_idx(l_json_get_fee, 0); + if (!l_first_result || !json_object_is_type(l_first_result, json_type_object)) { + json_object_put(l_json_get_fee); + return false; + } + + json_object *l_fees = NULL; + if (!json_object_object_get_ex(l_first_result, "fees", &l_fees) || + !json_object_is_type(l_fees, json_type_object)) { + json_object_put(l_json_get_fee); + return false; + } + + json_object *l_network = NULL; + if (!json_object_object_get_ex(l_fees, "network", &l_network) || + !json_object_is_type(l_network, json_type_object)) { + json_object_put(l_json_get_fee); + return false; + } + + json_object *l_balance = NULL; + if (!json_object_object_get_ex(l_network, "balance", &l_balance) || + !json_object_is_type(l_balance, json_type_string)) { + json_object_put(l_json_get_fee); + return false; + } + *a_net_fee = dap_chain_balance_scan(json_object_get_string(l_balance)); + + json_object *l_addr = NULL; + if (!json_object_object_get_ex(l_network, "addr", &l_addr) || + !json_object_is_type(l_addr, json_type_string)) { + json_object_put(l_json_get_fee); + return false; + } + *l_addr_fee = dap_chain_addr_from_str(json_object_get_string(l_addr)); + + json_object_put(l_json_get_fee); + return true; +} + +bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count) { + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name); + json_object *l_json_outs = s_request_command_to_rpc(data); + if (!l_json_outs) { + return false; + } + + if (!json_object_is_type(l_json_outs, json_type_array)) { + json_object_put(l_json_outs); + return false; + } + + if (json_object_array_length(l_json_outs) == 0) { + json_object_put(l_json_outs); + return false; + } + + json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0); + if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) { + json_object_put(l_json_outs); + return false; + } + + json_object *l_first_item = json_object_array_get_idx(l_first_array, 0); + if (!l_first_item) { + json_object_put(l_json_outs); + return false; + } + + if (!json_object_object_get_ex(l_first_item, "outs", l_outs) || + !json_object_is_type(*l_outs, json_type_array)) { + json_object_put(l_json_outs); + return false; + } + + *l_outputs_count = json_object_array_length(*l_outs); + json_object_get(*l_outs); + json_object_put(l_json_outs); // Clean up the JSON object + return true; +} + + int dap_tx_create_xchange_compose(int argc, char ** argv) { int arg_index = 1; const char *l_net_name = NULL; @@ -62,6 +318,21 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) { const char *l_rate_str = NULL; const char *l_fee_str = NULL; + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + arg_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif + } else { + arg_wallets_path = dap_strdup(l_wallet_path); + } + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_sell", &l_token_sell); dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_buy", &l_token_buy); @@ -105,7 +376,7 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) { return -1; } - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, c_wallets_path, NULL); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, arg_wallets_path, NULL); if(!l_wallet) { printf("wallet %s does not exist", l_wallet_name); return -1; @@ -141,15 +412,6 @@ int dap_tx_create_compose(int argc, char ** argv) { const char * l_token_ticker = NULL; const char * l_net_name = NULL; const char * l_chain_name = NULL; - const char * l_emission_chain_name = NULL; - const char * l_tx_num_str = NULL; - const char *l_emission_hash_str = NULL; - const char *l_cert_str = NULL; - dap_cert_t *l_cert = NULL; - dap_enc_key_t *l_priv_key = NULL; - dap_chain_hash_fast_t l_emission_hash = {}; - size_t l_tx_num = 0; - dap_chain_wallet_t * l_wallet_fee = NULL; const char * l_hash_out_type = NULL; dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type); @@ -160,6 +422,21 @@ int dap_tx_create_compose(int argc, char ** argv) { return -1; } + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + arg_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif + } else { + arg_wallets_path = dap_strdup(l_wallet_path); + } + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); if (!l_net_name) { printf("tx_create requires parameter '-net'"); @@ -174,11 +451,6 @@ int dap_tx_create_compose(int argc, char ** argv) { dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name); dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-wallet_fee", &l_wallet_fee_name); dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-tx_num", &l_tx_num_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str); - - if(l_tx_num_str) - l_tx_num = strtoul(l_tx_num_str, NULL, 10); // Validator's fee if (dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) { @@ -206,18 +478,19 @@ int dap_tx_create_compose(int argc, char ** argv) { dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to); dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp); - if (!addr_base58_to) { - printf("tx_create requires parameter '-to_addr'"); - return -5; - } + if (!str_tmp) { printf("tx_create requires parameter '-value' to be valid uint256 value"); return -6; } - l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1; l_value_el_count = dap_str_symbol_count(str_tmp, ',') + 1; - if (l_addr_el_count != l_value_el_count) { + if (addr_base58_to) + l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1; + else + l_addr_el_count = l_value_el_count; + + if (addr_base58_to && l_addr_el_count != l_value_el_count) { printf("num of '-to_addr' and '-value' should be equal"); return -5; } @@ -243,32 +516,34 @@ int dap_tx_create_compose(int argc, char ** argv) { } DAP_DELETE(l_value_array); - l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count); - if (!l_addr_to) { - printf("Can't allocate memory"); - DAP_DELETE(l_value); - return -9; - } - char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count); - if (!l_addr_base58_to_array) { - DAP_DEL_MULTY(l_addr_to, l_value); - printf("Can't read '-to_addr' arg"); - return -10; - } - for (size_t i = 0; i < l_addr_el_count; ++i) { - l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]); - if(!l_addr_to[i]) { - for (size_t j = 0; j < i; ++j) { - DAP_DELETE(l_addr_to[j]); + if (addr_base58_to) { + l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count); + if (!l_addr_to) { + printf("Can't allocate memory"); + DAP_DELETE(l_value); + return -9; + } + char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count); + if (!l_addr_base58_to_array) { + DAP_DEL_MULTY(l_addr_to, l_value); + printf("Can't read '-to_addr' arg"); + return -10; + } + for (size_t i = 0; i < l_addr_el_count; ++i) { + l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]); + if(!l_addr_to[i]) { + for (size_t j = 0; j < i; ++j) { + DAP_DELETE(l_addr_to[j]); + } + DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value); + printf("destination address is invalid"); + return -11; } - DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value); - printf("destination address is invalid"); - return -11; } + DAP_DELETE(l_addr_base58_to_array); } - DAP_DELETE(l_addr_base58_to_array); - dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, c_wallets_path, NULL); + dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, arg_wallets_path, NULL); if(!l_wallet) { printf("Can't open wallet %s", l_from_wallet_name); return -12; @@ -276,7 +551,7 @@ int dap_tx_create_compose(int argc, char ** argv) { dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)); - for (size_t i = 0; i < l_addr_el_count; ++i) { + for (size_t i = 0; l_addr_to && i < l_addr_el_count; ++i) { if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) { printf("The transaction cannot be directed to the same address as the source."); for (size_t j = 0; j < l_addr_el_count; ++j) { @@ -288,8 +563,6 @@ int dap_tx_create_compose(int argc, char ** argv) { } - - l_priv_key = dap_chain_wallet_get_key(l_wallet, 0); dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count); json_object * l_json_obj_ret = json_object_new_object(); @@ -301,124 +574,67 @@ int dap_tx_create_compose(int argc, char ** argv) { return 0; } -bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee) { - char data[512]; - snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name); - json_object *l_json_get_fee = request_command_to_rpc_by_curl(data); - if (!l_json_get_fee) { - return false; - } - - json_object *l_first_result = json_object_array_get_idx(l_json_get_fee, 0); - if (!l_first_result || !json_object_is_type(l_first_result, json_type_object)) { - json_object_put(l_json_get_fee); - return false; - } - - json_object *l_fees = NULL; - if (!json_object_object_get_ex(l_first_result, "fees", &l_fees) || - !json_object_is_type(l_fees, json_type_object)) { - json_object_put(l_json_get_fee); - return false; - } +int dap_chain_datum_tx_add_out_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value) { + if (IS_ZERO_256(a_value)) + return -1; + + dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t); + if (!l_item) + return -1; + + l_item->header.type = TX_ITEM_TYPE_OUT; + l_item->header.value = a_value; + + int res = dap_chain_datum_tx_add_item(a_tx, l_item); + DAP_DELETE(l_item); + + return res; +} - json_object *l_network = NULL; - if (!json_object_object_get_ex(l_fees, "network", &l_network) || - !json_object_is_type(l_network, json_type_object)) { - json_object_put(l_json_get_fee); - return false; - } - json_object *l_balance = NULL; - if (!json_object_object_get_ex(l_network, "balance", &l_balance) || - !json_object_is_type(l_balance, json_type_string)) { - json_object_put(l_json_get_fee); - return false; - } - *a_net_fee = dap_chain_balance_scan(json_object_get_string(l_balance)); +int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value, const char *a_token) +{ + if (!a_token || IS_ZERO_256(a_value)) + return -1; - json_object *l_addr = NULL; - if (!json_object_object_get_ex(l_network, "addr", &l_addr) || - !json_object_is_type(l_addr, json_type_string)) { - json_object_put(l_json_get_fee); - return false; - } - *l_addr_fee = dap_chain_addr_from_str(json_object_get_string(l_addr)); + dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t); + if (!l_item) + return -2; + l_item->header.type = TX_ITEM_TYPE_OUT_EXT; + l_item->header.value = a_value; + dap_strncpy((char*)l_item->token, a_token, sizeof(l_item->token) - 1); - json_object_put(l_json_get_fee); - return true; + int result = dap_chain_datum_tx_add_item(a_tx, l_item); + DAP_DELETE(l_item); + return result; } -bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count) { - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", - dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name); - json_object *l_json_outs = request_command_to_rpc_by_curl(data); - if (!l_json_outs) { - return false; + +dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, + const char* a_token_ticker, + uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num) +{ + if (!a_addr_from || !a_token_ticker || !a_value) { + return NULL; } - if (!json_object_is_type(l_json_outs, json_type_array)) { - json_object_put(l_json_outs); - return false; + if (dap_chain_addr_check_sum(a_addr_from)) { + return NULL; } - if (json_object_array_length(l_json_outs) == 0) { - json_object_put(l_json_outs); - return false; + for (size_t i = 0; i < a_tx_num; ++i) { + // if (!a_addr_to || !a_addr_to[i]) { + // return NULL; + // } + if (a_addr_to && dap_chain_addr_check_sum(a_addr_to[i])) { + return NULL; + } + if (IS_ZERO_256(a_value[i])) { + return NULL; + } } - - json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0); - if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) { - json_object_put(l_json_outs); - return false; - } - - json_object *l_first_item = json_object_array_get_idx(l_first_array, 0); - if (!l_first_item) { - json_object_put(l_json_outs); - return false; - } - - if (!json_object_object_get_ex(l_first_item, "outs", l_outs) || - !json_object_is_type(*l_outs, json_type_array)) { - json_object_put(l_json_outs); - return false; - } - - *l_outputs_count = json_object_array_length(*l_outs); - json_object_get(*l_outs); - json_object_put(l_json_outs); // Clean up the JSON object - return true; -} - - -dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, - const char* a_token_ticker, - uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num) -{ - if (!a_addr_from || !a_token_ticker || !a_value || !a_tx_num) { - return NULL; - } - - if (dap_chain_addr_check_sum(a_addr_from)) { - return NULL; - } - - for (size_t i = 0; i < a_tx_num; ++i) { - if (!a_addr_to || !a_addr_to[i]) { - return NULL; - } - if (dap_chain_addr_check_sum(a_addr_to[i])) { - return NULL; - } - if (IS_ZERO_256(a_value[i])) { - return NULL; - } - } - const char * l_native_ticker = s_get_native_ticker(l_net_name); - bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker); + const char * l_native_ticker = s_get_native_ticker(l_net_name); + bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker); uint256_t l_value_transfer = {}; // how many coins to transfer uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {}; @@ -486,12 +702,18 @@ dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, if (l_single_channel) { // add 'out' items uint256_t l_value_pack = {}; // how much datoshi add to 'out' items for (size_t i = 0; i < a_tx_num; ++i) { - if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) == 1) { - SUM_256_256(l_value_pack, a_value[i], &l_value_pack); + if (a_addr_to) { + if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } } else { - dap_chain_datum_tx_delete(l_tx); - return NULL; + if (dap_chain_datum_tx_add_out_without_addr(&l_tx, a_value[i]) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } } + SUM_256_256(l_value_pack, a_value[i], &l_value_pack); } // Network fee if (l_net_fee_used) { @@ -522,9 +744,16 @@ dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, } } else { // add 'out_ext' items for (size_t i = 0; i < a_tx_num; ++i) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; + if (a_addr_to) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } else { + if (dap_chain_datum_tx_add_out_ext_item_without_addr(&l_tx, a_value[i], a_token_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } } } // coin back @@ -703,7 +932,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name); - json_object *l_json_coins = request_command_to_rpc_by_curl(data); + json_object *l_json_coins = s_request_command_to_rpc(data); if (!l_json_coins) { return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS } @@ -717,7 +946,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", dap_chain_addr_to_str(l_wallet_addr), a_net_name); DAP_DEL_Z(l_wallet_addr); - json_object *l_json_outs = request_command_to_rpc_by_curl(data); + json_object *l_json_outs = s_request_command_to_rpc(data); uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell); uint256_t l_value_sell = a_datoshi_sell; @@ -753,7 +982,7 @@ json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_n snprintf(data, sizeof(data), "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name); - json_object *l_json_outs = request_command_to_rpc_by_curl(data); + json_object *l_json_outs = s_request_command_to_rpc(data); if (!l_json_outs) { return NULL; } @@ -792,7 +1021,7 @@ json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_n } -static dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, +dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *a_native_ticker, const char *a_net_name) { if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) { @@ -934,16 +1163,6 @@ static dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net } } } - - // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); - // // add 'sign' item - // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) { - // dap_chain_datum_tx_delete(l_tx); - // dap_enc_key_delete(l_seller_key); - // printf("Can't add sign output\n"); - // return NULL; - // } - // dap_enc_key_delete(l_seller_key); return l_tx; } @@ -961,13 +1180,20 @@ int dap_tx_cond_create_compose(int argc, char ** argv) const char * l_srv_uid_str = NULL; uint256_t l_value_datoshi = {}; uint256_t l_value_fee = {}; - const char * l_hash_out_type = NULL; - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type); - if(!l_hash_out_type) - l_hash_out_type = "hex"; - if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) { - printf("Invalid parameter -H, valid values: -H <hex | base58>\n"); - return -1; + + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + arg_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif + } else { + arg_wallets_path = dap_strdup(l_wallet_path); } dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker); @@ -1038,7 +1264,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv) return -13; } - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path, NULL); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL); if(!l_wallet) { printf("Can't open wallet '%s'\n", l_wallet_str); return -15; @@ -1063,7 +1289,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv) uint256_t l_value_per_unit_max = {}; dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker, l_value_datoshi, l_value_per_unit_max, l_price_unit, - l_srv_uid, l_value_fee, NULL, 0, l_hash_out_type); + l_srv_uid, l_value_fee, NULL, 0); json_object * l_json_obj_ret = json_object_new_object(); dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); @@ -1083,7 +1309,7 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net uint256_t a_value, uint256_t a_value_per_unit_max, dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, uint256_t a_value_fee, const void *a_cond, - size_t a_cond_size, const char *a_hash_out_type) + size_t a_cond_size) { // check valid param if (!a_net_name || !a_key_from || !a_key_cond || @@ -1114,17 +1340,10 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count)) { return NULL; } - dap_list_t *l_list_used_out = NULL; - l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, l_value_need, &l_value_transfer); json_object_put(l_outs); - - - // dap_list_t *l_list_used_out = NULL; - // if (dap_chain_wallet_cache_tx_find_outs_with_val(l_ledger->net, a_token_ticker, &l_addr_from, &l_list_used_out, l_value_need, &l_value_transfer) == -101) - // l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_token_ticker, - // &l_addr_from, l_value_need, &l_value_transfer); if(!l_list_used_out) { printf("Nothing to transfer (not enough funds)\n"); return NULL; @@ -1179,19 +1398,6 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net } } - // // add 'sign' items - // if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) { - // dap_chain_datum_tx_delete(l_tx); - // printf("Can't add sign output\n"); - // return NULL; - // } - // size_t l_tx_size = dap_chain_datum_tx_get_size( l_tx ); - // dap_chain_datum_t *l_datum = dap_chain_datum_create( DAP_CHAIN_DATUM_TX, l_tx, l_tx_size ); - // dap_chain_datum_tx_delete(l_tx); - // dap_chain_t *l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX); - // char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, a_hash_out_type); - // DAP_DELETE(l_datum); - return l_tx; } @@ -1203,7 +1409,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL, *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL; - const char *l_wallets_path = c_wallets_path; + const char *l_wallets_path = arg_wallets_path; char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; dap_time_t l_time_staking = 0; uint256_t l_reinvest_percent = {}; @@ -1214,6 +1420,21 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) dap_chain_wallet_t *l_wallet; dap_chain_addr_t *l_addr_holder; + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + arg_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif + } else { + arg_wallets_path = dap_strdup(l_wallet_path); + } + const char *l_hash_out_type = NULL; dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); @@ -1237,7 +1458,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name); - json_object *l_json_coins = request_command_to_rpc_by_curl(data); + json_object *l_json_coins = s_request_command_to_rpc(data); if (!l_json_coins) { return -4; } @@ -1371,7 +1592,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) dap_chain_addr_to_str(l_addr_holder), l_net_name); DAP_DEL_Z(l_addr_holder); - json_object *l_json_outs = request_command_to_rpc_by_curl(data); + json_object *l_json_outs = s_request_command_to_rpc(data); uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str); json_object_put(l_json_outs); if (compare256(l_value_balance, l_value) == -1) { @@ -1558,17 +1779,6 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_nam } return l_tx; - // // add 'sign' item - // if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) { - // dap_chain_datum_tx_delete(l_tx); - // printf("Error: Can't add sign output\n"); - // return NULL; - // } - - // size_t l_tx_size = dap_chain_datum_tx_get_size( l_tx ); - // dap_chain_datum_t *l_datum = dap_chain_datum_create( DAP_CHAIN_DATUM_TX, l_tx, l_tx_size ); - - // return l_datum; } @@ -1587,6 +1797,21 @@ int dap_cli_take_compose(int a_argc, char **a_argv) dap_enc_key_t *l_owner_key; + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + arg_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif + } else { + arg_wallets_path = dap_strdup(l_wallet_path); + } + const char *l_hash_out_type = NULL; dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); if (!l_hash_out_type) @@ -1622,7 +1847,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv) "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_str, l_net_str); - json_object *response = request_command_to_rpc_by_curl(data); + json_object *response = s_request_command_to_rpc(data); if (!response) { printf("Error: Failed to get response from remote node\n"); return -15; @@ -1709,7 +1934,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv) return -15; } - if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path, NULL))) { + if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL))) { printf("Error: Unable to open wallet\n"); return -16; } @@ -1742,7 +1967,6 @@ int dap_cli_take_compose(int a_argc, char **a_argv) return 0; } - dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, const char *a_main_ticker, uint256_t a_value, @@ -1903,6 +2127,7 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_na return l_tx; } + uint256_t s_get_key_delegating_min_value(const char *a_net_str){ uint256_t l_key_delegating_min_value = uint256_0; char data[512]; @@ -1910,7 +2135,7 @@ uint256_t s_get_key_delegating_min_value(const char *a_net_str){ "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); - json_object *response = request_command_to_rpc_by_curl(data); + json_object *response = s_request_command_to_rpc(data); if (!response) { printf("Error: Failed to get response from remote node\n"); return l_key_delegating_min_value; @@ -1960,6 +2185,22 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) const char* l_fee_str = NULL; const char* l_wallet_str = NULL; const char* l_net_str = NULL; + const char* l_token_str = NULL; + + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + arg_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif + } else { + arg_wallets_path = dap_strdup(l_wallet_path); + } dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); // Select chain network @@ -2025,13 +2266,34 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false; bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false; - dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, c_wallets_path,NULL); + dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL); if (!l_wallet_fee) { printf("Wallet %s does not exist\n", l_wallet_str); return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; } - dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net_str); + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str); + if (!l_token_str) { + printf("Command required -token argument"); + return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; + } + + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str); + json_object *l_json_coins = s_request_command_to_rpc(data); + if (!l_json_coins) { + printf("Error: Can't get ledger coins list\n"); + return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; + } + if (!check_token_in_ledger(l_json_coins, l_token_str)) { + json_object_put(l_json_coins); + printf("Token %s does not exist\n", l_token_str); + return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN; + } + json_object_put(l_json_coins); + + dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net_str, l_token_str); dap_list_free(l_options_list); dap_chain_wallet_close(l_wallet_fee); json_object * l_json_obj_ret = json_object_new_object(); @@ -2045,7 +2307,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, - const char *a_net_str) { + const char *a_net_str, const char *a_token_ticker) { if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ return NULL; @@ -2169,6 +2431,15 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item); DAP_DEL_Z(l_vote_changing_item); } + if (a_token_ticker) { + dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker); + if (!l_voting_token_item) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item); + DAP_DEL_Z(l_voting_token_item); + } // add 'in' items uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); @@ -2207,3 +2478,1367 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, return l_tx; } +/** +int dap_cli_vote_compose(int a_argc, char **a_argv){ + const char* l_cert_name = NULL; + const char* l_fee_str = NULL; + const char* l_wallet_str = NULL; + const char* l_hash_str = NULL; + const char* l_option_idx_str = NULL; + const char* l_net_str = NULL; + int arg_index = 1; + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); + if(!l_net_str) { + printf("command requires parameter '-net'\n"); + return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING; + } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hash", &l_hash_str); + if(!l_hash_str){ + printf("Command 'vote' require the parameter -hash\n"); + return -DAP_CHAIN_NET_VOTE_VOTING_HASH_NOT_FOUND; + } + + dap_hash_fast_t l_voting_hash = {}; + if (dap_chain_hash_fast_from_str(l_hash_str, &l_voting_hash)) { + printf("Hash string is not recognozed as hex of base58 hash\n"); + return -DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID; + } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_name); + dap_cert_t * l_cert = dap_cert_find_by_name(l_cert_name); + if (l_cert_name){ + if (l_cert == NULL) { + printf("Can't find \"%s\" certificate\n", l_cert_name); + return -DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_FIND_CERT; + } + } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str); + if (!l_fee_str){ + printf("Command 'vote' requires paramete -fee to be valid.\n"); + return -DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_NOT_VALID; + } + uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str); + if (IS_ZERO_256(l_value_fee)) { + printf("command requires parameter '-fee' to be valid uint256\n"); + return -DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_BAD_TYPE; + } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str); + if (!l_wallet_str){ + printf("Command 'vote' requires parameter -w to be valid.\n"); + return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_PARAM_NOT_VALID; + } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-option_idx", &l_option_idx_str); + if (!l_option_idx_str){ + printf("Command 'vote' requires parameter -option_idx to be valid.\n"); + return -DAP_CHAIN_NET_VOTE_VOTING_OPTION_IDX_PARAM_NOT_VALID; + } + + const char *arg_wallets_path = dap_chain_wallet_get_path(g_config); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path,NULL); + if (!l_wallet) { + printf("Wallet %s does not exist\n", l_wallet_str); + return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST; + } + + uint64_t l_option_idx_count = strtoul(l_option_idx_str, NULL, 10); + + char *l_hash_tx; + + int res = dap_chain_net_vote_voting_compose(l_cert, l_value_fee, l_wallet, l_voting_hash, l_option_idx_count, + l_net_str, &l_hash_tx); + dap_chain_wallet_close(l_wallet); + + return res; +} + + +int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wallet_t *a_wallet, dap_hash_fast_t a_hash, + uint64_t a_option_idx, const char *a_net_str, const char *a_hash_out_type, + char **a_hash_tx_out) { + const char * l_hash_str = dap_chain_hash_fast_to_str_static(&a_hash); + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"voting\",\"params\": [\"voting;dump;-hash;%s\"],\"id\": \"2\"}", l_hash_str); + json_object *l_json_voting = s_request_command_to_rpc(data); + if (!l_json_voting) { + printf("Error: Can't get voting info\n"); + return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; + } + + + json_object *l_voting_info = json_object_array_get_idx(l_json_voting, 0); + if (!l_voting_info) { + printf("Error: Can't get voting info from JSON\n"); + return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; + } + + const char *l_voting_tx = json_object_get_string(json_object_object_get(l_voting_info, "voting_tx")); + const char *l_expiration_str = json_object_get_string(json_object_object_get(l_voting_info, "expiration")); + const char *l_status = json_object_get_string(json_object_object_get(l_voting_info, "status")); + int l_votes_max = json_object_get_int(json_object_object_get(l_voting_info, "votes_max")); + int l_votes_available = json_object_get_int(json_object_object_get(l_voting_info, "votes_available")); + bool l_vote_changed = json_object_get_boolean(json_object_object_get(l_voting_info, "can_change_status")); + bool l_delegated_key_required = json_object_get_boolean(json_object_object_get(l_voting_info, "delegated_key_required")); + + json_object *l_results = json_object_object_get(l_voting_info, "results"); + if (!l_results) { + printf("Error: Can't get results from JSON\n"); + return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; + } + + int l_results_count = json_object_array_length(l_results); + + + if (l_votes_max && l_votes_max <= l_results_count) + return DAP_CHAIN_NET_VOTE_VOTING_THIS_VOTING_HAVE_MAX_VALUE_VOTES; + + if (l_expiration_str) { + struct tm tm; + strptime(l_expiration_str, "%a, %d %b %Y %H:%M:%S %z", &tm); + time_t l_expiration_time = mktime(&tm); + if (l_expiration_time && dap_time_now() > l_expiration_time) + return DAP_CHAIN_NET_VOTE_VOTING_ALREADY_EXPIRED; + } + + dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str)); + if (!l_addr_from) + return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID; + + dap_hash_fast_t l_pkey_hash = {0}; + if (l_delegated_key_required) { + if (!a_cert) + return DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED; + if (dap_cert_get_pkey_hash(a_cert, &l_pkey_hash)) + return DAP_CHAIN_NET_VOTE_VOTING_NO_KEY_FOUND_IN_CERT; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); + json_object *l_json_coins = s_request_command_to_rpc(data); + if (!l_json_coins) { + printf("Error: Failed to retrieve coins from ledger\n"); + return -4; + } + const char * l_hash_fast_str[DAP_HASH_FAST_STR_SIZE] = {}; + dap_chain_hash_fast_from_str(l_hash_fast_str, &l_pkey_hash); + if (!l_hash_fast_str) { + printf("Error: Can't covert l_pkey_hash to str"); + return -5; + } + int items_count = json_object_array_length(l_json_coins); + bool found = false; + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(l_json_coins, i); + const char *pkey_hash_str = json_object_get_string(json_object_object_get(item, "pkey_hash")); + if (l_hash_fast_str && !dap_strcmp(l_hash_fast_str, pkey_hash_str)) { + const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash")); + if (dap_chain_hash_fast_from_str(tx_hash_str, &l_pkey_hash)) { + printf("Invalid transaction hash format\n"); + return DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED; + } + found = true; + break; + } + } + if (!found) { + printf("Specified certificate/pkey hash is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n"); + return -9; + } + + + } else + l_pkey_hash = l_addr_from->data.hash_fast; + + + const char *l_token_ticker = json_object_get_string(json_object_object_get(l_voting_info, "token")); + uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer; + dap_chain_addr_t* l_addr_fee = NULL; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee); + if (l_net_fee_used) + SUM_256_256(l_net_fee, a_fee, &l_total_fee); + + bool l_native_tx = !dap_strcmp(l_token_ticker, s_get_native_ticker(a_net_str)); + + json_object *l_outs = NULL; + int l_outputs_count = 0; + if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_token_ticker, a_net_str, &l_outs, &l_outputs_count)) { + return -11; + } + + dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_total_fee, + &l_value_transfer); + json_object_put(l_outs); + if (!l_list_used_out) { + printf("Not enough funds to transfer"); + return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER; + } + + // check outputs UTXOs + uint256_t l_value_transfer_new = {}; + dap_list_t *it, *tmp; + DL_FOREACH_SAFE(l_list_used_out, it, tmp) { + dap_chain_tx_used_out_item_t *l_out = (dap_chain_tx_used_out_item_t *)it->data; + if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out, + l_vote_changed ? &l_pkey_hash : NULL)) { + l_list_used_out = dap_list_delete_link(l_list_used_out, it); + continue; + } + if (SUM_256_256(l_value_transfer_new, l_out->value, &l_value_transfer_new)) + return DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW; + } + + if (IS_ZERO_256(l_value_transfer_new) || (l_native_tx && compare256(l_value_transfer_new, l_total_fee) <= 0)) + return DAP_CHAIN_NET_VOTE_VOTING_UNSPENT_UTX0_FOR_PARTICIPATION_THIS_VOTING; + + l_value_transfer = l_value_transfer_new; + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + + uint256_t l_value_back = l_value_transfer, l_fee_back = {}; + if (!l_native_tx) { + dap_list_t *l_list_fee_outs = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_net->pub.native_ticker, l_addr_from, l_total_fee, &l_fee_transfer); + if (!l_list_fee_outs) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER; + } + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_outs); + assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); + dap_list_free_full(l_list_fee_outs, NULL); + SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_back); + } else + SUBTRACT_256_256(l_value_transfer, l_total_fee, &l_value_back); + + // add 'in' items + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + + // Add vote item + if (a_option_idx > dap_list_length(l_voting->voting_params.option_offsets_list)){ + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_INVALID_OPTION_INDEX; + } + dap_chain_tx_vote_t* l_vote_item = dap_chain_datum_tx_item_vote_create(&a_hash, &a_option_idx); + if(!l_vote_item){ + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_VOTE_ITEM; + } + dap_chain_datum_tx_add_item(&l_tx, l_vote_item); + DAP_DEL_Z(l_vote_item); + + // add out conds items + dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from); + for (dap_list_t *it = l_outs; it; it = it->next) { + dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data; + if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out, + l_vote_changed ? &l_pkey_hash : NULL) != 0) + continue; + dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out); + if(!l_item){ + dap_chain_datum_tx_delete(l_tx); + + dap_list_free_full(l_outs, NULL); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_TSD_TX_COND_ITEM; + } + dap_chain_datum_tx_add_item(&l_tx, l_item); + DAP_DEL_Z(l_item); + } + dap_list_free_full(l_outs, NULL); + + // Network fee + if (l_net_fee_used && dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, a_net->pub.native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; + } + + // Validator's fee + if (!IS_ZERO_256(a_fee) && dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; + } + + // coin back + if (!IS_ZERO_256(l_value_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_token_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; + } + if (!IS_ZERO_256(l_fee_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_fee_back, a_net->pub.native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; + } + + dap_enc_key_t *l_priv_key = dap_chain_wallet_get_key(a_wallet, 0); + // add 'sign' items with wallet sign + if (dap_chain_datum_tx_add_sign_item(&l_tx, l_priv_key) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_enc_key_delete(l_priv_key); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX; + } + dap_enc_key_delete(l_priv_key); + + // add 'sign' items with delegated key if needed + if (a_cert && dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX; + } + + size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx); + dap_hash_fast_t l_tx_hash; + dap_hash_fast(l_tx, l_tx_size, &l_tx_hash); + dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, l_tx_size); + DAP_DELETE(l_tx); + dap_chain_t* l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX); + + char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, a_hash_out_type); + DAP_DELETE(l_datum); + if (l_ret) { + *a_hash_tx_out = l_ret; + return DAP_CHAIN_NET_VOTE_VOTING_OK; + } else { + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_POOL_IN_MEMPOOL; + } +} + +*/ + + +/** +static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) +{ + const char *l_net_str = NULL, + *l_wallet_str = NULL, + *l_cert_str = NULL, + *l_fee_str = NULL, + *l_tx_hash_str = NULL, + *l_poa_cert_str = NULL, + *l_signing_pkey_hash_str = NULL, + *l_signing_pkey_type_str = NULL; + int l_arg_index = 1; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); + if (!l_net_str) { + printf("Command 'invalidate' requires parameter -net\n"); + return -1; + } + + uint256_t l_fee = {}; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); + if (!l_wallet_str) { + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-poa_cert", &l_poa_cert_str); + if (!l_poa_cert_str) { + printf("Command 'invalidate' requires parameter -w or -poa_cert\n"); + return -1; + } + } else { + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); + if (!l_fee_str) { + printf("Command 'delegate' requires parameter -fee\n"); + return -1; + } + l_fee = dap_chain_balance_scan(l_fee_str); + if (IS_ZERO_256(l_fee)) { + printf("Unrecognized number in '-fee' param\n"); + return -1; + } + } + + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tx", &l_tx_hash_str); + if (!l_tx_hash_str) { + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str); + if (!l_cert_str) { + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-signing_pkey_hash", &l_signing_pkey_hash_str); + if (!l_signing_pkey_hash_str) { + printf("Command 'invalidate' requires parameter -tx or -cert or -signing_pkey_hash\n"); + return -1; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-signing_pkey_type", &l_signing_pkey_type_str); + if (!l_signing_pkey_type_str) { + printf("Command 'invalidate' requires parameter -signing_pkey_type\n"); + return -1; + } + if (dap_sign_type_from_str(l_signing_pkey_type_str).type == SIG_TYPE_NULL) { + printf("Invalid signing_pkey_type %s\n", l_signing_pkey_type_str); + return -3; + } + } + } + + dap_hash_fast_t l_tx_hash = {}; + if (l_tx_hash_str) { + dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash); + } else { + dap_chain_addr_t l_signing_addr; + if (l_cert_str) { + dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str); + if (!l_cert) { + printf("Specified certificate not found\n"); + return -4; + } + if (!l_cert->enc_key->priv_key_data || l_cert->enc_key->priv_key_data_size == 0) { + printf("It is not possible to invalidate a stake using a public key.\n"); + return -5; + } + if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, s_get_net_id(l_net_str))) { + printf("Specified certificate is wrong\n"); + return -6; + } + } else { + dap_hash_fast_t l_pkey_hash = {}; + if (dap_chain_hash_fast_from_str(l_signing_pkey_hash_str, &l_pkey_hash)) { + printf("Invalid pkey hash format\n"); + return -7; + } + dap_chain_addr_fill(&l_signing_addr, dap_sign_type_from_str(l_signing_pkey_type_str), &l_pkey_hash, s_get_net_id(l_net_str)); + } + + + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", l_net_str); + json_object *l_json_coins = s_request_command_to_rpc(data); + if (!l_json_coins) { + printf("Error: Failed to retrieve coins from ledger\n"); + return -4; + } + + int items_count = json_object_array_length(l_json_coins); + bool found = false; + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(l_json_coins, i); + const char *pkey_hash_str = json_object_get_string(json_object_object_get(item, "pkey_hash")); + if (l_signing_pkey_hash_str && !dap_strcmp(l_signing_pkey_hash_str, pkey_hash_str)) { + const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash")); + if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) { + printf("Invalid transaction hash format\n"); + return -8; + } + found = true; + break; + } + } + if (!found) { + printf("Specified certificate/pkey hash is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n"); + return -9; + } + } + + const char *l_tx_hash_str_tmp = l_tx_hash_str ? l_tx_hash_str : dap_hash_fast_to_str_static(&l_tx_hash); + + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str); + json_object *l_json_response = s_request_command_to_rpc(data); + if (!l_json_response) { + printf("Error: Failed to retrieve transaction info from ledger\n"); + return -4; + } + + json_object *l_json_items = json_object_object_get(l_json_response, "ITEMS"); + bool has_delegate_out = false; + if (l_json_items) { + int items_count = json_object_array_length(l_json_items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(l_json_items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (item_type && strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (subtype && strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE") == 0) { + has_delegate_out = true; + break; + } + } + } + } + + if (!has_delegate_out) { + printf("Transaction %s does not have a delegate out\n", l_tx_hash_str_tmp); + return -11; + } + + json_object *l_json_spents = json_object_object_get(l_json_response, "Spent OUTs"); + if (l_json_spents) { + int spents_count = json_object_array_length(l_json_spents); + for (int i = 0; i < spents_count; i++) { + json_object *spent_item = json_object_array_get_idx(l_json_spents, i); + const char *spent_by_tx = json_object_get_string(json_object_object_get(spent_item, "is spent by tx")); + if (spent_by_tx) { + if (dap_chain_hash_fast_from_str(spent_by_tx, &l_tx_hash)) { + printf("Invalid transaction hash format in response\n"); + return -8; + } + l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash); + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str); + json_object *l_json_prev_tx = s_request_command_to_rpc(data); + if (!l_json_prev_tx) { + printf("Previous transaction %s is not found\n", l_tx_hash_str_tmp); + return -12; + } + break; + } + } + } + + if (l_tx_hash_str) { + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", l_net_str); + json_object *l_json_coins = s_request_command_to_rpc(data); + if (!l_json_coins) { + printf("Error: Failed to retrieve coins from ledger\n"); + return -4; + } + + bool tx_exists = false; + int tx_count = json_object_array_length(l_json_coins); + for (int i = 0; i < tx_count; i++) { + json_object *tx_item = json_object_array_get_idx(l_json_items, i); + const char *tx_hash = json_object_get_string(json_object_object_get(tx_item, "tx_hash")); + if (tx_hash && strcmp(tx_hash, l_tx_hash_str_tmp) == 0) { + printf("Error: Transaction %s already exists in the ledger\n", l_tx_hash_str_tmp); + return -13; + } + } + } + dap_chain_datum_tx_t *l_tx = NULL; + if (l_wallet_str) { + const char* l_sign_str = ""; + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config),NULL); + if (!l_wallet) { + printf("Specified wallet not found\n"); + return -14; + } else { + l_sign_str = dap_chain_wallet_check_sign(l_wallet); + } + dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); + l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key); + dap_chain_wallet_close(l_wallet); + dap_enc_key_delete(l_enc_key); + } else { + dap_cert_t *l_poa_cert = dap_cert_find_by_name(l_poa_cert_str); + if (!l_poa_cert) { + printf("Specified certificate not found\n"); + return -4; + } + if (!s_srv_stake_is_poa_cert(l_net, l_poa_cert->enc_key)) { + printf("Specified certificate is not PoA root one\n"); + return -16; + } + dap_chain_datum_decree_t *l_decree = s_stake_decree_invalidate(l_net, &l_tx_hash, l_poa_cert); + char *l_decree_hash_str = NULL; + if (l_decree && (l_decree_hash_str = s_stake_decree_put(l_decree, l_net))) { + json_object* l_json_object_invalidate = json_object_new_object(); + json_object_object_add(l_json_object_invalidate, "status", json_object_new_string("success")); + json_object_object_add(l_json_object_invalidate, "decree", json_object_new_string(l_decree_hash_str)); + json_object_object_add(l_json_object_invalidate, "message", json_object_new_string("Specified delegated key invalidated. Try to execute this command with -w to return m-tokens to owner")); + json_object_array_add(*a_json_arr_reply, l_json_object_invalidate); + DAP_DELETE(l_decree); + DAP_DELETE(l_decree_hash_str); + } else { + char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; + dap_chain_hash_fast_to_str(&l_tx, l_tx_hash_str, sizeof(l_tx_hash_str)); + printf("Can't invalidate transaction %s, examine log files for details\n", l_tx_hash_str); + DAP_DEL_Z(l_decree); + return -15; + } + } + return 0; +} + +dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key) +{ + + + dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash); + if (!l_cond_tx) { + printf("Requested conditional transaction not found\n"); + return NULL; + } + int l_prev_cond_idx = 0; + dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, + DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_prev_cond_idx); + if (!l_tx_out_cond) { + printf("Requested conditional transaction requires conditional output\n"); + return NULL; + } + dap_hash_fast_t l_spender_hash = { }; + if (dap_ledger_tx_hash_is_used_out_item(l_ledger, a_tx_hash, l_prev_cond_idx, &l_spender_hash)) { + char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; + dap_chain_hash_fast_to_str(&l_spender_hash, l_hash_str, sizeof(l_hash_str)); + printf("Requested conditional transaction is already used out by %s\n", l_hash_str); + return NULL; + } + dap_chain_tx_in_cond_t *l_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(l_cond_tx, NULL, NULL, TX_ITEM_TYPE_IN_COND, NULL); + if (l_in_cond) { + l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, &l_in_cond->header.tx_prev_hash); + if (!l_cond_tx) { + printf("Requested conditional transaction is unchained\n"); + return NULL; + } + } + // Get sign item + dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(l_cond_tx, NULL, NULL, + TX_ITEM_TYPE_SIG, NULL); + // Get sign from sign item + // TODO Can't get sign from sign item required new command for remote node + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); + dap_chain_addr_t l_owner_addr; + dap_chain_addr_fill_from_sign(&l_owner_addr, l_sign, s_get_net_id(a_net_str)); + dap_chain_addr_t l_wallet_addr; + dap_chain_addr_fill_from_key(&l_wallet_addr, a_key, s_get_net_id(a_net_str)); + if (!dap_chain_addr_compare(&l_owner_addr, &l_wallet_addr)) { + printf("Trying to invalidate delegating tx with not a owner wallet\n"); + return NULL; + } + const char *l_native_ticker = s_get_native_ticker(a_net_str); + const char *l_delegated_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, a_tx_hash); + uint256_t l_fee_transfer = {}; // how many coins to transfer + // list of transaction with 'out' items to sell + uint256_t l_net_fee, l_fee_total = a_fee; + dap_chain_addr_t l_net_fee_addr; + bool l_net_fee_used = dap_chain_net_tx_get_fee(a_net->pub.id, &l_net_fee, &l_net_fee_addr); + if (l_net_fee_used) + SUM_256_256(l_fee_total, l_net_fee, &l_fee_total); + dap_list_t *l_list_fee_out = NULL; + if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101) + l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, + &l_owner_addr, l_fee_total, &l_fee_transfer); + if (!l_list_fee_out) { + printf("Nothing to pay for fee (not enough funds)\n"); + return NULL; + } + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + + // add 'in' item to buy from conditional transaction + dap_chain_datum_tx_add_in_cond_item(&l_tx, a_tx_hash, l_prev_cond_idx, 0); + + // add 'in' items to pay fee + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + dap_list_free_full(l_list_fee_out, NULL); + if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { + printf("Can't compose the transaction input\n"); + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + + // add 'out_ext' item + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_tx_out_cond->header.value, l_delegated_ticker) == -1) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add returning coins output\n"); + return NULL; + } + // add fee items + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + if (!IS_ZERO_256(a_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // fee coin back + uint256_t l_fee_back = {}; + SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back); + if(!IS_ZERO_256(l_fee_back)) { + if(dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // add 'sign' items + if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Can't add sign output\n"); + return NULL; + } + return l_tx; +} +*/ + +// dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){ +// dap_chain_net_srv_order_t* l_order = NULL; +// json_object *orders_array = json_object_array_get_idx(response, 0); +// size_t orders_count = json_object_array_length(orders_array); +// for (size_t i = 0; i < orders_count; i++) { +// json_object *order_obj = json_object_array_get_idx(orders_array, i); +// const char *order_hash_str = json_object_get_string(json_object_object_get(order_obj, "order")); + +// if (strcmp(order_hash_str, l_order_hash_str) == 0) { +// l_order = DAP_NEW_Z_SIZE(dap_chain_net_srv_order_t, sizeof(dap_chain_net_srv_order_t)); +// l_order->version = json_object_get_int(json_object_object_get(order_obj, "version")); +// l_order->direction = dap_chain_net_srv_order_direction_from_str(json_object_get_string(json_object_object_get(order_obj, "direction"))); +// l_order->ts_created = dap_time_from_str(json_object_get_string(json_object_object_get(order_obj, "created"))); +// l_order->srv_uid.uint64 = dap_chain_net_srv_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "srv_uid"))).uint64; +// l_order->price = dap_uint256_scan_uninteger(json_object_get_string(json_object_object_get(order_obj, "price datoshi"))); +// strncpy(l_order->price_ticker, json_object_get_string(json_object_object_get(order_obj, "price token")), DAP_CHAIN_TICKER_SIZE_MAX); +// l_order->units = json_object_get_int(json_object_object_get(order_obj, "units")); +// l_order->price_unit = dap_chain_net_srv_price_unit_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "price unit"))); +// dap_chain_node_addr_from_str(&l_order->node_addr, json_object_get_string(json_object_object_get(order_obj, "node_addr"))); +// dap_chain_hash_fast_from_str(&l_order->tx_cond_hash, json_object_get_string(json_object_object_get(order_obj, "tx_cond_hash"))); +// l_order->ext_size = json_object_get_int(json_object_object_get(order_obj, "ext_size")); +// if (l_order->ext_size > 0) { +// const char *tax_str = json_object_get_string(json_object_object_get(order_obj, "tax")); +// const char *value_max_str = json_object_get_string(json_object_object_get(order_obj, "maximum_value")); +// *a_tax = dap_uint256_scan_decimal(tax_str); +// *a_value_max = dap_uint256_scan_decimal(value_max_str); +// } + +// json_object *conditional_tx_params = json_object_object_get(order_obj, "conditional_tx_params"); +// if (conditional_tx_params) { +// const char *sovereign_tax_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_tax")); +// const char *sovereign_addr_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_addr")); +// *a_sovereign_tax = dap_uint256_scan_decimal(sovereign_tax_str); +// a_sovereign_addr = dap_chain_addr_from_str(sovereign_addr_str); +// } +// break; +// } +// } +// return l_order; +// } + +// dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax){ +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", +// l_net_str); +// json_object *response = s_request_command_to_rpc(data); +// if (!response) { +// printf("Error: Failed to get response from remote node\n"); +// return NULL; +// } + +// dap_chain_net_srv_order_t *l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response); +// json_object_put(response); + +// if (!l_order) { +// snprintf(data, sizeof(data), +// "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", +// l_net_str); +// response = s_request_command_to_rpc(data); +// if (!response) { +// printf("Error: Failed to get response from remote node\n"); +// return NULL; +// } +// l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response); +// json_object_put(response); +// } +// return l_order; +// } + + + + +// static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) +// { +// int l_arg_index = 0; +// const char *l_net_str = NULL, +// *l_wallet_str = NULL, +// *l_cert_str = NULL, +// *l_pkey_str = NULL, +// *l_pkey_full_str = NULL, +// *l_sign_type_str = NULL, +// *l_value_str = NULL, +// *l_fee_str = NULL, +// *l_node_addr_str = NULL, +// *l_order_hash_str = NULL; + +// dap_pkey_t *l_pkey = NULL; +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-net", &l_net_str); +// if (!l_net_str) { +// printf("Command 'delegate' requires parameter -net\n"); +// return -1; +// } + +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-w", &l_wallet_str); +// if (!l_wallet_str) { +// printf("Command 'delegate' requires parameter -w\n"); +// return -1; +// } +// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL); +// if (!l_wallet) { +// printf("Specified wallet not found\n"); +// return -2; +// } +// dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); +// dap_chain_wallet_close(l_wallet); +// dap_chain_addr_t l_signing_addr, l_sovereign_addr = {}; +// uint256_t l_sovereign_tax = uint256_0; +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-cert", &l_cert_str); +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str); +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-sign_type", &l_sign_type_str); +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-order", &l_order_hash_str); +// if (!l_cert_str && !l_order_hash_str && !l_pkey_full_str) { +// printf("Command 'delegate' requires parameter -cert and/or -order and/or -pkey\n"); +// dap_enc_key_delete(l_enc_key); +// return -1; +// } +// if (l_pkey_full_str) { +// printf("Command 'delegate' requires only one, -pkey or -pkey_full\n"); +// dap_enc_key_delete(l_enc_key); +// return -1; +// } +// if (( l_pkey_full_str) && !l_sign_type_str) { +// printf("Command 'delegate' requires parameter -sign_type for pkey\n"); +// dap_enc_key_delete(l_enc_key); +// return -1; +// } +// uint256_t l_value = uint256_0; +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-value", &l_value_str); +// if (!l_value_str) { +// if (!l_order_hash_str) { +// printf("Command 'delegate' requires parameter -value\n"); +// dap_enc_key_delete(l_enc_key); +// return -1; +// } +// } else { +// l_value = dap_chain_balance_scan(l_value_str); +// if (IS_ZERO_256(l_value)) { +// printf("Unrecognized number in '-value' param\n"); +// dap_enc_key_delete(l_enc_key); +// return -1; +// } +// } +// dap_chain_datum_tx_t *l_prev_tx = NULL; +// if (l_cert_str) { +// dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str); +// if (!l_signing_cert) { +// printf("Specified certificate not found\n"); +// dap_enc_key_delete(l_enc_key); +// return -3; +// } +// if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(l_net_str))) { +// printf("Specified certificate is wrong\n"); +// dap_enc_key_delete(l_enc_key); +// return -4; +// } +// l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key); +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str); +// } +// else if (l_pkey_full_str) { +// dap_sign_type_t l_type = dap_sign_type_from_str(l_sign_type_str); +// if (l_type.type == SIG_TYPE_NULL) { +// printf("Wrong sign type\n"); +// dap_enc_key_delete(l_enc_key); +// return -5; +// } +// l_pkey = dap_pkey_get_from_str(l_pkey_full_str); +// if (!l_pkey) { +// printf("Invalid pkey string format, can't get pkey_full\n"); +// dap_enc_key_delete(l_enc_key); +// return -6; +// } +// if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) { +// printf("pkey and sign types is different\n"); +// dap_enc_key_delete(l_enc_key); +// return -6; +// } +// dap_chain_hash_fast_t l_hash_public_key = {0}; +// if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) { +// printf("Invalid pkey hash format\n"); +// dap_enc_key_delete(l_enc_key); +// return -6; +// } +// dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(l_net_str)); +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str); +// } + +// dap_chain_node_addr_t l_node_addr = g_node_addr; +// if (l_node_addr_str) { +// if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) { +// printf("Unrecognized node addr %s\n", l_node_addr_str); +// dap_enc_key_delete(l_enc_key); +// return -7; +// } +// } +// if (l_order_hash_str) { + +// uint256_t l_tax; +// uint256_t l_value_max; +// int l_prev_tx_count = 0; +// dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax); + +// if (l_order->direction == SERV_DIR_BUY) { // Staker order +// if (!l_cert_str) { +// printf("Command 'delegate' requires parameter -cert with this order type\n"); +// dap_enc_key_delete(l_enc_key); +// return -1; +// } +// if (l_order->ext_size != 0) { +// printf("Specified order has invalid size\n"); +// dap_enc_key_delete(l_enc_key); +// DAP_DELETE(l_order); +// return -9; +// } + +// dap_chain_tx_out_cond_t *l_cond_tx = NULL; +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", +// l_order->tx_cond_hash, l_net_str); + +// json_object *response = s_request_command_to_rpc(data); +// if (!response) { +// printf("Error: Failed to get response from remote node\n"); +// return -15; +// } + +// json_object *items = json_object_object_get(response, "ITEMS"); +// if (!items) { +// printf("Error: No items found in response\n"); +// return -16; +// } +// int items_count = json_object_array_length(items); +// for (int i = 0; i < items_count; i++) { +// json_object *item = json_object_array_get_idx(items, i); +// const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); +// if (dap_strcmp(item_type, "OUT COND") == 0) { +// const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); +// if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE")) { +// l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); +// l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; +// l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); +// l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE; +// l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); +// l_cond_tx->header.ts_expires = dap_time_from_str(json_object_get_string(json_object_object_get(item, "ts_expires"))); +// l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr"))); +// if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) { +// printf("Error: Failed to parse signer node address\n"); +// return -17; +// } +// l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); +// l_prev_tx_count++; +// break; +// } +// } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) { +// l_prev_tx_count++; +// } +// } +// if (!l_cond_tx) { +// printf("Error: No transaction output condition found\n"); +// return -7; +// } + +// json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); +// const char *spent_outs_value = json_object_get_string(spent_outs); +// if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { +// printf("Error: Transaction output item already used\n"); +// return -9; +// } + + + +// // l_prev_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash); +// // if (!l_prev_tx) { +// // printf("The order's conditional transaction not found in ledger\n"); +// // dap_enc_key_delete(l_enc_key); +// // DAP_DELETE(l_order); +// // return -10; +// // } +// // int l_out_num = 0; +// // dap_chain_tx_out_cond_t *l_cond_tx = dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); +// // if (!l_cond) { +// // printf("The order's conditional transaction has invalid type\n"); +// // dap_enc_key_delete(l_enc_key); +// // DAP_DELETE(l_order); +// // return -11; +// // } +// // if (dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_order->tx_cond_hash, l_out_num, NULL)) { +// // printf("The order's conditional transaction is already spent\n"); +// // dap_enc_key_delete(l_enc_key); +// // DAP_DELETE(l_order); +// // return -12; +// // } + +// char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; +// dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(l_net_str)); +// const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker")); +// if (!l_token_ticker) { +// printf("Error: Token ticker not found in response\n"); +// return -18; +// } +// json_object_put(response); +// if (dap_strcmp(l_token_ticker, l_delegated_ticker)) { +// printf("Requested conditional transaction have another ticker (not %s)\n", l_delegated_ticker); +// return -13; +// } +// if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) { +// printf("The order's conditional transaction has invalid format\n"); +// dap_enc_key_delete(l_enc_key); +// DAP_DELETE(l_order); +// return -14; +// } +// if (compare256(l_cond_tx->header.value, l_order->price)) { +// printf("The order's conditional transaction has different value\n"); +// dap_enc_key_delete(l_enc_key); +// DAP_DELETE(l_order); +// return -15; +// } +// if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) || +// l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) { +// printf("The order's conditional transaction gas not blank address or key\n"); +// dap_enc_key_delete(l_enc_key); +// DAP_DELETE(l_order); +// return -16; +// } +// l_value = l_order->price; +// // dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR); +// // l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE); +// // l_sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t); +// // MULT_256_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); +// } +// /** TODO add new command to get l_pkey from order +// * else { +// if (!l_value_str) { +// printf("Command 'delegate' requires parameter -value with this order type\n"); +// dap_enc_key_delete(l_enc_key); +// return -1; +// } +// const char *l_sovereign_addr_str = NULL; +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str); +// if (l_sovereign_addr_str) { +// dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str); +// if (!l_spec_addr) { +// printf("Specified address is ivalid\n"); +// return -17; +// } +// l_sovereign_addr = *l_spec_addr; +// DAP_DELETE(l_spec_addr); +// } else +// dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, s_get_net_id(l_net_str)); + +// if (l_order_hash_str && compare256(l_value, l_order->price) == -1) { +// const char *l_coin_min_str, *l_value_min_str = +// dap_uint256_to_char(l_order->price, &l_coin_min_str); +// printf("Number in '-value' param %s is lower than order minimum allowed value %s(%s)\n", +// l_value_str, l_coin_min_str, l_value_min_str); +// dap_enc_key_delete(l_enc_key); +// return -18; +// } +// if (l_order_hash_str && compare256(l_value, l_value_max) == 1) { +// const char *l_coin_max_str, *l_value_max_str = +// dap_uint256_to_char(l_value_max, &l_coin_max_str); +// printf("Number in '-value' param %s is higher than order minimum allowed value %s(%s)\n", +// l_value_str, l_coin_max_str, l_value_max_str); +// dap_enc_key_delete(l_enc_key); +// return -19; +// } +// dap_sign_t *l_sign = (dap_sign_t *)(l_order->ext_n_sign + l_order->ext_size); +// if (l_sign->header.type.type == SIG_TYPE_NULL) { +// printf("Specified order is unsigned\n"); +// dap_enc_key_delete(l_enc_key); +// DAP_DELETE(l_order); +// return -20; +// } +// dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_net->pub.id); +// l_pkey = dap_pkey_get_from_sign(l_sign); +// char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX]; +// dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_net->pub.native_ticker); +// if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) { +// printf("Specified order is invalid\n"); +// dap_enc_key_delete(l_enc_key); +// DAP_DELETE(l_order); +// return -21; +// } +// l_node_addr = l_order->node_addr; +// } +// DAP_DELETE(l_order); +// if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 || +// compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) { +// printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n"); +// dap_enc_key_delete(l_enc_key); +// return -22; +// } +// DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); +// } +// */ +// if (!l_pkey) { +// printf("pkey not defined\n"); +// dap_enc_key_delete(l_enc_key); +// return -6; +// } + +// int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr); +// if (l_check_result) { +// printf("Key and node verification error\n"); +// dap_enc_key_delete(l_enc_key); +// return l_check_result; +// } + + +// uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str); +// if (compare256(l_value, l_allowed_min) == -1) { +// const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str); +// printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n", +// l_value_str, l_coin_min_str, l_value_min_str); +// dap_enc_key_delete(l_enc_key); +// return -23; +// } +// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-fee", &l_fee_str); +// if (!l_fee_str) { +// printf("Command 'delegate' requires parameter -fee\n"); +// dap_enc_key_delete(l_enc_key); +// return -1; +// } +// uint256_t l_fee = dap_chain_balance_scan(l_fee_str); +// if (IS_ZERO_256(l_fee)) { +// printf("Unrecognized number in '-fee' param\n"); +// dap_enc_key_delete(l_enc_key); +// return -1; +// } + +// // Create conditional transaction +// dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr, +// l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_prev_tx_count, l_pkey); +// dap_enc_key_delete(l_enc_key); +// DAP_DELETE(l_pkey); + +// DAP_DELETE(l_tx); + +// return 0; + +// } + +// // Freeze staker's funds when delegating a key +// dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc_key_t *a_key, +// uint256_t a_value, uint256_t a_fee, +// dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, +// dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, +// dap_chain_datum_tx_t *a_prev_tx, int l_prev_tx_count, dap_pkey_t *a_pkey) +// { +// dap_return_val_if_pass (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr, NULL); + +// const char *l_native_ticker = s_get_native_ticker(a_net_str); +// char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; +// dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker); +// uint256_t l_value_transfer = {}, l_fee_transfer = {}; // how many coins to transfer +// // list of transaction with 'out' items to sell +// dap_chain_addr_t l_owner_addr; +// dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str)); +// uint256_t l_net_fee, l_fee_total = a_fee; +// dap_chain_addr_t l_net_fee_addr; +// bool l_net_fee_used = get_remote_net_fee(a_net_str, l_native_ticker, &l_net_fee, &l_net_fee_addr); +// if (l_net_fee_used) +// SUM_256_256(l_fee_total, l_net_fee, &l_fee_total); + +// dap_list_t *l_list_fee_out = NULL; +// if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101) +// l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, +// &l_owner_addr, l_fee_total, &l_fee_transfer); +// if (!l_list_fee_out) { +// log_it(L_WARNING, "Nothing to pay for fee (not enough funds)"); +// return NULL; +// } + +// // create empty transaction +// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + +// if (!a_prev_tx) { +// dap_list_t *l_list_used_out = NULL ; +// if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_delegated_ticker, &l_owner_addr, &l_list_used_out, a_value, &l_value_transfer) == -101) +// l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_delegated_ticker, +// &l_owner_addr, a_value, &l_value_transfer); +// if (!l_list_used_out) { +// log_it(L_WARNING, "Nothing to pay for delegate (not enough funds)"); +// goto tx_fail; +// } +// // add 'in' items to pay for delegate +// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); +// dap_list_free_full(l_list_used_out, NULL); +// if (!EQUAL_256(l_value_to_items, l_value_transfer)) { +// log_it(L_ERROR, "Can't compose the transaction input"); +// goto tx_fail; +// } +// } else { +// dap_hash_fast_t l_prev_tx_hash; +// dap_hash_fast(a_prev_tx, dap_chain_datum_tx_get_size(a_prev_tx), &l_prev_tx_hash); +// int l_out_num = 0; +// dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); +// // add 'in' item to buy from conditional transaction +// if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_prev_tx_count, -1)) { +// log_it(L_ERROR, "Can't compose the transaction conditional input"); +// goto tx_fail; +// } +// } +// // add 'in' items to pay fee +// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); +// dap_list_free_full(l_list_fee_out, NULL); +// if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { +// log_it(L_ERROR, "Can't compose the fee transaction input"); +// goto tx_fail; +// } + +// // add 'out_cond' & 'out_ext' items +// dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID }; +// dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_value, a_signing_addr, a_node_addr, +// a_sovereign_addr, a_sovereign_tax, a_pkey); + +// if (!l_tx_out) { +// log_it(L_ERROR, "Can't compose the transaction conditional output"); +// goto tx_fail; +// } +// dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); +// DAP_DELETE(l_tx_out); +// if (!a_prev_tx) { +// // coin back +// uint256_t l_value_back = {}; +// SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back); +// if (!IS_ZERO_256(l_value_back)) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) { +// log_it(L_ERROR, "Cant add coin back output"); +// goto tx_fail; +// } +// } +// } + +// // add fee items +// if (l_net_fee_used) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { +// log_it(L_ERROR, "Cant add net fee output"); +// goto tx_fail; +// } +// } +// if (!IS_ZERO_256(a_fee)) { +// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { +// log_it(L_ERROR, "Cant add validator fee output"); +// goto tx_fail; +// } +// } +// uint256_t l_fee_back = {}; +// // fee coin back +// SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back); +// if (!IS_ZERO_256(l_fee_back)) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) { +// log_it(L_ERROR, "Cant add fee back output"); +// goto tx_fail; +// } +// } + +// // add 'sign' item +// if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) { +// log_it(L_ERROR, "Can't add sign output"); +// goto tx_fail; +// } + +// return l_tx; + +// tx_fail: +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } + + +// srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value> +// int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) { +// int arg_index = 1; +// const char * l_net_name = NULL; +// const char * l_wallet_name = NULL; +// const char * l_order_hash = NULL; +// const char * l_value = NULL; +// const char * l_fee = NULL; + +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); +// if (!l_net_name) { +// printf("tx_create requires parameter '-net'"); +// return -1; +// } + +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name); +// if (!l_wallet_name) { +// printf("Error: Command 'purchase' requires parameter -w\n"); +// return -1; +// } +// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, arg_wallets_path, NULL); +// if (!l_wallet) { +// printf("Error: Specified wallet not found\n"); +// return -2; +// } +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-order", &l_order_hash); +// if (!l_order_hash) { +// printf("Error: Command 'purchase' requires parameter -order\n"); +// return -3; +// } +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value); +// if (!l_value) { +// printf("Error: Command 'purchase' requires parameter -value\n"); +// return -4; +// } +// uint256_t l_datoshi_buy = dap_chain_balance_scan(l_value); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee); +// if (!l_fee) { +// printf("Error: Command 'purchase' requires parameter -fee\n"); +// return -5; +// } +// uint256_t l_datoshi_fee = dap_chain_balance_scan(l_fee); +// dap_hash_fast_t l_tx_hash = {}; +// dap_chain_hash_fast_from_str(l_order_hash, &l_tx_hash); +// char *l_str_ret_hash = NULL; +// int l_ret_code = dap_chain_net_srv_xchange_purchase_compose(l_net_name, &l_tx_hash, l_datoshi_buy, l_datoshi_fee, +// l_wallet, &l_str_ret_hash); +// switch (l_ret_code) { +// case XCHANGE_PURCHASE_ERROR_OK: { +// printf("Exchange transaction has done\n"); +// printf("hash: %s\n", l_str_ret_hash); +// DAP_DELETE(l_str_ret_hash); +// return 0; +// } +// case XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND: { +// printf("Error: Specified order not found\n"); +// return -6; +// } +// case XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE: { +// printf("Error: Can't create price from order\n"); +// return -7; +// } +// case XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX: { +// printf("Error: Exchange transaction error\n"); +// return -8; +// } +// default: { +// printf("Error: An error occurred with an unknown code: %d.\n", l_ret_code); +// return -9; +// } +// } +// return 0; +// } + + +// dap_chain_net_srv_xchange_purchase_error_t dap_chain_net_srv_xchange_purchase_compose(const char *a_net_name, dap_hash_fast_t *a_order_hash, uint256_t a_value, +// uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out){ +// if (!a_net_name || !a_order_hash || !a_wallet || !a_hash_out) { +// return XCHANGE_PURCHASE_ERROR_INVALID_ARGUMENT; +// } +// dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(a_net->pub.ledger, a_order_hash); +// if (l_cond_tx) { +// dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(a_net, l_cond_tx, a_order_hash, &a_fee, false); +// if(!l_price){ +// return XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE; +// } +// // Create conditional transaction +// char *l_ret = NULL; +// dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_exchange(l_price, a_wallet, a_value, a_fee); +// if (l_tx ) { +// l_ret = s_xchange_tx_put(l_tx, a_net); +// } +// DAP_DELETE(l_price); +// if (l_tx && l_ret){ +// *a_hash_out = l_ret; +// return XCHANGE_PURCHASE_ERROR_OK; +// } else +// return XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX; +// } else { +// return XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND; +// } +// } + + diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 5ff863f5da..12867d60e9 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -38,11 +38,9 @@ // #define RPC_NODES_URL "http://rpc.cellframe.net" #define RPC_NODES_URL "45.76.140.191:8081" - +#define MAX_RESPONSE_SIZE 4096 #define NET_COUNT 6 -const char *c_wallets_path = NULL; - typedef struct { char name[20]; char native_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; @@ -69,37 +67,34 @@ int dap_cli_hold_compose(int a_argc, char **a_argv); int dap_cli_take_compose(int a_argc, char **a_argv); int dap_cli_voting_compose(int a_argc, char **a_argv); +int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer); dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num); dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,const char *a_token_sell, uint256_t a_datoshi_sell, uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet); -static dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, +dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *a_native_ticker, const char *a_net_name); dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name, - dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], - uint256_t a_value, uint256_t a_value_per_unit_max, - dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, - uint256_t a_value_fee, const void *a_cond, - size_t a_cond_size, const char *a_hash_out_type); + dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, + const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], + uint256_t a_value, uint256_t a_value_per_unit_max, + dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, + uint256_t a_value_fee, const void *a_cond, + size_t a_cond_size); bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee); bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count); -dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, - const char *a_main_ticker, - uint256_t a_value, uint256_t a_value_fee, - dap_time_t a_time_staking, uint256_t a_reinvest_percent, +dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, const char *a_main_ticker, + uint256_t a_value, uint256_t a_value_fee, dap_time_t a_time_staking, uint256_t a_reinvest_percent, const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * l_chain_id_str); bool check_token_in_ledger(json_object *l_json_coins, const char *a_token); -dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, - dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, - const char *a_main_ticker, uint256_t a_value, - uint256_t a_value_fee, - const char *a_delegated_ticker_str, uint256_t a_delegated_value); +dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, + const char *a_main_ticker, uint256_t a_value, uint256_t a_value_fee, const char *a_delegated_ticker_str, uint256_t a_delegated_value); dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, - const char *a_net_str); + const char *a_net_str, const char *a_token_ticker); #ifdef __cplusplus } diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index 9081fe4bf1..60f5e6f244 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -51,7 +51,6 @@ typedef struct dap_chain_net_voting_params_offsets{ bool delegate_key_required; bool vote_changing_allowed; char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; - char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; } dap_chain_net_voting_params_offsets_t; typedef struct dap_chain_net_vote_option { @@ -574,7 +573,6 @@ static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledge return false; } - dap_chain_net_votings_t *l_voting = NULL; dap_chain_net_votings_t *l_voting = NULL; pthread_rwlock_wrlock(&s_votings_rwlock); HASH_FIND(hh, s_votings, &l_vote_tx_item->voting_hash, sizeof(dap_hash_fast_t), l_voting); @@ -1223,9 +1221,6 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f } -static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, - dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx, - dap_hash_fast_t *a_pkey_hash) static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_cond_hash, int a_cond_out_idx, dap_hash_fast_t *a_pkey_hash) diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h index 2f944a4324..9299ac5022 100644 --- a/modules/service/voting/include/dap_chain_net_srv_voting.h +++ b/modules/service/voting/include/dap_chain_net_srv_voting.h @@ -95,7 +95,6 @@ enum DAP_CHAIN_NET_VOTE_CREATE_ERROR { DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN, - DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_TOKEN, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN, DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_TOKEN, DAP_CHAIN_NET_VOTE_CREATE_UNKNOWN_ERR, DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS -- GitLab From 4842fe8707f23ccd2138f9592ff28015a9148945 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Thu, 27 Mar 2025 12:39:39 +0700 Subject: [PATCH 24/53] [*] fix http --- modules/compose/dap_chain_tx_compose.c | 319 +++++++++++------- .../compose/include/dap_chain_tx_compose.h | 20 +- 2 files changed, 210 insertions(+), 129 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index ce082f0782..a992519a56 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -39,7 +39,7 @@ #include <netdb.h> #include <json-c/json.h> -static json_object* s_request_command_to_rpc(const char *request); +static json_object* s_request_command_to_rpc(const char *a_request, const char * a_net_name); const char *arg_wallets_path = NULL; @@ -63,6 +63,24 @@ static dap_chain_net_id_t s_get_net_id(const char* name) { return empty_id; } +static const char* s_get_net_url(const char* name) { + for (int i = 0; i < NET_COUNT; i++) { + if (strcmp(netinfo[i].name, name) == 0) { + return netinfo[i].url; + } + } + return NULL; +} + +static uint16_t s_get_net_port(const char* name) { + for (int i = 0; i < NET_COUNT; i++) { + if (strcmp(netinfo[i].name, name) == 0) { + return netinfo[i].port; + } + } + return 0; +} + int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add) { json_object *items_array; @@ -74,127 +92,193 @@ int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add) { return 0; } +struct cmd_request { +#ifdef DAP_OS_WINDOWS + CONDITION_VARIABLE wait_cond; + CRITICAL_SECTION wait_crit_sec; +#else + pthread_cond_t wait_cond; + pthread_mutex_t wait_mutex; +#endif + char* response; + size_t response_size; + int error_code; +}; + +static struct cmd_request* s_cmd_request_init() +{ + struct cmd_request *l_cmd_request = DAP_NEW_Z(struct cmd_request); + if (!l_cmd_request) + return NULL; +#ifdef DAP_OS_WINDOWS + InitializeCriticalSection(&l_cmd_request->wait_crit_sec); + InitializeConditionVariable(&l_cmd_request->wait_cond); +#else + pthread_mutex_init(&l_cmd_request->wait_mutex, NULL); +#ifdef DAP_OS_DARWIN + pthread_cond_init(&l_cmd_request->wait_cond, NULL); +#else + pthread_condattr_t attr; + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + pthread_cond_init(&l_cmd_request->wait_cond, &attr); +#endif +#endif + return l_cmd_request; +} -static json_object* s_request_command_to_rpc(const char *request) { - struct addrinfo hints, *res = NULL, *p = NULL; - int sockfd = -1; - struct sockaddr_storage l_saddr = { }; - char l_ip[INET6_ADDRSTRLEN] = { '\0' }; - uint16_t l_port = 0; - char path[256] = "/"; - json_object *response_json = NULL; - dap_json_rpc_response_t* response = NULL; - - if (strchr(RPC_NODES_URL, ':') != NULL && strchr(RPC_NODES_URL, '/') == NULL) { - if (dap_net_parse_config_address(RPC_NODES_URL, l_ip, &l_port, &l_saddr, NULL) < 0) { - printf("Incorrect address \"%s\" format\n", RPC_NODES_URL); - return NULL; - } - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - - char port_str[6]; - snprintf(port_str, sizeof(port_str), "%u", l_port); - - if (getaddrinfo(l_ip, port_str, &hints, &res) != 0) { - fprintf(stderr, "Failed to resolve IP address\n"); - return NULL; - } - } else { - const char *host_start = strstr(RPC_NODES_URL, "://"); - if (!host_start) { - fprintf(stderr, "Invalid URL format\n"); - return NULL; - } - host_start += 3; // Move past "://" +void s_cmd_request_free(struct cmd_request *a_cmd_request) +{ + if (!a_cmd_request) + return; + +#ifdef DAP_OS_WINDOWS + DeleteCriticalSection(&a_cmd_request->wait_crit_sec); +#else + pthread_mutex_destroy(&a_cmd_request->wait_mutex); + pthread_cond_destroy(&a_cmd_request->wait_cond); +#endif + DAP_DEL_MULTY(a_cmd_request->response, a_cmd_request); +} - char host[256] = {0}; - const char *path_start = strchr(host_start, '/'); - size_t host_len = path_start ? (size_t)(path_start - host_start) : strlen(host_start); - if (host_len >= sizeof(host)) host_len = sizeof(host) - 1; - strncpy(host, host_start, host_len); - host[host_len] = '\0'; // Ensure null termination +static void s_cmd_response_handler(void *a_response, size_t a_response_size, void *a_arg, + http_status_code_t http_status_code) { + (void)http_status_code; + struct cmd_request *l_cmd_request = (struct cmd_request *)a_arg; +#ifdef DAP_OS_WINDOWS + EnterCriticalSection(&l_cmd_request->wait_crit_sec); +#else + pthread_mutex_lock(&l_cmd_request->wait_mutex); +#endif + l_cmd_request->response = DAP_DUP_SIZE(a_response, a_response_size); + l_cmd_request->response_size = a_response_size; +#ifdef DAP_OS_WINDOWS + WakeConditionVariable(&l_cmd_request->wait_cond); + LeaveCriticalSection(&l_cmd_request->wait_crit_sec); +#else + pthread_cond_signal(&l_cmd_request->wait_cond); + pthread_mutex_unlock(&l_cmd_request->wait_mutex); +#endif +} - printf("Extracted host: %s\n", host); // Debugging output +static void s_cmd_error_handler(int a_error_code, void *a_arg){ + struct cmd_request * l_cmd_request = (struct cmd_request *)a_arg; +#ifdef DAP_OS_WINDOWS + EnterCriticalSection(&l_cmd_request->wait_crit_sec); + l_cmd_request->response = NULL; + l_cmd_request->error_code = a_error_code; + WakeConditionVariable(&l_cmd_request->wait_cond); + LeaveCriticalSection(&l_cmd_request->wait_crit_sec); +#else + pthread_mutex_lock(&l_cmd_request->wait_mutex); + l_cmd_request->response = NULL; + l_cmd_request->error_code = a_error_code; + pthread_cond_signal(&l_cmd_request->wait_cond); + pthread_mutex_unlock(&l_cmd_request->wait_mutex); +#endif +} - struct addrinfo hints = {0}, *res = NULL; - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - if (getaddrinfo(host, "80", &hints, &res) != 0) { - fprintf(stderr, "Failed to resolve hostname: %s\n", host); - return NULL; +static int dap_chain_cmd_list_wait(struct cmd_request *a_cmd_request, int a_timeout_ms) { +#ifdef DAP_OS_WINDOWS + EnterCriticalSection(&a_cmd_request->wait_crit_sec); + if (a_cmd_request->response) + return LeaveCriticalSection(&a_cmd_request->wait_crit_sec), 0; + while (!a_cmd_request->response) { + if (!SleepConditionVariableCS(&a_cmd_request->wait_cond, &a_cmd_request->wait_crit_sec, a_timeout_ms)) { + a_cmd_request->error_code = GetLastError() == ERROR_TIMEOUT ? 1 : 2; + break; } } - - for (p = res; p != NULL; p = p->ai_next) { - sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if (sockfd == -1) continue; - - if (connect(sockfd, p->ai_addr, p->ai_addrlen) == 0) { + LeaveCriticalSection(&a_cmd_request->wait_crit_sec); + return a_cmd_request->error_code; +#else + pthread_mutex_lock(&a_cmd_request->wait_mutex); + if(a_cmd_request->response) { + pthread_mutex_unlock(&a_cmd_request->wait_mutex); + return 0; + } + + struct timespec l_cond_timeout; +#ifdef DAP_OS_DARWIN + l_cond_timeout.tv_sec = a_timeout_ms / 1000; + l_cond_timeout.tv_nsec = (a_timeout_ms % 1000) * 1000000; +#else + clock_gettime(CLOCK_MONOTONIC, &l_cond_timeout); + l_cond_timeout.tv_sec += a_timeout_ms / 1000; + l_cond_timeout.tv_nsec += (a_timeout_ms % 1000) * 1000000; + if (l_cond_timeout.tv_nsec >= 1000000000) { + l_cond_timeout.tv_sec += l_cond_timeout.tv_nsec / 1000000000; + l_cond_timeout.tv_nsec %= 1000000000; + } +#endif + + int ret = 0; + while (!a_cmd_request->response) { + int cond_ret; +#ifdef DAP_OS_DARWIN + cond_ret = pthread_cond_timedwait_relative_np(&a_cmd_request->wait_cond, + &a_cmd_request->wait_mutex, &l_cond_timeout); +#else + cond_ret = pthread_cond_timedwait(&a_cmd_request->wait_cond, + &a_cmd_request->wait_mutex, &l_cond_timeout); +#endif + if (cond_ret == ETIMEDOUT) { + a_cmd_request->error_code = 1; + ret = 1; + break; + } else if (cond_ret != 0) { + a_cmd_request->error_code = 2; + ret = 2; break; } - - close(sockfd); - sockfd = -1; - } - - freeaddrinfo(res); - - if (sockfd == -1) { - fprintf(stderr, "Failed to connect to host\n"); - return NULL; } + pthread_mutex_unlock(&a_cmd_request->wait_mutex); + return ret; +#endif +} - char http_request[1024]; - snprintf(http_request, sizeof(http_request), - "POST %s HTTP/1.1\r\n" - "Host: %s\r\n" - "Content-Type: application/json\r\n" - "Content-Length: %zu\r\n" - "Connection: close\r\n\r\n" - "%s", - path, l_ip, strlen(request), request); +static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_object **a_response_out, size_t *a_response_out_size) +{ + int ret = 0; - if (send(sockfd, http_request, strlen(http_request), 0) < 0) { - fprintf(stderr, "Failed to send request\n"); - close(sockfd); - return NULL; + if (a_cmd_request->error_code) { + ret = - 1; + } else if (a_cmd_request->response) { + *a_response_out = json_tokener_parse(a_cmd_request->response); + *a_response_out_size = a_cmd_request->response_size; + } else { + ret = -2; } - dap_app_cli_cmd_state_t cmd = { - .cmd_res = DAP_NEW_Z_SIZE(char, MAX_RESPONSE_SIZE), - .cmd_res_cur = 0, - .hdr_len = 0 // Ensure this is initialized - }; + return ret; +} - if (!cmd.cmd_res) { - fprintf(stderr, "Memory allocation failed\n"); - close(sockfd); - return NULL; - } +static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name) { + json_object * l_response = NULL; + size_t l_response_size; + struct cmd_request* l_cmd_request = s_cmd_request_init(); - int l_status = 1; - while (l_status > 0) { - l_status = dap_app_cli_http_read(sockfd, &cmd, l_status); - } - - close(sockfd); + dap_client_http_request(dap_worker_get_auto(), + s_get_net_url(a_net_name), + s_get_net_port(a_net_name), + "POST", "application/json", + NULL, request, strlen(request), NULL, + s_cmd_response_handler, s_cmd_error_handler, + l_cmd_request, NULL); - response = dap_json_rpc_response_from_string(cmd.cmd_res + cmd.hdr_len); - DAP_DELETE(cmd.cmd_res); + int l_ret = dap_chain_cmd_list_wait(l_cmd_request, 15000); - if (!response) { - return NULL; + if (!l_ret){ + if (s_cmd_request_get_response(l_cmd_request, &l_response, &l_response_size)) { + printf( "Response error code: %d", l_cmd_request->error_code); + } } - - response_json = response->result_json_object; - json_object_get(response_json); // Prevent early free - + json_object * l_result; + json_object_object_get_ex(l_response, "result", &l_result); json_object *errors_array; - if (json_object_is_type(response_json, json_type_array) && json_object_array_length(response_json) > 0) { - json_object *first_element = json_object_array_get_idx(response_json, 0); + if (json_object_is_type(l_result, json_type_array) && json_object_array_length(l_result) > 0) { + json_object *first_element = json_object_array_get_idx(l_result, 0); if (json_object_object_get_ex(first_element, "errors", &errors_array)) { int errors_len = json_object_array_length(errors_array); for (int j = 0; j < errors_len; j++) { @@ -205,20 +289,21 @@ static json_object* s_request_command_to_rpc(const char *request) { printf("Error %d: %s\n", json_object_get_int(error_code), json_object_get_string(error_message)); } } - json_object_put(response_json); // Free memory - response_json = NULL; + json_object_put(l_result); + l_result = NULL; } } - - dap_json_rpc_response_free(response); - return response_json; + s_cmd_request_free(l_cmd_request); + json_object_get(l_result); + json_object_put(l_response); + return l_result; } bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee) { char data[512]; snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name); - json_object *l_json_get_fee = s_request_command_to_rpc(data); + json_object *l_json_get_fee = s_request_command_to_rpc(data, l_net_name); if (!l_json_get_fee) { return false; } @@ -268,7 +353,7 @@ bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const c snprintf(data, sizeof(data), "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name); - json_object *l_json_outs = s_request_command_to_rpc(data); + json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name); if (!l_json_outs) { return false; } @@ -932,7 +1017,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name); - json_object *l_json_coins = s_request_command_to_rpc(data); + json_object *l_json_coins = s_request_command_to_rpc(data, a_net_name); if (!l_json_coins) { return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS } @@ -946,7 +1031,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", dap_chain_addr_to_str(l_wallet_addr), a_net_name); DAP_DEL_Z(l_wallet_addr); - json_object *l_json_outs = s_request_command_to_rpc(data); + json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name); uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell); uint256_t l_value_sell = a_datoshi_sell; @@ -982,7 +1067,7 @@ json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_n snprintf(data, sizeof(data), "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name); - json_object *l_json_outs = s_request_command_to_rpc(data); + json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name); if (!l_json_outs) { return NULL; } @@ -1458,7 +1543,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name); - json_object *l_json_coins = s_request_command_to_rpc(data); + json_object *l_json_coins = s_request_command_to_rpc(data, l_net_name); if (!l_json_coins) { return -4; } @@ -1592,7 +1677,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) dap_chain_addr_to_str(l_addr_holder), l_net_name); DAP_DEL_Z(l_addr_holder); - json_object *l_json_outs = s_request_command_to_rpc(data); + json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name); uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str); json_object_put(l_json_outs); if (compare256(l_value_balance, l_value) == -1) { @@ -1847,7 +1932,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv) "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_str, l_net_str); - json_object *response = s_request_command_to_rpc(data); + json_object *response = s_request_command_to_rpc(data, l_net_str); if (!response) { printf("Error: Failed to get response from remote node\n"); return -15; @@ -2135,7 +2220,7 @@ uint256_t s_get_key_delegating_min_value(const char *a_net_str){ "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); - json_object *response = s_request_command_to_rpc(data); + json_object *response = s_request_command_to_rpc(data, a_net_str); if (!response) { printf("Error: Failed to get response from remote node\n"); return l_key_delegating_min_value; @@ -2281,7 +2366,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str); - json_object *l_json_coins = s_request_command_to_rpc(data); + json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str); if (!l_json_coins) { printf("Error: Can't get ledger coins list\n"); return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 12867d60e9..4fe3739f61 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -33,27 +33,23 @@ #include <json-c/json.h> - - - - // #define RPC_NODES_URL "http://rpc.cellframe.net" -#define RPC_NODES_URL "45.76.140.191:8081" -#define MAX_RESPONSE_SIZE 4096 #define NET_COUNT 6 typedef struct { char name[20]; char native_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; dap_chain_net_id_t net_id; + char url[128]; + uint16_t port; } NetInfo; static NetInfo netinfo[NET_COUNT] = { - {"riemann", "tKEL", {.uint64 = 0x000000000000dddd}}, - {"raiden", "tCELL", {.uint64 = 0x000000000000bbbb}}, - {"KelVPN", "KEL", {.uint64 = 0x1807202300000000}}, - {"Backbone", "CELL", {.uint64 = 0x0404202200000000}}, - {"mileena", "tMIL", {.uint64 = 0x000000000000cccc}}, - {"subzero", "tCELL", {.uint64 = 0x000000000000acca}} + {"riemann", "tKEL", {.uint64 = 0x000000000000dddd}, "45.76.140.191", 8081}, + {"raiden", "tCELL", {.uint64 = 0x000000000000bbbb}, "http://rpc.cellframe.net", 8081}, + {"KelVPN", "KEL", {.uint64 = 0x1807202300000000}, "http://rpc.cellframe.net", 8081}, + {"Backbone", "CELL", {.uint64 = 0x0404202200000000}, "http://rpc.cellframe.net", 8081}, + {"mileena", "tMIL", {.uint64 = 0x000000000000cccc}, "http://rpc.cellframe.net", 8081}, + {"subzero", "tCELL", {.uint64 = 0x000000000000acca}, "http://rpc.cellframe.net", 8081} }; #ifdef __cplusplus -- GitLab From 01ce7c26f822216922aadee7d1ab9a56504eef9b Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Fri, 28 Mar 2025 12:20:21 +0700 Subject: [PATCH 25/53] [+] -url -port --- modules/compose/dap_chain_tx_compose.c | 1377 +++++++++-------- .../compose/include/dap_chain_tx_compose.h | 36 +- 2 files changed, 729 insertions(+), 684 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index a992519a56..f0dbdd845e 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -39,7 +39,7 @@ #include <netdb.h> #include <json-c/json.h> -static json_object* s_request_command_to_rpc(const char *a_request, const char * a_net_name); +static json_object* s_request_command_to_rpc(const char *a_request, const char * a_net_name, const char * a_url_str, uint16_t a_port); const char *arg_wallets_path = NULL; @@ -254,14 +254,14 @@ static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_ob return ret; } -static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name) { +static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) { json_object * l_response = NULL; size_t l_response_size; struct cmd_request* l_cmd_request = s_cmd_request_init(); dap_client_http_request(dap_worker_get_auto(), - s_get_net_url(a_net_name), - s_get_net_port(a_net_name), + a_url_str ? a_url_str : s_get_net_url(a_net_name), + a_port ? a_port : s_get_net_port(a_net_name), "POST", "application/json", NULL, request, strlen(request), NULL, s_cmd_response_handler, s_cmd_error_handler, @@ -300,10 +300,10 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a } -bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee) { +bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, const char * a_url_str, uint16_t a_port) { char data[512]; snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name); - json_object *l_json_get_fee = s_request_command_to_rpc(data, l_net_name); + json_object *l_json_get_fee = s_request_command_to_rpc(data, l_net_name, a_url_str, a_port); if (!l_json_get_fee) { return false; } @@ -348,12 +348,13 @@ bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net return true; } -bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count) { +bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, + json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port) { char data[512]; snprintf(data, sizeof(data), "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name); - json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name); + json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name, a_url_str, a_port); if (!l_json_outs) { return false; } @@ -402,6 +403,9 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) { const char *l_value_str = NULL; const char *l_rate_str = NULL; const char *l_fee_str = NULL; + const char *l_url_str = NULL; + const char *l_port_str = NULL; + uint16_t l_port = 0; const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); @@ -425,12 +429,24 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) { dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_str); dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-rate", &l_rate_str); dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str); if (!l_net_name) { printf("xchange_create requires parameter '-net'"); return -1; } + if (!l_url_str) { + l_url_str = s_get_net_url(l_net_name); + } + + if (!l_port_str) { + l_port = s_get_net_port(l_net_name); + } else { + l_port = atoi(l_port_str); + } + if (!l_token_buy) { printf("xchange_create requires parameter '-token_buy'"); return -1; @@ -477,7 +493,7 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) { } dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_net_name, l_token_buy, - l_token_sell, l_value, l_rate, l_fee, l_wallet); + l_token_sell, l_value, l_rate, l_fee, l_wallet, l_url_str, l_port); json_object *l_ret = json_object_new_object(); dap_chain_net_tx_to_json(l_tx, l_ret); printf("%s", json_object_to_json_string(l_ret)); @@ -497,6 +513,8 @@ int dap_tx_create_compose(int argc, char ** argv) { const char * l_token_ticker = NULL; const char * l_net_name = NULL; const char * l_chain_name = NULL; + const char * l_url_str = NULL; + uint16_t l_port = 0; const char * l_hash_out_type = NULL; dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type); @@ -528,6 +546,16 @@ int dap_tx_create_compose(int argc, char ** argv) { return -1; } + if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str)) { + l_url_str = s_get_net_url(l_net_name); + } + const char *l_port_str = NULL; + if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str)) { + l_port = s_get_net_port(l_net_name); + } else { + l_port = atoi(l_port_str); + } + uint256_t *l_value = NULL; uint256_t l_value_fee = {}; dap_chain_addr_t **l_addr_to = NULL; @@ -648,7 +676,7 @@ int dap_tx_create_compose(int argc, char ** argv) { } - dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count); + dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count, l_url_str, l_port); json_object * l_json_obj_ret = json_object_new_object(); dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); @@ -696,8 +724,7 @@ int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, - const char* a_token_ticker, - uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num) + const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port) { if (!a_addr_from || !a_token_ticker || !a_value) { return NULL; @@ -731,7 +758,7 @@ dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_list_t *l_list_fee_out = NULL; uint256_t l_net_fee = {}; dap_chain_addr_t *l_addr_fee = NULL; - if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee)) { + if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port)) { return NULL; } @@ -739,7 +766,7 @@ dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); json_object *l_outs = NULL; int l_outputs_count = 0; - if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count)) { + if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) { return NULL; } @@ -1001,9 +1028,9 @@ bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) { dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, const char *a_token_sell, uint256_t a_datoshi_sell, - uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet){ + uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port){ if (!a_net_name || !a_token_buy || !a_token_sell || !a_wallet) { - return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMENT + return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMEN } if (IS_ZERO_256(a_rate)) { return NULL; // XCHANGE_CREATE_ERROR_RATE_IS_ZERO @@ -1017,7 +1044,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name); - json_object *l_json_coins = s_request_command_to_rpc(data, a_net_name); + json_object *l_json_coins = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port); if (!l_json_coins) { return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS } @@ -1031,7 +1058,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", dap_chain_addr_to_str(l_wallet_addr), a_net_name); DAP_DEL_Z(l_wallet_addr); - json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name); + json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port); uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell); uint256_t l_value_sell = a_datoshi_sell; @@ -1058,16 +1085,16 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net l_price->datoshi_sell = a_datoshi_sell; l_price->rate = a_rate; l_price->fee = a_fee; - dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name); + dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name, a_url_str, a_port); return l_tx; } -json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_name, dap_chain_addr_t * a_addr) { +json_object *dap_get_remote_tx_outs(const char *a_token_ticker, const char *a_net_name, dap_chain_addr_t * a_addr, const char *a_url_str, uint16_t a_port) { char data[512]; snprintf(data, sizeof(data), "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name); - json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name); + json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port); if (!l_json_outs) { return NULL; } @@ -1107,7 +1134,7 @@ json_object *get_tx_outs_by_curl(const char *a_token_ticker, const char *a_net_n dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, - const char *a_native_ticker, const char *a_net_name) + const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port) { if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) { return NULL; @@ -1123,13 +1150,13 @@ dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xc dap_chain_addr_t * l_addr_net_fee = NULL; dap_list_t *l_list_fee_out = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee); + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee, a_url_str, a_port); if (l_net_fee_used) SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name)); dap_chain_addr_t l_seller_addr = *l_wallet_addr; - json_object *l_outs_native = get_tx_outs_by_curl(a_native_ticker, a_net_name, l_wallet_addr); + json_object *l_outs_native = dap_get_remote_tx_outs(a_native_ticker, a_net_name, l_wallet_addr, a_url_str, a_port); if (!l_outs_native) { return NULL; } @@ -1138,7 +1165,7 @@ dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xc if (!dap_strcmp(a_price->token_sell, a_native_ticker)) { l_outs = l_outs_native; } else { - l_outs = get_tx_outs_by_curl(a_price->token_sell, a_net_name, l_wallet_addr); + l_outs = dap_get_remote_tx_outs(a_price->token_sell, a_net_name, l_wallet_addr, a_url_str, a_port); } DAP_DELETE(l_wallet_addr); int l_out_native_count = json_object_array_length(l_outs_native); @@ -1265,6 +1292,9 @@ int dap_tx_cond_create_compose(int argc, char ** argv) const char * l_srv_uid_str = NULL; uint256_t l_value_datoshi = {}; uint256_t l_value_fee = {}; + const char * l_url_str = NULL; + const char * l_port_str = NULL; + uint16_t l_port = 0; const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); @@ -1289,6 +1319,8 @@ int dap_tx_cond_create_compose(int argc, char ** argv) dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str); dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str); + dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str); if(!l_token_ticker) { printf("tx_cond_create requires parameter '-token'\n"); @@ -1314,6 +1346,14 @@ int dap_tx_cond_create_compose(int argc, char ** argv) printf("tx_cond_create requires parameter '-net'\n"); return -7; } + if(!l_url_str) { + l_url_str = s_get_net_url(l_net_name); + } + if(!l_port_str) { + l_port = s_get_net_port(l_net_name); + } else { + l_port = atoi(l_port_str); + } if(!l_unit_str) { printf("tx_cond_create requires parameter '-unit'\n"); return -8; @@ -1374,7 +1414,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv) uint256_t l_value_per_unit_max = {}; dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker, l_value_datoshi, l_value_per_unit_max, l_price_unit, - l_srv_uid, l_value_fee, NULL, 0); + l_srv_uid, l_value_fee, NULL, 0, l_url_str, l_port); json_object * l_json_obj_ret = json_object_new_object(); dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); @@ -1394,7 +1434,7 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net uint256_t a_value, uint256_t a_value_per_unit_max, dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, uint256_t a_value_fee, const void *a_cond, - size_t a_cond_size) + size_t a_cond_size, const char *a_url_str, uint16_t a_port) { // check valid param if (!a_net_name || !a_key_from || !a_key_cond || @@ -1408,7 +1448,7 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net uint256_t l_net_fee = {}; dap_chain_addr_t* l_addr_fee = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee); + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port); // find the transactions from which to take away coins uint256_t l_value_transfer = {}; // how many coins to transfer uint256_t l_value_need = {}; @@ -1422,7 +1462,7 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net // list of transaction with 'out' items json_object *l_outs = NULL; int l_outputs_count = 0; - if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count)) { + if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) { return NULL; } dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, @@ -1504,6 +1544,8 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) dap_enc_key_t *l_key_from; dap_chain_wallet_t *l_wallet; dap_chain_addr_t *l_addr_holder; + const char *l_url_str = NULL; + uint16_t l_port = 0; const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); @@ -1540,10 +1582,21 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) return -3; } + if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) { + l_url_str = s_get_net_url(l_net_name); + } + + const char *l_port_str = NULL; + if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) { + l_port = s_get_net_port(l_net_name); + } else { + l_port = atoi(l_port_str); + } + char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name); - json_object *l_json_coins = s_request_command_to_rpc(data, l_net_name); + json_object *l_json_coins = s_request_command_to_rpc(data, l_net_name, l_url_str, l_port); if (!l_json_coins) { return -4; } @@ -1677,7 +1730,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) dap_chain_addr_to_str(l_addr_holder), l_net_name); DAP_DEL_Z(l_addr_holder); - json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name); + json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name, l_url_str, l_port); uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str); json_object_put(l_json_outs); if (compare256(l_value_balance, l_value) == -1) { @@ -1692,7 +1745,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_net_name, l_key_from, l_ticker_str, l_value, l_value_fee, l_time_staking, l_reinvest_percent, - l_delegated_ticker_str, l_value_delegated, l_chain_id_str); + l_delegated_ticker_str, l_value_delegated, l_chain_id_str, l_url_str, l_port); json_object * l_json_obj_ret = json_object_new_object(); dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); @@ -1711,7 +1764,8 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_nam const char *a_main_ticker, uint256_t a_value, uint256_t a_value_fee, dap_time_t a_time_staking, uint256_t a_reinvest_percent, - const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * l_chain_id_str) + const char *a_delegated_ticker_str, uint256_t a_delegated_value, + const char * l_chain_id_str, const char *l_url_str, uint16_t l_port) { dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID }; // check valid param @@ -1728,10 +1782,10 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_nam dap_chain_addr_t l_addr = {}; dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name)); - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee); + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port); SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); - json_object *l_outs_native = get_tx_outs_by_curl(l_native_ticker, a_net_name, &l_addr); + json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port); if (!l_outs_native) { return NULL; } @@ -1740,7 +1794,7 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_nam if (!dap_strcmp(a_main_ticker, l_native_ticker)) { l_outs_main = l_outs_native; } else { - l_outs_main = get_tx_outs_by_curl(a_main_ticker, a_net_name, &l_addr); + l_outs_main = dap_get_remote_tx_outs(a_main_ticker, a_net_name, &l_addr, l_url_str, l_port); } int l_out_native_count = json_object_array_length(l_outs_native); int l_out_main_count = json_object_array_length(l_outs_main); @@ -1880,6 +1934,8 @@ int dap_cli_take_compose(int a_argc, char **a_argv) dap_hash_fast_t l_tx_hash; dap_chain_tx_out_cond_t *l_cond_tx = NULL; dap_enc_key_t *l_owner_key; + const char *l_url_str = NULL; + uint16_t l_port = 0; const char *l_wallet_path = NULL; @@ -1897,6 +1953,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv) arg_wallets_path = dap_strdup(l_wallet_path); } + const char *l_hash_out_type = NULL; dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); if (!l_hash_out_type) @@ -1911,6 +1968,17 @@ int dap_cli_take_compose(int a_argc, char **a_argv) return -2; } + if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) { + l_url_str = s_get_net_url(l_net_str); + } + + const char *l_port_str = NULL; + if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) { + l_port = s_get_net_port(l_net_str); + } else { + l_port = atoi(l_port_str); + } + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str); if (!l_chain_id_str) { printf("Error: Missing or invalid chain_id argument\n"); @@ -1932,7 +2000,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv) "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_str, l_net_str); - json_object *response = s_request_command_to_rpc(data, l_net_str); + json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return -15; @@ -2038,7 +2106,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv) } dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_net_str, l_owner_key, &l_tx_hash, l_prev_cond_idx, l_ticker_str, l_cond_tx->header.value, l_value_fee, - l_delegated_ticker_str, l_value_delegated); + l_delegated_ticker_str, l_value_delegated, l_url_str, l_port); json_object * l_json_obj_ret = json_object_new_object(); dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); @@ -2056,7 +2124,8 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_na dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, const char *a_main_ticker, uint256_t a_value, uint256_t a_value_fee, - const char *a_delegated_ticker_str, uint256_t a_delegated_value) + const char *a_delegated_ticker_str, uint256_t a_delegated_value, + const char *l_url_str, uint16_t l_port) { // check valid param if (!a_net_name | !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) { @@ -2075,14 +2144,14 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_na dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name)); dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee); + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port); - json_object *l_outs_native = get_tx_outs_by_curl(l_native_ticker, a_net_name, &l_addr); + json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port); if (!l_outs_native) { return NULL; } - json_object *l_outs_delegated = get_tx_outs_by_curl(a_delegated_ticker_str, a_net_name, &l_addr); + json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, a_net_name, &l_addr, l_url_str, l_port); int l_out_native_count = json_object_array_length(l_outs_native); int l_out_delegated_count = json_object_array_length(l_outs_delegated); @@ -2213,14 +2282,14 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_na return l_tx; } -uint256_t s_get_key_delegating_min_value(const char *a_net_str){ +uint256_t s_get_key_delegating_min_value(const char *a_net_str, const char *l_url_str, uint16_t l_port){ uint256_t l_key_delegating_min_value = uint256_0; char data[512]; snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); - json_object *response = s_request_command_to_rpc(data, a_net_str); + json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return l_key_delegating_min_value; @@ -2271,7 +2340,8 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) const char* l_wallet_str = NULL; const char* l_net_str = NULL; const char* l_token_str = NULL; - + const char* l_url_str = NULL; + uint16_t l_port = 0; const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); if (!l_wallet_path) { @@ -2294,6 +2364,17 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING; } + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-url", &l_url_str)) { + l_url_str = s_get_net_url(l_net_str); + } + + const char *l_port_str = NULL; + if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str)) { + l_port = s_get_net_port(l_net_str); + } else { + l_port = atoi(l_port_str); + } + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str); if (!l_question_str){ printf("Voting requires a question parameter to be valid.\n"); @@ -2366,7 +2447,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str); - json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str); + json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_coins) { printf("Error: Can't get ledger coins list\n"); return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; @@ -2378,7 +2459,9 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) } json_object_put(l_json_coins); - dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net_str, l_token_str); + dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, + l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, + l_wallet_fee, l_net_str, l_token_str, l_url_str, l_port); dap_list_free(l_options_list); dap_chain_wallet_close(l_wallet_fee); json_object * l_json_obj_ret = json_object_new_object(); @@ -2392,7 +2475,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, - const char *a_net_str, const char *a_token_ticker) { + const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port) { if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ return NULL; @@ -2417,12 +2500,12 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, const char *l_native_ticker = s_get_native_ticker(a_net_str); uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer; dap_chain_addr_t *l_addr_fee = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee); + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port); SUM_256_256(l_net_fee, a_fee, &l_total_fee); json_object *l_outs = NULL; int l_outputs_count = 0; - if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count)) { + if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count, l_url_str, l_port)) { return NULL; } @@ -2893,17 +2976,15 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c */ -/** +/** static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) { const char *l_net_str = NULL, *l_wallet_str = NULL, *l_cert_str = NULL, *l_fee_str = NULL, - *l_tx_hash_str = NULL, - *l_poa_cert_str = NULL, - *l_signing_pkey_hash_str = NULL, - *l_signing_pkey_type_str = NULL; + *l_tx_hash_str = NULL; + int l_arg_index = 1; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); if (!l_net_str) { @@ -2914,42 +2995,26 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) uint256_t l_fee = {}; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); if (!l_wallet_str) { - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-poa_cert", &l_poa_cert_str); - if (!l_poa_cert_str) { - printf("Command 'invalidate' requires parameter -w or -poa_cert\n"); - return -1; - } - } else { - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); - if (!l_fee_str) { - printf("Command 'delegate' requires parameter -fee\n"); - return -1; - } - l_fee = dap_chain_balance_scan(l_fee_str); - if (IS_ZERO_256(l_fee)) { - printf("Unrecognized number in '-fee' param\n"); - return -1; - } + printf("Command 'invalidate' requires parameter -w\n"); + return -1; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); + if (!l_fee_str) { + printf("Command 'delegate' requires parameter -fee\n"); + return -1; + } + l_fee = dap_chain_balance_scan(l_fee_str); + if (IS_ZERO_256(l_fee)) { + printf("Unrecognized number in '-fee' param\n"); + return -1; } dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tx", &l_tx_hash_str); if (!l_tx_hash_str) { dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str); if (!l_cert_str) { - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-signing_pkey_hash", &l_signing_pkey_hash_str); - if (!l_signing_pkey_hash_str) { - printf("Command 'invalidate' requires parameter -tx or -cert or -signing_pkey_hash\n"); - return -1; - } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-signing_pkey_type", &l_signing_pkey_type_str); - if (!l_signing_pkey_type_str) { - printf("Command 'invalidate' requires parameter -signing_pkey_type\n"); - return -1; - } - if (dap_sign_type_from_str(l_signing_pkey_type_str).type == SIG_TYPE_NULL) { - printf("Invalid signing_pkey_type %s\n", l_signing_pkey_type_str); - return -3; - } + printf("Command 'invalidate' requires parameter -tx or -cert\n"); + return -1; } } @@ -3091,47 +3156,22 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) } } dap_chain_datum_tx_t *l_tx = NULL; - if (l_wallet_str) { - const char* l_sign_str = ""; - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config),NULL); - if (!l_wallet) { - printf("Specified wallet not found\n"); - return -14; - } else { - l_sign_str = dap_chain_wallet_check_sign(l_wallet); - } - dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); - l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key); - dap_chain_wallet_close(l_wallet); - dap_enc_key_delete(l_enc_key); + const char* l_sign_str = ""; + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config),NULL); + if (!l_wallet) { + printf("Specified wallet not found\n"); + return -14; } else { - dap_cert_t *l_poa_cert = dap_cert_find_by_name(l_poa_cert_str); - if (!l_poa_cert) { - printf("Specified certificate not found\n"); - return -4; - } - if (!s_srv_stake_is_poa_cert(l_net, l_poa_cert->enc_key)) { - printf("Specified certificate is not PoA root one\n"); - return -16; - } - dap_chain_datum_decree_t *l_decree = s_stake_decree_invalidate(l_net, &l_tx_hash, l_poa_cert); - char *l_decree_hash_str = NULL; - if (l_decree && (l_decree_hash_str = s_stake_decree_put(l_decree, l_net))) { - json_object* l_json_object_invalidate = json_object_new_object(); - json_object_object_add(l_json_object_invalidate, "status", json_object_new_string("success")); - json_object_object_add(l_json_object_invalidate, "decree", json_object_new_string(l_decree_hash_str)); - json_object_object_add(l_json_object_invalidate, "message", json_object_new_string("Specified delegated key invalidated. Try to execute this command with -w to return m-tokens to owner")); - json_object_array_add(*a_json_arr_reply, l_json_object_invalidate); - DAP_DELETE(l_decree); - DAP_DELETE(l_decree_hash_str); - } else { - char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; - dap_chain_hash_fast_to_str(&l_tx, l_tx_hash_str, sizeof(l_tx_hash_str)); - printf("Can't invalidate transaction %s, examine log files for details\n", l_tx_hash_str); - DAP_DEL_Z(l_decree); - return -15; - } + l_sign_str = dap_chain_wallet_check_sign(l_wallet); } + dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); + l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key); + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); + dap_chain_wallet_close(l_wallet); + dap_enc_key_delete(l_enc_key); return 0; } @@ -3139,7 +3179,8 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap { - dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash); + dap_chain_datum_tx_t *l_cond_tx = + dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash); if (!l_cond_tx) { printf("Requested conditional transaction not found\n"); return NULL; @@ -3186,7 +3227,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap // list of transaction with 'out' items to sell uint256_t l_net_fee, l_fee_total = a_fee; dap_chain_addr_t l_net_fee_addr; - bool l_net_fee_used = dap_chain_net_tx_get_fee(a_net->pub.id, &l_net_fee, &l_net_fee_addr); + bool l_net_fee_used = dap_get_remote_net_fee_and_address(s_get_net_id(a_net_str), &l_net_fee, &l_net_fee_addr); if (l_net_fee_used) SUM_256_256(l_fee_total, l_net_fee, &l_fee_total); dap_list_t *l_list_fee_out = NULL; @@ -3250,578 +3291,574 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap return l_tx; } */ +/** +dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){ + dap_chain_net_srv_order_t* l_order = NULL; + json_object *orders_array = json_object_array_get_idx(response, 0); + size_t orders_count = json_object_array_length(orders_array); + for (size_t i = 0; i < orders_count; i++) { + json_object *order_obj = json_object_array_get_idx(orders_array, i); + const char *order_hash_str = json_object_get_string(json_object_object_get(order_obj, "order")); + + if (strcmp(order_hash_str, l_order_hash_str) == 0) { + l_order = DAP_NEW_Z_SIZE(dap_chain_net_srv_order_t, sizeof(dap_chain_net_srv_order_t)); + l_order->version = json_object_get_int(json_object_object_get(order_obj, "version")); + l_order->direction = dap_chain_net_srv_order_direction_from_str(json_object_get_string(json_object_object_get(order_obj, "direction"))); + l_order->ts_created = dap_time_from_str(json_object_get_string(json_object_object_get(order_obj, "created"))); + l_order->srv_uid.uint64 = dap_chain_net_srv_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "srv_uid"))).uint64; + l_order->price = dap_uint256_scan_uninteger(json_object_get_string(json_object_object_get(order_obj, "price datoshi"))); + strncpy(l_order->price_ticker, json_object_get_string(json_object_object_get(order_obj, "price token")), DAP_CHAIN_TICKER_SIZE_MAX); + l_order->units = json_object_get_int(json_object_object_get(order_obj, "units")); + l_order->price_unit = dap_chain_net_srv_price_unit_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "price unit"))); + dap_chain_node_addr_from_str(&l_order->node_addr, json_object_get_string(json_object_object_get(order_obj, "node_addr"))); + dap_chain_hash_fast_from_str(&l_order->tx_cond_hash, json_object_get_string(json_object_object_get(order_obj, "tx_cond_hash"))); + l_order->ext_size = json_object_get_int(json_object_object_get(order_obj, "ext_size")); + if (l_order->ext_size > 0) { + const char *tax_str = json_object_get_string(json_object_object_get(order_obj, "tax")); + const char *value_max_str = json_object_get_string(json_object_object_get(order_obj, "maximum_value")); + *a_tax = dap_uint256_scan_decimal(tax_str); + *a_value_max = dap_uint256_scan_decimal(value_max_str); + } -// dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){ -// dap_chain_net_srv_order_t* l_order = NULL; -// json_object *orders_array = json_object_array_get_idx(response, 0); -// size_t orders_count = json_object_array_length(orders_array); -// for (size_t i = 0; i < orders_count; i++) { -// json_object *order_obj = json_object_array_get_idx(orders_array, i); -// const char *order_hash_str = json_object_get_string(json_object_object_get(order_obj, "order")); - -// if (strcmp(order_hash_str, l_order_hash_str) == 0) { -// l_order = DAP_NEW_Z_SIZE(dap_chain_net_srv_order_t, sizeof(dap_chain_net_srv_order_t)); -// l_order->version = json_object_get_int(json_object_object_get(order_obj, "version")); -// l_order->direction = dap_chain_net_srv_order_direction_from_str(json_object_get_string(json_object_object_get(order_obj, "direction"))); -// l_order->ts_created = dap_time_from_str(json_object_get_string(json_object_object_get(order_obj, "created"))); -// l_order->srv_uid.uint64 = dap_chain_net_srv_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "srv_uid"))).uint64; -// l_order->price = dap_uint256_scan_uninteger(json_object_get_string(json_object_object_get(order_obj, "price datoshi"))); -// strncpy(l_order->price_ticker, json_object_get_string(json_object_object_get(order_obj, "price token")), DAP_CHAIN_TICKER_SIZE_MAX); -// l_order->units = json_object_get_int(json_object_object_get(order_obj, "units")); -// l_order->price_unit = dap_chain_net_srv_price_unit_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "price unit"))); -// dap_chain_node_addr_from_str(&l_order->node_addr, json_object_get_string(json_object_object_get(order_obj, "node_addr"))); -// dap_chain_hash_fast_from_str(&l_order->tx_cond_hash, json_object_get_string(json_object_object_get(order_obj, "tx_cond_hash"))); -// l_order->ext_size = json_object_get_int(json_object_object_get(order_obj, "ext_size")); -// if (l_order->ext_size > 0) { -// const char *tax_str = json_object_get_string(json_object_object_get(order_obj, "tax")); -// const char *value_max_str = json_object_get_string(json_object_object_get(order_obj, "maximum_value")); -// *a_tax = dap_uint256_scan_decimal(tax_str); -// *a_value_max = dap_uint256_scan_decimal(value_max_str); -// } - -// json_object *conditional_tx_params = json_object_object_get(order_obj, "conditional_tx_params"); -// if (conditional_tx_params) { -// const char *sovereign_tax_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_tax")); -// const char *sovereign_addr_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_addr")); -// *a_sovereign_tax = dap_uint256_scan_decimal(sovereign_tax_str); -// a_sovereign_addr = dap_chain_addr_from_str(sovereign_addr_str); -// } -// break; -// } -// } -// return l_order; -// } + json_object *conditional_tx_params = json_object_object_get(order_obj, "conditional_tx_params"); + if (conditional_tx_params) { + const char *sovereign_tax_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_tax")); + const char *sovereign_addr_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_addr")); + *a_sovereign_tax = dap_uint256_scan_decimal(sovereign_tax_str); + a_sovereign_addr = dap_chain_addr_from_str(sovereign_addr_str); + } + break; + } + } + return l_order; +} -// dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax){ -// char data[512]; -// snprintf(data, sizeof(data), -// "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", -// l_net_str); -// json_object *response = s_request_command_to_rpc(data); -// if (!response) { -// printf("Error: Failed to get response from remote node\n"); -// return NULL; -// } +dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax){ + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", + l_net_str); + json_object *response = s_request_command_to_rpc(data); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return NULL; + } -// dap_chain_net_srv_order_t *l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response); -// json_object_put(response); - -// if (!l_order) { -// snprintf(data, sizeof(data), -// "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", -// l_net_str); -// response = s_request_command_to_rpc(data); -// if (!response) { -// printf("Error: Failed to get response from remote node\n"); -// return NULL; -// } -// l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response); -// json_object_put(response); -// } -// return l_order; -// } + dap_chain_net_srv_order_t *l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response); + json_object_put(response); + + if (!l_order) { + snprintf(data, sizeof(data), + "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", + l_net_str); + response = s_request_command_to_rpc(data); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return NULL; + } + l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response); + json_object_put(response); + } + return l_order; +} -// static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) -// { -// int l_arg_index = 0; -// const char *l_net_str = NULL, -// *l_wallet_str = NULL, -// *l_cert_str = NULL, -// *l_pkey_str = NULL, -// *l_pkey_full_str = NULL, -// *l_sign_type_str = NULL, -// *l_value_str = NULL, -// *l_fee_str = NULL, -// *l_node_addr_str = NULL, -// *l_order_hash_str = NULL; +static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) +{ + int l_arg_index = 0; + const char *l_net_str = NULL, + *l_wallet_str = NULL, + *l_cert_str = NULL, + *l_pkey_str = NULL, + *l_pkey_full_str = NULL, + *l_sign_type_str = NULL, + *l_value_str = NULL, + *l_fee_str = NULL, + *l_node_addr_str = NULL, + *l_order_hash_str = NULL; -// dap_pkey_t *l_pkey = NULL; -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-net", &l_net_str); -// if (!l_net_str) { -// printf("Command 'delegate' requires parameter -net\n"); -// return -1; -// } + dap_pkey_t *l_pkey = NULL; + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-net", &l_net_str); + if (!l_net_str) { + printf("Command 'delegate' requires parameter -net\n"); + return -1; + } -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-w", &l_wallet_str); -// if (!l_wallet_str) { -// printf("Command 'delegate' requires parameter -w\n"); -// return -1; -// } -// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL); -// if (!l_wallet) { -// printf("Specified wallet not found\n"); -// return -2; -// } -// dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); -// dap_chain_wallet_close(l_wallet); -// dap_chain_addr_t l_signing_addr, l_sovereign_addr = {}; -// uint256_t l_sovereign_tax = uint256_0; -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-cert", &l_cert_str); -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str); -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-sign_type", &l_sign_type_str); -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-order", &l_order_hash_str); -// if (!l_cert_str && !l_order_hash_str && !l_pkey_full_str) { -// printf("Command 'delegate' requires parameter -cert and/or -order and/or -pkey\n"); -// dap_enc_key_delete(l_enc_key); -// return -1; -// } -// if (l_pkey_full_str) { -// printf("Command 'delegate' requires only one, -pkey or -pkey_full\n"); -// dap_enc_key_delete(l_enc_key); -// return -1; -// } -// if (( l_pkey_full_str) && !l_sign_type_str) { -// printf("Command 'delegate' requires parameter -sign_type for pkey\n"); -// dap_enc_key_delete(l_enc_key); -// return -1; -// } -// uint256_t l_value = uint256_0; -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-value", &l_value_str); -// if (!l_value_str) { -// if (!l_order_hash_str) { -// printf("Command 'delegate' requires parameter -value\n"); -// dap_enc_key_delete(l_enc_key); -// return -1; -// } -// } else { -// l_value = dap_chain_balance_scan(l_value_str); -// if (IS_ZERO_256(l_value)) { -// printf("Unrecognized number in '-value' param\n"); -// dap_enc_key_delete(l_enc_key); -// return -1; -// } -// } -// dap_chain_datum_tx_t *l_prev_tx = NULL; -// if (l_cert_str) { -// dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str); -// if (!l_signing_cert) { -// printf("Specified certificate not found\n"); -// dap_enc_key_delete(l_enc_key); -// return -3; -// } -// if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(l_net_str))) { -// printf("Specified certificate is wrong\n"); -// dap_enc_key_delete(l_enc_key); -// return -4; -// } -// l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key); -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str); -// } -// else if (l_pkey_full_str) { -// dap_sign_type_t l_type = dap_sign_type_from_str(l_sign_type_str); -// if (l_type.type == SIG_TYPE_NULL) { -// printf("Wrong sign type\n"); -// dap_enc_key_delete(l_enc_key); -// return -5; -// } -// l_pkey = dap_pkey_get_from_str(l_pkey_full_str); -// if (!l_pkey) { -// printf("Invalid pkey string format, can't get pkey_full\n"); -// dap_enc_key_delete(l_enc_key); -// return -6; -// } -// if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) { -// printf("pkey and sign types is different\n"); -// dap_enc_key_delete(l_enc_key); -// return -6; -// } -// dap_chain_hash_fast_t l_hash_public_key = {0}; -// if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) { -// printf("Invalid pkey hash format\n"); -// dap_enc_key_delete(l_enc_key); -// return -6; -// } -// dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(l_net_str)); -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str); -// } + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-w", &l_wallet_str); + if (!l_wallet_str) { + printf("Command 'delegate' requires parameter -w\n"); + return -1; + } + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL); + if (!l_wallet) { + printf("Specified wallet not found\n"); + return -2; + } + dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); + dap_chain_wallet_close(l_wallet); + dap_chain_addr_t l_signing_addr, l_sovereign_addr = {}; + uint256_t l_sovereign_tax = uint256_0; + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-cert", &l_cert_str); + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str); + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-sign_type", &l_sign_type_str); + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-order", &l_order_hash_str); + if (!l_cert_str && !l_order_hash_str && !l_pkey_full_str) { + printf("Command 'delegate' requires parameter -cert and/or -order and/or -pkey\n"); + dap_enc_key_delete(l_enc_key); + return -1; + } + if (l_pkey_full_str) { + printf("Command 'delegate' requires only one, -pkey or -pkey_full\n"); + dap_enc_key_delete(l_enc_key); + return -1; + } + if (( l_pkey_full_str) && !l_sign_type_str) { + printf("Command 'delegate' requires parameter -sign_type for pkey\n"); + dap_enc_key_delete(l_enc_key); + return -1; + } + uint256_t l_value = uint256_0; + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-value", &l_value_str); + if (!l_value_str) { + if (!l_order_hash_str) { + printf("Command 'delegate' requires parameter -value\n"); + dap_enc_key_delete(l_enc_key); + return -1; + } + } else { + l_value = dap_chain_balance_scan(l_value_str); + if (IS_ZERO_256(l_value)) { + printf("Unrecognized number in '-value' param\n"); + dap_enc_key_delete(l_enc_key); + return -1; + } + } + dap_chain_datum_tx_t *l_prev_tx = NULL; + if (l_cert_str) { + dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str); + if (!l_signing_cert) { + printf("Specified certificate not found\n"); + dap_enc_key_delete(l_enc_key); + return -3; + } + if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(l_net_str))) { + printf("Specified certificate is wrong\n"); + dap_enc_key_delete(l_enc_key); + return -4; + } + l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key); + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str); + } + else if (l_pkey_full_str) { + dap_sign_type_t l_type = dap_sign_type_from_str(l_sign_type_str); + if (l_type.type == SIG_TYPE_NULL) { + printf("Wrong sign type\n"); + dap_enc_key_delete(l_enc_key); + return -5; + } + l_pkey = dap_pkey_get_from_str(l_pkey_full_str); + if (!l_pkey) { + printf("Invalid pkey string format, can't get pkey_full\n"); + dap_enc_key_delete(l_enc_key); + return -6; + } + if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) { + printf("pkey and sign types is different\n"); + dap_enc_key_delete(l_enc_key); + return -6; + } + dap_chain_hash_fast_t l_hash_public_key = {0}; + if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) { + printf("Invalid pkey hash format\n"); + dap_enc_key_delete(l_enc_key); + return -6; + } + dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(l_net_str)); + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str); + } + + dap_chain_node_addr_t l_node_addr = g_node_addr; + if (l_node_addr_str) { + if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) { + printf("Unrecognized node addr %s\n", l_node_addr_str); + dap_enc_key_delete(l_enc_key); + return -7; + } + } + if (l_order_hash_str) { + uint256_t l_tax; + uint256_t l_value_max; + int l_prev_tx_count = 0; + dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax); + + if (l_order->direction == SERV_DIR_BUY) { // Staker order + if (!l_cert_str) { + printf("Command 'delegate' requires parameter -cert with this order type\n"); + dap_enc_key_delete(l_enc_key); + return -1; + } + if (l_order->ext_size != 0) { + printf("Specified order has invalid size\n"); + dap_enc_key_delete(l_enc_key); + DAP_DELETE(l_order); + return -9; + } -// dap_chain_node_addr_t l_node_addr = g_node_addr; -// if (l_node_addr_str) { -// if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) { -// printf("Unrecognized node addr %s\n", l_node_addr_str); -// dap_enc_key_delete(l_enc_key); -// return -7; -// } -// } -// if (l_order_hash_str) { - -// uint256_t l_tax; -// uint256_t l_value_max; -// int l_prev_tx_count = 0; -// dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax); - -// if (l_order->direction == SERV_DIR_BUY) { // Staker order -// if (!l_cert_str) { -// printf("Command 'delegate' requires parameter -cert with this order type\n"); -// dap_enc_key_delete(l_enc_key); -// return -1; -// } -// if (l_order->ext_size != 0) { -// printf("Specified order has invalid size\n"); -// dap_enc_key_delete(l_enc_key); -// DAP_DELETE(l_order); -// return -9; -// } - -// dap_chain_tx_out_cond_t *l_cond_tx = NULL; -// char data[512]; -// snprintf(data, sizeof(data), -// "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", -// l_order->tx_cond_hash, l_net_str); + dap_chain_tx_out_cond_t *l_cond_tx = NULL; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + l_order->tx_cond_hash, l_net_str); -// json_object *response = s_request_command_to_rpc(data); -// if (!response) { -// printf("Error: Failed to get response from remote node\n"); -// return -15; -// } + json_object *response = s_request_command_to_rpc(data); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return -15; + } -// json_object *items = json_object_object_get(response, "ITEMS"); -// if (!items) { -// printf("Error: No items found in response\n"); -// return -16; -// } -// int items_count = json_object_array_length(items); -// for (int i = 0; i < items_count; i++) { -// json_object *item = json_object_array_get_idx(items, i); -// const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); -// if (dap_strcmp(item_type, "OUT COND") == 0) { -// const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); -// if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE")) { -// l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); -// l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; -// l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); -// l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE; -// l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); -// l_cond_tx->header.ts_expires = dap_time_from_str(json_object_get_string(json_object_object_get(item, "ts_expires"))); -// l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr"))); -// if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) { -// printf("Error: Failed to parse signer node address\n"); -// return -17; -// } -// l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); -// l_prev_tx_count++; -// break; -// } -// } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) { -// l_prev_tx_count++; -// } -// } -// if (!l_cond_tx) { -// printf("Error: No transaction output condition found\n"); -// return -7; -// } - -// json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); -// const char *spent_outs_value = json_object_get_string(spent_outs); -// if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { -// printf("Error: Transaction output item already used\n"); -// return -9; -// } - - - -// // l_prev_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash); -// // if (!l_prev_tx) { -// // printf("The order's conditional transaction not found in ledger\n"); -// // dap_enc_key_delete(l_enc_key); -// // DAP_DELETE(l_order); -// // return -10; -// // } -// // int l_out_num = 0; -// // dap_chain_tx_out_cond_t *l_cond_tx = dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); -// // if (!l_cond) { -// // printf("The order's conditional transaction has invalid type\n"); -// // dap_enc_key_delete(l_enc_key); -// // DAP_DELETE(l_order); -// // return -11; -// // } -// // if (dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_order->tx_cond_hash, l_out_num, NULL)) { -// // printf("The order's conditional transaction is already spent\n"); -// // dap_enc_key_delete(l_enc_key); -// // DAP_DELETE(l_order); -// // return -12; -// // } - -// char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; -// dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(l_net_str)); -// const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker")); -// if (!l_token_ticker) { -// printf("Error: Token ticker not found in response\n"); -// return -18; -// } -// json_object_put(response); -// if (dap_strcmp(l_token_ticker, l_delegated_ticker)) { -// printf("Requested conditional transaction have another ticker (not %s)\n", l_delegated_ticker); -// return -13; -// } -// if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) { -// printf("The order's conditional transaction has invalid format\n"); -// dap_enc_key_delete(l_enc_key); -// DAP_DELETE(l_order); -// return -14; -// } -// if (compare256(l_cond_tx->header.value, l_order->price)) { -// printf("The order's conditional transaction has different value\n"); -// dap_enc_key_delete(l_enc_key); -// DAP_DELETE(l_order); -// return -15; -// } -// if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) || -// l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) { -// printf("The order's conditional transaction gas not blank address or key\n"); -// dap_enc_key_delete(l_enc_key); -// DAP_DELETE(l_order); -// return -16; -// } -// l_value = l_order->price; -// // dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR); -// // l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE); -// // l_sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t); -// // MULT_256_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); -// } -// /** TODO add new command to get l_pkey from order -// * else { -// if (!l_value_str) { -// printf("Command 'delegate' requires parameter -value with this order type\n"); -// dap_enc_key_delete(l_enc_key); -// return -1; -// } -// const char *l_sovereign_addr_str = NULL; -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str); -// if (l_sovereign_addr_str) { -// dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str); -// if (!l_spec_addr) { -// printf("Specified address is ivalid\n"); -// return -17; -// } -// l_sovereign_addr = *l_spec_addr; -// DAP_DELETE(l_spec_addr); -// } else -// dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, s_get_net_id(l_net_str)); - -// if (l_order_hash_str && compare256(l_value, l_order->price) == -1) { -// const char *l_coin_min_str, *l_value_min_str = -// dap_uint256_to_char(l_order->price, &l_coin_min_str); -// printf("Number in '-value' param %s is lower than order minimum allowed value %s(%s)\n", -// l_value_str, l_coin_min_str, l_value_min_str); -// dap_enc_key_delete(l_enc_key); -// return -18; -// } -// if (l_order_hash_str && compare256(l_value, l_value_max) == 1) { -// const char *l_coin_max_str, *l_value_max_str = -// dap_uint256_to_char(l_value_max, &l_coin_max_str); -// printf("Number in '-value' param %s is higher than order minimum allowed value %s(%s)\n", -// l_value_str, l_coin_max_str, l_value_max_str); -// dap_enc_key_delete(l_enc_key); -// return -19; -// } -// dap_sign_t *l_sign = (dap_sign_t *)(l_order->ext_n_sign + l_order->ext_size); -// if (l_sign->header.type.type == SIG_TYPE_NULL) { -// printf("Specified order is unsigned\n"); -// dap_enc_key_delete(l_enc_key); -// DAP_DELETE(l_order); -// return -20; -// } -// dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_net->pub.id); -// l_pkey = dap_pkey_get_from_sign(l_sign); -// char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX]; -// dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_net->pub.native_ticker); -// if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) { -// printf("Specified order is invalid\n"); -// dap_enc_key_delete(l_enc_key); -// DAP_DELETE(l_order); -// return -21; -// } -// l_node_addr = l_order->node_addr; -// } -// DAP_DELETE(l_order); -// if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 || -// compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) { -// printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n"); -// dap_enc_key_delete(l_enc_key); -// return -22; -// } -// DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); -// } -// */ -// if (!l_pkey) { -// printf("pkey not defined\n"); -// dap_enc_key_delete(l_enc_key); -// return -6; -// } + json_object *items = json_object_object_get(response, "ITEMS"); + if (!items) { + printf("Error: No items found in response\n"); + return -16; + } + int items_count = json_object_array_length(items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (dap_strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE")) { + l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); + l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; + l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); + l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE; + l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); + l_cond_tx->header.ts_expires = dap_time_from_str(json_object_get_string(json_object_object_get(item, "ts_expires"))); + l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr"))); + if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) { + printf("Error: Failed to parse signer node address\n"); + return -17; + } + l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); + l_prev_tx_count++; + break; + } + } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) { + l_prev_tx_count++; + } + } + if (!l_cond_tx) { + printf("Error: No transaction output condition found\n"); + return -7; + } -// int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr); -// if (l_check_result) { -// printf("Key and node verification error\n"); -// dap_enc_key_delete(l_enc_key); -// return l_check_result; -// } + json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); + const char *spent_outs_value = json_object_get_string(spent_outs); + if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { + printf("Error: Transaction output item already used\n"); + return -9; + } + + + + l_prev_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash); + if (!l_prev_tx) { + printf("The order's conditional transaction not found in ledger\n"); + dap_enc_key_delete(l_enc_key); + DAP_DELETE(l_order); + return -10; + } + int l_out_num = 0; + dap_chain_tx_out_cond_t *l_cond_tx = dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); + if (!l_cond) { + printf("The order's conditional transaction has invalid type\n"); + dap_enc_key_delete(l_enc_key); + DAP_DELETE(l_order); + return -11; + } + if (dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_order->tx_cond_hash, l_out_num, NULL)) { + printf("The order's conditional transaction is already spent\n"); + dap_enc_key_delete(l_enc_key); + DAP_DELETE(l_order); + return -12; + } + + char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; + dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(l_net_str)); + const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker")); + if (!l_token_ticker) { + printf("Error: Token ticker not found in response\n"); + return -18; + } + json_object_put(response); + if (dap_strcmp(l_token_ticker, l_delegated_ticker)) { + printf("Requested conditional transaction have another ticker (not %s)\n", l_delegated_ticker); + return -13; + } + if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) { + printf("The order's conditional transaction has invalid format\n"); + dap_enc_key_delete(l_enc_key); + DAP_DELETE(l_order); + return -14; + } + if (compare256(l_cond_tx->header.value, l_order->price)) { + printf("The order's conditional transaction has different value\n"); + dap_enc_key_delete(l_enc_key); + DAP_DELETE(l_order); + return -15; + } + if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) || + l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) { + printf("The order's conditional transaction gas not blank address or key\n"); + dap_enc_key_delete(l_enc_key); + DAP_DELETE(l_order); + return -16; + } + l_value = l_order->price; + // dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR); + // l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE); + // l_sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t); + // MULT_256_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); + } else { + if (!l_value_str) { + printf("Command 'delegate' requires parameter -value with this order type\n"); + dap_enc_key_delete(l_enc_key); + return -1; + } + const char *l_sovereign_addr_str = NULL; + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str); + if (l_sovereign_addr_str) { + dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str); + if (!l_spec_addr) { + printf("Specified address is ivalid\n"); + return -17; + } + l_sovereign_addr = *l_spec_addr; + DAP_DELETE(l_spec_addr); + } else + dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, s_get_net_id(l_net_str)); + + if (l_order_hash_str && compare256(l_value, l_order->price) == -1) { + const char *l_coin_min_str, *l_value_min_str = + dap_uint256_to_char(l_order->price, &l_coin_min_str); + printf("Number in '-value' param %s is lower than order minimum allowed value %s(%s)\n", + l_value_str, l_coin_min_str, l_value_min_str); + dap_enc_key_delete(l_enc_key); + return -18; + } + if (l_order_hash_str && compare256(l_value, l_value_max) == 1) { + const char *l_coin_max_str, *l_value_max_str = + dap_uint256_to_char(l_value_max, &l_coin_max_str); + printf("Number in '-value' param %s is higher than order minimum allowed value %s(%s)\n", + l_value_str, l_coin_max_str, l_value_max_str); + dap_enc_key_delete(l_enc_key); + return -19; + } + dap_sign_t *l_sign = (dap_sign_t *)(l_order->ext_n_sign + l_order->ext_size); + if (l_sign->header.type.type == SIG_TYPE_NULL) { + printf("Specified order is unsigned\n"); + dap_enc_key_delete(l_enc_key); + DAP_DELETE(l_order); + return -20; + } + dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_net->pub.id); + l_pkey = dap_pkey_get_from_sign(l_sign); + char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX]; + dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_net->pub.native_ticker); + if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) { + printf("Specified order is invalid\n"); + dap_enc_key_delete(l_enc_key); + DAP_DELETE(l_order); + return -21; + } + l_node_addr = l_order->node_addr; + } + DAP_DELETE(l_order); + if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 || + compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) { + printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n"); + dap_enc_key_delete(l_enc_key); + return -22; + } + DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); + } + if (!l_pkey) { + printf("pkey not defined\n"); + dap_enc_key_delete(l_enc_key); + return -6; + } + + int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr); + if (l_check_result) { + printf("Key and node verification error\n"); + dap_enc_key_delete(l_enc_key); + return l_check_result; + } -// uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str); -// if (compare256(l_value, l_allowed_min) == -1) { -// const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str); -// printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n", -// l_value_str, l_coin_min_str, l_value_min_str); -// dap_enc_key_delete(l_enc_key); -// return -23; -// } -// dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-fee", &l_fee_str); -// if (!l_fee_str) { -// printf("Command 'delegate' requires parameter -fee\n"); -// dap_enc_key_delete(l_enc_key); -// return -1; -// } -// uint256_t l_fee = dap_chain_balance_scan(l_fee_str); -// if (IS_ZERO_256(l_fee)) { -// printf("Unrecognized number in '-fee' param\n"); -// dap_enc_key_delete(l_enc_key); -// return -1; -// } + uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str); + if (compare256(l_value, l_allowed_min) == -1) { + const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str); + printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n", + l_value_str, l_coin_min_str, l_value_min_str); + dap_enc_key_delete(l_enc_key); + return -23; + } + dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-fee", &l_fee_str); + if (!l_fee_str) { + printf("Command 'delegate' requires parameter -fee\n"); + dap_enc_key_delete(l_enc_key); + return -1; + } + uint256_t l_fee = dap_chain_balance_scan(l_fee_str); + if (IS_ZERO_256(l_fee)) { + printf("Unrecognized number in '-fee' param\n"); + dap_enc_key_delete(l_enc_key); + return -1; + } -// // Create conditional transaction -// dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr, -// l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_prev_tx_count, l_pkey); -// dap_enc_key_delete(l_enc_key); -// DAP_DELETE(l_pkey); + // Create conditional transaction + dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr, + l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_prev_tx_count, l_pkey); + dap_enc_key_delete(l_enc_key); + DAP_DELETE(l_pkey); -// DAP_DELETE(l_tx); + DAP_DELETE(l_tx); -// return 0; + return 0; -// } +} -// // Freeze staker's funds when delegating a key -// dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc_key_t *a_key, -// uint256_t a_value, uint256_t a_fee, -// dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, -// dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, -// dap_chain_datum_tx_t *a_prev_tx, int l_prev_tx_count, dap_pkey_t *a_pkey) -// { -// dap_return_val_if_pass (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr, NULL); - -// const char *l_native_ticker = s_get_native_ticker(a_net_str); -// char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; -// dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker); -// uint256_t l_value_transfer = {}, l_fee_transfer = {}; // how many coins to transfer -// // list of transaction with 'out' items to sell -// dap_chain_addr_t l_owner_addr; -// dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str)); -// uint256_t l_net_fee, l_fee_total = a_fee; -// dap_chain_addr_t l_net_fee_addr; -// bool l_net_fee_used = get_remote_net_fee(a_net_str, l_native_ticker, &l_net_fee, &l_net_fee_addr); -// if (l_net_fee_used) -// SUM_256_256(l_fee_total, l_net_fee, &l_fee_total); - -// dap_list_t *l_list_fee_out = NULL; -// if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101) -// l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, -// &l_owner_addr, l_fee_total, &l_fee_transfer); -// if (!l_list_fee_out) { -// log_it(L_WARNING, "Nothing to pay for fee (not enough funds)"); -// return NULL; -// } +// Freeze staker's funds when delegating a key +dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc_key_t *a_key, + uint256_t a_value, uint256_t a_fee, + dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, + dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, + dap_chain_datum_tx_t *a_prev_tx, int l_prev_tx_count, dap_pkey_t *a_pkey) +{ + dap_return_val_if_pass (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr, NULL); -// // create empty transaction -// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - -// if (!a_prev_tx) { -// dap_list_t *l_list_used_out = NULL ; -// if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_delegated_ticker, &l_owner_addr, &l_list_used_out, a_value, &l_value_transfer) == -101) -// l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_delegated_ticker, -// &l_owner_addr, a_value, &l_value_transfer); -// if (!l_list_used_out) { -// log_it(L_WARNING, "Nothing to pay for delegate (not enough funds)"); -// goto tx_fail; -// } -// // add 'in' items to pay for delegate -// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); -// dap_list_free_full(l_list_used_out, NULL); -// if (!EQUAL_256(l_value_to_items, l_value_transfer)) { -// log_it(L_ERROR, "Can't compose the transaction input"); -// goto tx_fail; -// } -// } else { -// dap_hash_fast_t l_prev_tx_hash; -// dap_hash_fast(a_prev_tx, dap_chain_datum_tx_get_size(a_prev_tx), &l_prev_tx_hash); -// int l_out_num = 0; -// dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); -// // add 'in' item to buy from conditional transaction -// if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_prev_tx_count, -1)) { -// log_it(L_ERROR, "Can't compose the transaction conditional input"); -// goto tx_fail; -// } -// } -// // add 'in' items to pay fee -// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); -// dap_list_free_full(l_list_fee_out, NULL); -// if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { -// log_it(L_ERROR, "Can't compose the fee transaction input"); -// goto tx_fail; -// } + const char *l_native_ticker = s_get_native_ticker(a_net_str); + char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; + dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker); + uint256_t l_value_transfer = {}, l_fee_transfer = {}; // how many coins to transfer + // list of transaction with 'out' items to sell + dap_chain_addr_t l_owner_addr; + dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str)); + uint256_t l_net_fee, l_fee_total = a_fee; + dap_chain_addr_t l_net_fee_addr; + bool l_net_fee_used = get_remote_net_fee(a_net_str, l_native_ticker, &l_net_fee, &l_net_fee_addr); + if (l_net_fee_used) + SUM_256_256(l_fee_total, l_net_fee, &l_fee_total); -// // add 'out_cond' & 'out_ext' items -// dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID }; -// dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_value, a_signing_addr, a_node_addr, -// a_sovereign_addr, a_sovereign_tax, a_pkey); + dap_list_t *l_list_fee_out = NULL; + if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101) + l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, + &l_owner_addr, l_fee_total, &l_fee_transfer); + if (!l_list_fee_out) { + log_it(L_WARNING, "Nothing to pay for fee (not enough funds)"); + return NULL; + } -// if (!l_tx_out) { -// log_it(L_ERROR, "Can't compose the transaction conditional output"); -// goto tx_fail; -// } -// dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); -// DAP_DELETE(l_tx_out); -// if (!a_prev_tx) { -// // coin back -// uint256_t l_value_back = {}; -// SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back); -// if (!IS_ZERO_256(l_value_back)) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) { -// log_it(L_ERROR, "Cant add coin back output"); -// goto tx_fail; -// } -// } -// } + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); -// // add fee items -// if (l_net_fee_used) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { -// log_it(L_ERROR, "Cant add net fee output"); -// goto tx_fail; -// } -// } -// if (!IS_ZERO_256(a_fee)) { -// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { -// log_it(L_ERROR, "Cant add validator fee output"); -// goto tx_fail; -// } -// } -// uint256_t l_fee_back = {}; -// // fee coin back -// SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back); -// if (!IS_ZERO_256(l_fee_back)) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) { -// log_it(L_ERROR, "Cant add fee back output"); -// goto tx_fail; -// } -// } + if (!a_prev_tx) { + dap_list_t *l_list_used_out = NULL ; + if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_delegated_ticker, &l_owner_addr, &l_list_used_out, a_value, &l_value_transfer) == -101) + l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_delegated_ticker, + &l_owner_addr, a_value, &l_value_transfer); + if (!l_list_used_out) { + log_it(L_WARNING, "Nothing to pay for delegate (not enough funds)"); + goto tx_fail; + } + // add 'in' items to pay for delegate + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + dap_list_free_full(l_list_used_out, NULL); + if (!EQUAL_256(l_value_to_items, l_value_transfer)) { + log_it(L_ERROR, "Can't compose the transaction input"); + goto tx_fail; + } + } else { + dap_hash_fast_t l_prev_tx_hash; + dap_hash_fast(a_prev_tx, dap_chain_datum_tx_get_size(a_prev_tx), &l_prev_tx_hash); + int l_out_num = 0; + dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); + // add 'in' item to buy from conditional transaction + if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_prev_tx_count, -1)) { + log_it(L_ERROR, "Can't compose the transaction conditional input"); + goto tx_fail; + } + } + // add 'in' items to pay fee + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + dap_list_free_full(l_list_fee_out, NULL); + if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { + log_it(L_ERROR, "Can't compose the fee transaction input"); + goto tx_fail; + } -// // add 'sign' item -// if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) { -// log_it(L_ERROR, "Can't add sign output"); -// goto tx_fail; -// } + // add 'out_cond' & 'out_ext' items + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID }; + dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_value, a_signing_addr, a_node_addr, + a_sovereign_addr, a_sovereign_tax, a_pkey); -// return l_tx; + if (!l_tx_out) { + log_it(L_ERROR, "Can't compose the transaction conditional output"); + goto tx_fail; + } + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); + DAP_DELETE(l_tx_out); + if (!a_prev_tx) { + // coin back + uint256_t l_value_back = {}; + SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) { + log_it(L_ERROR, "Cant add coin back output"); + goto tx_fail; + } + } + } -// tx_fail: -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } + // add fee items + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { + log_it(L_ERROR, "Cant add net fee output"); + goto tx_fail; + } + } + if (!IS_ZERO_256(a_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { + log_it(L_ERROR, "Cant add validator fee output"); + goto tx_fail; + } + } + uint256_t l_fee_back = {}; + // fee coin back + SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back); + if (!IS_ZERO_256(l_fee_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) { + log_it(L_ERROR, "Cant add fee back output"); + goto tx_fail; + } + } + + // add 'sign' item + if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) { + log_it(L_ERROR, "Can't add sign output"); + goto tx_fail; + } + + return l_tx; +tx_fail: + dap_chain_datum_tx_delete(l_tx); + return NULL; +} +*/ // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value> // int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) { diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 4fe3739f61..6f07efe7b2 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -44,7 +44,7 @@ typedef struct { } NetInfo; static NetInfo netinfo[NET_COUNT] = { - {"riemann", "tKEL", {.uint64 = 0x000000000000dddd}, "45.76.140.191", 8081}, + {"riemann", "tKEL", {.uint64 = 0x000000000000dddd}, "http://rpc.cellframe.net", 8081}, {"raiden", "tCELL", {.uint64 = 0x000000000000bbbb}, "http://rpc.cellframe.net", 8081}, {"KelVPN", "KEL", {.uint64 = 0x1807202300000000}, "http://rpc.cellframe.net", 8081}, {"Backbone", "CELL", {.uint64 = 0x0404202200000000}, "http://rpc.cellframe.net", 8081}, @@ -67,30 +67,38 @@ int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer); dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, - const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num); -dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy,const char *a_token_sell, - uint256_t a_datoshi_sell, uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet); + const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port); +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, const char *a_token_sell, uint256_t a_datoshi_sell, + uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port); dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, - const char *a_native_ticker, const char *a_net_name); + const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port); dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name, dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], uint256_t a_value, uint256_t a_value_per_unit_max, dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, uint256_t a_value_fee, const void *a_cond, - size_t a_cond_size); -bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee); -bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count); -dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, const char *a_main_ticker, - uint256_t a_value, uint256_t a_value_fee, dap_time_t a_time_staking, uint256_t a_reinvest_percent, - const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * l_chain_id_str); + size_t a_cond_size, const char *a_url_str, uint16_t a_port); +bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, const char * a_url_str, uint16_t a_port); +bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, + json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port); +dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, + const char *a_main_ticker, + uint256_t a_value, uint256_t a_value_fee, + dap_time_t a_time_staking, uint256_t a_reinvest_percent, + const char *a_delegated_ticker_str, uint256_t a_delegated_value, + const char * l_chain_id_str, const char *l_url_str, uint16_t l_port); bool check_token_in_ledger(json_object *l_json_coins, const char *a_token); -dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, - const char *a_main_ticker, uint256_t a_value, uint256_t a_value_fee, const char *a_delegated_ticker_str, uint256_t a_delegated_value); +dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, + dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, + const char *a_main_ticker, uint256_t a_value, + uint256_t a_value_fee, + const char *a_delegated_ticker_str, uint256_t a_delegated_value, + const char *l_url_str, uint16_t l_port); dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, - const char *a_net_str, const char *a_token_ticker); + const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port); #ifdef __cplusplus } -- GitLab From 9cdcc78bf87a463f744e7fac78b948152247319c Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Fri, 28 Mar 2025 12:21:18 +0700 Subject: [PATCH 26/53] [*] fix --- modules/compose/include/dap_chain_tx_compose.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 6f07efe7b2..d88f925cd2 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -44,7 +44,7 @@ typedef struct { } NetInfo; static NetInfo netinfo[NET_COUNT] = { - {"riemann", "tKEL", {.uint64 = 0x000000000000dddd}, "http://rpc.cellframe.net", 8081}, + {"riemann", "tKEL", {.uint64 = 0x000000000000dddd}, "45.76.140.191", 8081}, {"raiden", "tCELL", {.uint64 = 0x000000000000bbbb}, "http://rpc.cellframe.net", 8081}, {"KelVPN", "KEL", {.uint64 = 0x1807202300000000}, "http://rpc.cellframe.net", 8081}, {"Backbone", "CELL", {.uint64 = 0x0404202200000000}, "http://rpc.cellframe.net", 8081}, -- GitLab From 34a1b177b82e686d80facaa05d7fdc7992861764 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Fri, 28 Mar 2025 15:41:57 +0700 Subject: [PATCH 27/53] [*] invalidate --- dap-sdk | 2 +- modules/compose/dap_chain_tx_compose.c | 54 ++++++++++++++++---------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/dap-sdk b/dap-sdk index 5afcf73284..695db02acc 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit 5afcf7328475a0dfce4eb7630876cf1d79fa0329 +Subproject commit 695db02acc05add13e8ba75c13812148aaeb6e63 diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index f0dbdd845e..114103eb1f 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -2976,14 +2976,17 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c */ -/** +/** static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) { const char *l_net_str = NULL, *l_wallet_str = NULL, *l_cert_str = NULL, *l_fee_str = NULL, - *l_tx_hash_str = NULL; + *l_tx_hash_str = NULL, + *l_url_str = NULL, + *l_port_str = NULL; + uint16_t l_port = 0; int l_arg_index = 1; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); @@ -2991,6 +2994,14 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) printf("Command 'invalidate' requires parameter -net\n"); return -1; } + if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { + l_url_str = s_get_net_url(l_net_str); + } + if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { + l_port = atoi(l_port_str); + } else { + l_port = s_get_net_port(l_net_str); + } uint256_t l_fee = {}; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); @@ -3037,20 +3048,13 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) printf("Specified certificate is wrong\n"); return -6; } - } else { - dap_hash_fast_t l_pkey_hash = {}; - if (dap_chain_hash_fast_from_str(l_signing_pkey_hash_str, &l_pkey_hash)) { - printf("Invalid pkey hash format\n"); - return -7; - } - dap_chain_addr_fill(&l_signing_addr, dap_sign_type_from_str(l_signing_pkey_type_str), &l_pkey_hash, s_get_net_id(l_net_str)); } + const char *l_addr_str = dap_chain_addr_to_str_static(&l_signing_addr); - char data[512]; snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", l_net_str); - json_object *l_json_coins = s_request_command_to_rpc(data); + json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_coins) { printf("Error: Failed to retrieve coins from ledger\n"); return -4; @@ -3060,8 +3064,8 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) bool found = false; for (int i = 0; i < items_count; i++) { json_object *item = json_object_array_get_idx(l_json_coins, i); - const char *pkey_hash_str = json_object_get_string(json_object_object_get(item, "pkey_hash")); - if (l_signing_pkey_hash_str && !dap_strcmp(l_signing_pkey_hash_str, pkey_hash_str)) { + const char *node_addr_str = json_object_get_string(json_object_object_get(item, "node_addr")); + if (node_addr_str && !dap_strcmp(l_addr_str, node_addr_str)) { const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash")); if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) { printf("Invalid transaction hash format\n"); @@ -3072,7 +3076,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) } } if (!found) { - printf("Specified certificate/pkey hash is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n"); + printf("Specified address is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n"); return -9; } } @@ -3082,7 +3086,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str); - json_object *l_json_response = s_request_command_to_rpc(data); + json_object *l_json_response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_response) { printf("Error: Failed to retrieve transaction info from ledger\n"); return -4; @@ -3124,7 +3128,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash); snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str); - json_object *l_json_prev_tx = s_request_command_to_rpc(data); + json_object *l_json_prev_tx = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_prev_tx) { printf("Previous transaction %s is not found\n", l_tx_hash_str_tmp); return -12; @@ -3138,7 +3142,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", l_net_str); - json_object *l_json_coins = s_request_command_to_rpc(data); + json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_coins) { printf("Error: Failed to retrieve coins from ledger\n"); return -4; @@ -3165,7 +3169,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) l_sign_str = dap_chain_wallet_check_sign(l_wallet); } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); - l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key); + l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key, l_url_str, l_port); json_object * l_json_obj_ret = json_object_new_object(); dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); printf("%s", json_object_to_json_string(l_json_obj_ret)); @@ -3175,9 +3179,19 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) return 0; } -dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key) +dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port) { - + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + a_tx_hash, a_net_str); + + json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return -15; + } + dap_chain_datum_tx_t *l_cond_tx = NULL; dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash); -- GitLab From 5e77f4cdc6607f88e279f9a6b77c0df9d0628fef Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Mon, 31 Mar 2025 12:13:39 +0700 Subject: [PATCH 28/53] [+] need sign --- modules/net/dap_chain_node_cli_cmd_tx.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index d8d718c9e7..eac3b5e6ec 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -1104,6 +1104,8 @@ int com_ledger(int a_argc, char ** a_argv, void **reply) dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hash", &l_tx_hash_str); //get net dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); + const char * l_need_sign; + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-need_sign", &l_need_sign); //get search type bool l_unspent_flag = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-unspent", NULL); //check input @@ -1140,6 +1142,21 @@ int com_ledger(int a_argc, char ** a_argv, void **reply) DAP_DEL_Z(l_tx_hash); return DAP_CHAIN_NODE_CLI_COM_LEDGER_TX_HASH_ERR; } + if (l_need_sign) { + byte_t *item; size_t l_size; + TX_ITEM_ITER_TX(item, l_size, l_datum_tx) { + if (*item == TX_ITEM_TYPE_SIG) { + json_object *json_obj_item = json_object_new_object(); + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t*)item); + char *l_sign_b64 = DAP_NEW_Z_SIZE(char, DAP_ENC_BASE64_ENCODE_SIZE(dap_sign_get_size(l_sign)) + 1); + size_t l_sign_size = dap_sign_get_size(l_sign); + dap_enc_base64_encode(l_sign, l_sign_size, l_sign_b64, DAP_ENC_DATA_TYPE_B64_URLSAFE); + json_object_object_add(json_obj_item, "sig_b64_size", json_object_new_uint64(l_sign_size)); + json_object_object_add(json_obj_item, "sig_b64", json_object_new_string(l_sign_b64)); + json_object_array_add(json_datum, json_obj_item); + } + } + } DAP_DEL_Z(l_tx_hash); if (json_datum){ json_object_array_add(*a_json_arr_reply, json_datum); -- GitLab From e8a430db05a4df3d463757ace9a2404c2bbe6f0c Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Mon, 31 Mar 2025 16:38:54 +0700 Subject: [PATCH 29/53] [+] invalidate --- dap-sdk | 2 +- modules/compose/dap_chain_tx_compose.c | 202 +++++++++++++----- .../compose/include/dap_chain_tx_compose.h | 2 + modules/net/dap_chain_node_cli_cmd_tx.c | 24 ++- 4 files changed, 161 insertions(+), 69 deletions(-) diff --git a/dap-sdk b/dap-sdk index 695db02acc..e303f12da9 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit 695db02acc05add13e8ba75c13812148aaeb6e63 +Subproject commit e303f12da9e8a8b632e296e8897319b952837a62 diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 114103eb1f..ef7a8fc4f3 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -35,6 +35,7 @@ #include "dap_json_rpc.h" #include "dap_app_cli_net.h" #include "dap_cli_server.h" +#include "dap_enc_base64.h" #include <netdb.h> #include <json-c/json.h> @@ -289,12 +290,12 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a printf("Error %d: %s\n", json_object_get_int(error_code), json_object_get_string(error_message)); } } - json_object_put(l_result); l_result = NULL; } } s_cmd_request_free(l_cmd_request); - json_object_get(l_result); + if (l_result) + json_object_get(l_result); json_object_put(l_response); return l_result; } @@ -2152,6 +2153,10 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_na } json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, a_net_name, &l_addr, l_url_str, l_port); + if (!l_outs_delegated) { + return NULL; + } + int l_out_native_count = json_object_array_length(l_outs_native); int l_out_delegated_count = json_object_array_length(l_outs_delegated); @@ -2976,8 +2981,8 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c */ -/** -static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) + +int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) { const char *l_net_str = NULL, *l_wallet_str = NULL, @@ -2994,13 +2999,28 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) printf("Command 'invalidate' requires parameter -net\n"); return -1; } - if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { l_url_str = s_get_net_url(l_net_str); } - if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { + l_port = s_get_net_port(l_net_str); + } else { l_port = atoi(l_port_str); + } + + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + arg_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif } else { - l_port = s_get_net_port(l_net_str); + arg_wallets_path = dap_strdup(l_wallet_path); } uint256_t l_fee = {}; @@ -3085,14 +3105,15 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str); + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str); json_object *l_json_response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_response) { printf("Error: Failed to retrieve transaction info from ledger\n"); return -4; } - json_object *l_json_items = json_object_object_get(l_json_response, "ITEMS"); + json_object *l_json_items = json_object_array_get_idx(l_json_response, 0); + l_json_items = json_object_object_get(l_json_items, "ITEMS"); bool has_delegate_out = false; if (l_json_items) { int items_count = json_object_array_length(l_json_items); @@ -3111,6 +3132,7 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) if (!has_delegate_out) { printf("Transaction %s does not have a delegate out\n", l_tx_hash_str_tmp); + json_object_put(l_json_response); return -11; } @@ -3160,13 +3182,11 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) } } dap_chain_datum_tx_t *l_tx = NULL; - const char* l_sign_str = ""; - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config),NULL); + + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path,NULL); if (!l_wallet) { printf("Specified wallet not found\n"); return -14; - } else { - l_sign_str = dap_chain_wallet_check_sign(l_wallet); } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key, l_url_str, l_port); @@ -3180,52 +3200,102 @@ static int s_cli_srv_stake_invalidate(int a_argc, char **a_argv) } dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port) -{ +{ char data[512]; snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", - a_tx_hash, a_net_str); + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-need_sign;-hash;%s;-net;%s\"],\"id\": \"1\"}", + dap_hash_fast_to_str_static(a_tx_hash), a_net_str); json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); - return -15; + return NULL; } - dap_chain_datum_tx_t *l_cond_tx = NULL; - - dap_chain_datum_tx_t *l_cond_tx = - dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash); - if (!l_cond_tx) { - printf("Requested conditional transaction not found\n"); + json_object *l_items_array = json_object_array_get_idx(response, 0); + l_items_array = json_object_object_get(l_items_array, "ITEMS"); + if (!l_items_array) { + printf("Error: ITEMS array not found in JSON response\n"); return NULL; } + + json_object *l_unspent_outs = json_object_object_get(response, "all OUTs yet unspent"); + if (l_unspent_outs) { + const char *all_unspent = json_object_get_string(l_unspent_outs); + if (all_unspent && strcmp(all_unspent, "yes") == 0) { + printf("Error: All outputs are spent\n"); + json_object_put(response); + return NULL; + } + } + + dap_chain_tx_out_cond_t *l_tx_out_cond = NULL; + const char * l_tx_prev_hash = NULL; int l_prev_cond_idx = 0; - dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, - DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_prev_cond_idx); - if (!l_tx_out_cond) { - printf("Requested conditional transaction requires conditional output\n"); - return NULL; + + size_t items_count = json_object_array_length(l_items_array); + for (size_t i = 0; i < items_count; i++) { + json_object *l_item = json_object_array_get_idx(l_items_array, i); + const char *item_type = json_object_get_string(json_object_object_get(l_item, "item type")); + + if (item_type && strcmp(item_type, "OUT COND") == 0) { + l_tx_out_cond = DAP_NEW_Z(dap_chain_tx_out_cond_t); + l_tx_out_cond->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE; + l_tx_out_cond->header.value = dap_uint256_scan_uninteger(json_object_get_string(json_object_object_get(l_item, "value"))); + } else if (item_type && strcmp(item_type, "IN COND") == 0) { + l_tx_prev_hash = json_object_get_string(json_object_object_get(l_item, "Tx_prev_hash")); + if (!l_tx_prev_hash) { + printf("Error: Tx_prev_hash not found in ITEMS array\n"); + return NULL; + } + l_prev_cond_idx = json_object_get_int(json_object_object_get(l_item, "Tx_out_prev_idx")); + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + l_tx_prev_hash, a_net_str); + + json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + if (!response) { + printf("Error: Request conditional transaction failed\n"); + return NULL; + } + } } - dap_hash_fast_t l_spender_hash = { }; - if (dap_ledger_tx_hash_is_used_out_item(l_ledger, a_tx_hash, l_prev_cond_idx, &l_spender_hash)) { - char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; - dap_chain_hash_fast_to_str(&l_spender_hash, l_hash_str, sizeof(l_hash_str)); - printf("Requested conditional transaction is already used out by %s\n", l_hash_str); + + if (!l_tx_out_cond || !l_tx_prev_hash) { + printf("Error: Required conditional transaction structures not found\n"); return NULL; } - dap_chain_tx_in_cond_t *l_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(l_cond_tx, NULL, NULL, TX_ITEM_TYPE_IN_COND, NULL); - if (l_in_cond) { - l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, &l_in_cond->header.tx_prev_hash); - if (!l_cond_tx) { - printf("Requested conditional transaction is unchained\n"); - return NULL; + + json_object *l_sig_item = NULL; + for (size_t i = 0; i < items_count; i++) { + json_object *l_item = json_object_array_get_idx(l_items_array, i); + const char *item_type = json_object_get_string(json_object_object_get(l_item, "item type")); + if (item_type && strcmp(item_type, "SIG") == 0) { + l_sig_item = l_item; + break; } } - // Get sign item - dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(l_cond_tx, NULL, NULL, - TX_ITEM_TYPE_SIG, NULL); - // Get sign from sign item - // TODO Can't get sign from sign item required new command for remote node + + if (!l_sig_item) { + printf("Error: SIG item not found in ITEMS array\n"); + return NULL; + } + + const char *l_sign_b64_str = json_object_get_string(json_object_object_get(l_sig_item, "sig_b64")); + if (!l_sign_b64_str) { + printf("Error: Can't get base64-encoded sign from SIG item\n"); + return NULL; + } + + int64_t l_sign_b64_strlen = json_object_get_string_len(json_object_object_get(l_sig_item, "sig_b64")); + int64_t l_sign_decoded_size = DAP_ENC_BASE64_DECODE_SIZE(l_sign_b64_strlen); + dap_chain_tx_sig_t *l_tx_sig = DAP_NEW_Z_SIZE(dap_chain_tx_sig_t, sizeof(dap_chain_tx_sig_t) + l_sign_decoded_size); + *l_tx_sig = (dap_chain_tx_sig_t) { + .header = { + .type = TX_ITEM_TYPE_SIG, .version = 1, + .sig_size = dap_enc_base64_decode(l_sign_b64_str, l_sign_b64_strlen, l_tx_sig->sig, DAP_ENC_DATA_TYPE_B64_URLSAFE) + } + }; + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); dap_chain_addr_t l_owner_addr; dap_chain_addr_fill_from_sign(&l_owner_addr, l_sign, s_get_net_id(a_net_str)); @@ -3235,21 +3305,41 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap printf("Trying to invalidate delegating tx with not a owner wallet\n"); return NULL; } + const char *l_native_ticker = s_get_native_ticker(a_net_str); - const char *l_delegated_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, a_tx_hash); + + json_object *l_json_tiker = json_object_array_get_idx(response, 0); + json_object *token_ticker_obj = json_object_object_get(l_json_tiker, "Token_ticker"); + if (!token_ticker_obj) { + token_ticker_obj = json_object_object_get(l_json_tiker, "token ticker"); + if (!token_ticker_obj) { + printf("Error: Token ticker not found in response\n"); + json_object_put(response); + return NULL; + } + } + const char *l_delegated_ticker = json_object_get_string(token_ticker_obj); + + json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); + if (!l_outs_native) { + return NULL; + } + + int l_out_native_count = json_object_array_length(l_outs_native); uint256_t l_fee_transfer = {}; // how many coins to transfer // list of transaction with 'out' items to sell uint256_t l_net_fee, l_fee_total = a_fee; - dap_chain_addr_t l_net_fee_addr; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(s_get_net_id(a_net_str), &l_net_fee, &l_net_fee_addr); + dap_chain_addr_t*l_net_fee_addr = NULL; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_net_fee_addr, l_url_str, l_port); if (l_net_fee_used) SUM_256_256(l_fee_total, l_net_fee, &l_fee_total); dap_list_t *l_list_fee_out = NULL; - if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101) - l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, - &l_owner_addr, l_fee_total, &l_fee_transfer); + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, + l_fee_total, + &l_fee_transfer); if (!l_list_fee_out) { - printf("Nothing to pay for fee (not enough funds)\n"); + printf("Not enough funds to pay fee"); + json_object_put(l_outs_native); return NULL; } @@ -3276,7 +3366,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap } // add fee items if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { dap_chain_datum_tx_delete(l_tx); return NULL; } @@ -3296,15 +3386,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap return NULL; } } - // add 'sign' items - if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Can't add sign output\n"); - return NULL; - } return l_tx; } -*/ + /** dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){ dap_chain_net_srv_order_t* l_order = NULL; diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index d88f925cd2..74773d5440 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -62,6 +62,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv); int dap_cli_hold_compose(int a_argc, char **a_argv); int dap_cli_take_compose(int a_argc, char **a_argv); int dap_cli_voting_compose(int a_argc, char **a_argv); +int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv); int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); @@ -99,6 +100,7 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port); +dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port); #ifdef __cplusplus } diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index eac3b5e6ec..b56cb4bcc6 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -46,6 +46,7 @@ #include "dap_chain_mempool.h" #include "dap_math_convert.h" #include "dap_json_rpc_errors.h" +#include "dap_enc_base64.h" #include "dap_chain_wallet_cache.h" @@ -1100,13 +1101,9 @@ int com_ledger(int a_argc, char ** a_argv, void **reply) } return 0; } else if (l_cmd == CMD_TX_INFO){ - //GET hash dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hash", &l_tx_hash_str); - //get net dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); - const char * l_need_sign; - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-need_sign", &l_need_sign); - //get search type + bool l_need_sign = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-need_sign", NULL); bool l_unspent_flag = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-unspent", NULL); //check input if (l_tx_hash_str == NULL){ @@ -1146,14 +1143,23 @@ int com_ledger(int a_argc, char ** a_argv, void **reply) byte_t *item; size_t l_size; TX_ITEM_ITER_TX(item, l_size, l_datum_tx) { if (*item == TX_ITEM_TYPE_SIG) { - json_object *json_obj_item = json_object_new_object(); dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t*)item); char *l_sign_b64 = DAP_NEW_Z_SIZE(char, DAP_ENC_BASE64_ENCODE_SIZE(dap_sign_get_size(l_sign)) + 1); size_t l_sign_size = dap_sign_get_size(l_sign); dap_enc_base64_encode(l_sign, l_sign_size, l_sign_b64, DAP_ENC_DATA_TYPE_B64_URLSAFE); - json_object_object_add(json_obj_item, "sig_b64_size", json_object_new_uint64(l_sign_size)); - json_object_object_add(json_obj_item, "sig_b64", json_object_new_string(l_sign_b64)); - json_object_array_add(json_datum, json_obj_item); + + json_object *json_items = json_object_object_get(json_datum, "ITEMS"); + if (json_items && json_object_is_type(json_items, json_type_array)) { + int array_len = json_object_array_length(json_items); + for (int i = 0; i < array_len; i++) { + json_object *item = json_object_array_get_idx(json_items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (item_type && strcmp(item_type, "SIG") == 0) { + json_object_object_add(item, "sig_b64", json_object_new_string(l_sign_b64)); + json_object_object_add(item, "sig_b64_size", json_object_new_uint64(l_sign_size)); + } + } + } } } } -- GitLab From bd03ccda6747fb7c8d3438e7ee75270f54c2ba90 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Mon, 31 Mar 2025 16:48:21 +0700 Subject: [PATCH 30/53] [*] fix --- modules/compose/dap_chain_tx_compose.c | 66 ++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index ef7a8fc4f3..f26d40dac2 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -2981,7 +2981,6 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c */ - int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) { const char *l_net_str = NULL, @@ -3089,12 +3088,14 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash")); if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) { printf("Invalid transaction hash format\n"); + json_object_put(l_json_coins); return -8; } found = true; break; } } + json_object_put(l_json_coins); if (!found) { printf("Specified address is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n"); return -9; @@ -3145,6 +3146,7 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) if (spent_by_tx) { if (dap_chain_hash_fast_from_str(spent_by_tx, &l_tx_hash)) { printf("Invalid transaction hash format in response\n"); + json_object_put(l_json_response); return -8; } l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash); @@ -3153,8 +3155,10 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) json_object *l_json_prev_tx = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_prev_tx) { printf("Previous transaction %s is not found\n", l_tx_hash_str_tmp); + json_object_put(l_json_response); return -12; } + json_object_put(l_json_prev_tx); break; } } @@ -3167,25 +3171,30 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_coins) { printf("Error: Failed to retrieve coins from ledger\n"); + json_object_put(l_json_response); return -4; } bool tx_exists = false; int tx_count = json_object_array_length(l_json_coins); for (int i = 0; i < tx_count; i++) { - json_object *tx_item = json_object_array_get_idx(l_json_items, i); + json_object *tx_item = json_object_array_get_idx(l_json_coins, i); const char *tx_hash = json_object_get_string(json_object_object_get(tx_item, "tx_hash")); if (tx_hash && strcmp(tx_hash, l_tx_hash_str_tmp) == 0) { printf("Error: Transaction %s already exists in the ledger\n", l_tx_hash_str_tmp); + json_object_put(l_json_coins); + json_object_put(l_json_response); return -13; } } + json_object_put(l_json_coins); } dap_chain_datum_tx_t *l_tx = NULL; dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path,NULL); if (!l_wallet) { printf("Specified wallet not found\n"); + json_object_put(l_json_response); return -14; } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); @@ -3196,9 +3205,11 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) json_object_put(l_json_obj_ret); dap_chain_wallet_close(l_wallet); dap_enc_key_delete(l_enc_key); + json_object_put(l_json_response); return 0; } + dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port) { char data[512]; @@ -3215,6 +3226,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap l_items_array = json_object_object_get(l_items_array, "ITEMS"); if (!l_items_array) { printf("Error: ITEMS array not found in JSON response\n"); + json_object_put(response); return NULL; } @@ -3245,6 +3257,8 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap l_tx_prev_hash = json_object_get_string(json_object_object_get(l_item, "Tx_prev_hash")); if (!l_tx_prev_hash) { printf("Error: Tx_prev_hash not found in ITEMS array\n"); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); return NULL; } l_prev_cond_idx = json_object_get_int(json_object_object_get(l_item, "Tx_out_prev_idx")); @@ -3252,16 +3266,21 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_prev_hash, a_net_str); - json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port); - if (!response) { + json_object *response_cond = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + if (!response_cond) { printf("Error: Request conditional transaction failed\n"); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); return NULL; } + json_object_put(response_cond); } } if (!l_tx_out_cond || !l_tx_prev_hash) { printf("Error: Required conditional transaction structures not found\n"); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); return NULL; } @@ -3277,12 +3296,16 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!l_sig_item) { printf("Error: SIG item not found in ITEMS array\n"); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); return NULL; } const char *l_sign_b64_str = json_object_get_string(json_object_object_get(l_sig_item, "sig_b64")); if (!l_sign_b64_str) { printf("Error: Can't get base64-encoded sign from SIG item\n"); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); return NULL; } @@ -3303,6 +3326,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap dap_chain_addr_fill_from_key(&l_wallet_addr, a_key, s_get_net_id(a_net_str)); if (!dap_chain_addr_compare(&l_owner_addr, &l_wallet_addr)) { printf("Trying to invalidate delegating tx with not a owner wallet\n"); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); + DAP_DELETE(l_tx_sig); return NULL; } @@ -3315,6 +3341,8 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!token_ticker_obj) { printf("Error: Token ticker not found in response\n"); json_object_put(response); + DAP_DELETE(l_tx_out_cond); + DAP_DELETE(l_tx_sig); return NULL; } } @@ -3322,6 +3350,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); if (!l_outs_native) { + json_object_put(response); + DAP_DELETE(l_tx_out_cond); + DAP_DELETE(l_tx_sig); return NULL; } @@ -3340,6 +3371,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!l_list_fee_out) { printf("Not enough funds to pay fee"); json_object_put(l_outs_native); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); + DAP_DELETE(l_tx_sig); return NULL; } @@ -3355,6 +3389,10 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { printf("Can't compose the transaction input\n"); dap_chain_datum_tx_delete(l_tx); + json_object_put(l_outs_native); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); + DAP_DELETE(l_tx_sig); return NULL; } @@ -3362,18 +3400,30 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_tx_out_cond->header.value, l_delegated_ticker) == -1) { dap_chain_datum_tx_delete(l_tx); printf("Cant add returning coins output\n"); + json_object_put(l_outs_native); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); + DAP_DELETE(l_tx_sig); return NULL; } // add fee items if (l_net_fee_used) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { dap_chain_datum_tx_delete(l_tx); + json_object_put(l_outs_native); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); + DAP_DELETE(l_tx_sig); return NULL; } } if (!IS_ZERO_256(a_fee)) { if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { dap_chain_datum_tx_delete(l_tx); + json_object_put(l_outs_native); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); + DAP_DELETE(l_tx_sig); return NULL; } } @@ -3383,9 +3433,17 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if(!IS_ZERO_256(l_fee_back)) { if(dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) { dap_chain_datum_tx_delete(l_tx); + json_object_put(l_outs_native); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); + DAP_DELETE(l_tx_sig); return NULL; } } + json_object_put(l_outs_native); + json_object_put(response); + DAP_DELETE(l_tx_out_cond); + DAP_DELETE(l_tx_sig); return l_tx; } -- GitLab From 6d06dafa226b82e4078eb2417aae3080bed01b51 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Tue, 1 Apr 2025 17:55:39 +0700 Subject: [PATCH 31/53] [+] srv_stake delegate --- modules/compose/dap_chain_tx_compose.c | 203 ++++++++++-------- .../compose/include/dap_chain_tx_compose.h | 6 + 2 files changed, 124 insertions(+), 85 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index f26d40dac2..e64e75107b 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -36,6 +36,8 @@ #include "dap_app_cli_net.h" #include "dap_cli_server.h" #include "dap_enc_base64.h" +#include "dap_chain_net_srv_order.h" +#include "dap_chain_net_srv_stake_pos_delegate.h" #include <netdb.h> #include <json-c/json.h> @@ -3447,8 +3449,19 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap return l_tx; } -/** -dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){ +dap_chain_net_srv_order_direction_t dap_chain_net_srv_order_direction_from_str(const char* str) { + dap_chain_net_srv_order_direction_t direction = SERV_DIR_UNDEFINED; + if (strcmp(str, "BUY") == 0) { + direction = SERV_DIR_BUY; + } else if (strcmp(str, "SELL") == 0) { + direction = SERV_DIR_SELL; + } + return direction; +} + + +dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, + uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){ dap_chain_net_srv_order_t* l_order = NULL; json_object *orders_array = json_object_array_get_idx(response, 0); size_t orders_count = json_object_array_length(orders_array); @@ -3460,14 +3473,17 @@ dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, con l_order = DAP_NEW_Z_SIZE(dap_chain_net_srv_order_t, sizeof(dap_chain_net_srv_order_t)); l_order->version = json_object_get_int(json_object_object_get(order_obj, "version")); l_order->direction = dap_chain_net_srv_order_direction_from_str(json_object_get_string(json_object_object_get(order_obj, "direction"))); - l_order->ts_created = dap_time_from_str(json_object_get_string(json_object_object_get(order_obj, "created"))); + l_order->ts_created = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(order_obj, "created"))); l_order->srv_uid.uint64 = dap_chain_net_srv_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "srv_uid"))).uint64; l_order->price = dap_uint256_scan_uninteger(json_object_get_string(json_object_object_get(order_obj, "price datoshi"))); strncpy(l_order->price_ticker, json_object_get_string(json_object_object_get(order_obj, "price token")), DAP_CHAIN_TICKER_SIZE_MAX); l_order->units = json_object_get_int(json_object_object_get(order_obj, "units")); l_order->price_unit = dap_chain_net_srv_price_unit_uid_from_str(json_object_get_string(json_object_object_get(order_obj, "price unit"))); dap_chain_node_addr_from_str(&l_order->node_addr, json_object_get_string(json_object_object_get(order_obj, "node_addr"))); - dap_chain_hash_fast_from_str(&l_order->tx_cond_hash, json_object_get_string(json_object_object_get(order_obj, "tx_cond_hash"))); + const char *tx_cond_hash_str = json_object_get_string(json_object_object_get(order_obj, "tx_cond_hash")); + if (tx_cond_hash_str) { + dap_chain_hash_fast_from_str(tx_cond_hash_str, &l_order->tx_cond_hash); + } l_order->ext_size = json_object_get_int(json_object_object_get(order_obj, "ext_size")); if (l_order->ext_size > 0) { const char *tax_str = json_object_get_string(json_object_object_get(order_obj, "tax")); @@ -3489,12 +3505,14 @@ dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, con return l_order; } -dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax){ +dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, + uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, + const char* l_url_str, uint16_t l_port){ char data[512]; snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", l_net_str); - json_object *response = s_request_command_to_rpc(data); + json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return NULL; @@ -3507,7 +3525,7 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", l_net_str); - response = s_request_command_to_rpc(data); + response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return NULL; @@ -3521,7 +3539,7 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const -static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) +int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) { int l_arg_index = 0; const char *l_net_str = NULL, @@ -3533,16 +3551,43 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) *l_value_str = NULL, *l_fee_str = NULL, *l_node_addr_str = NULL, - *l_order_hash_str = NULL; + *l_order_hash_str = NULL, + *l_url_str = NULL, + *l_port_str = NULL; + int l_port = 0; dap_pkey_t *l_pkey = NULL; - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-net", &l_net_str); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); if (!l_net_str) { printf("Command 'delegate' requires parameter -net\n"); return -1; } - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-w", &l_wallet_str); + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { + l_url_str = s_get_net_url(l_net_str); + } + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { + l_port = s_get_net_port(l_net_str); + } else { + l_port = atoi(l_port_str); + } + + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + arg_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif + } else { + arg_wallets_path = dap_strdup(l_wallet_path); + } + + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); if (!l_wallet_str) { printf("Command 'delegate' requires parameter -w\n"); return -1; @@ -3556,10 +3601,10 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) dap_chain_wallet_close(l_wallet); dap_chain_addr_t l_signing_addr, l_sovereign_addr = {}; uint256_t l_sovereign_tax = uint256_0; - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-cert", &l_cert_str); - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str); - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-sign_type", &l_sign_type_str); - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-order", &l_order_hash_str); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-sign_type", &l_sign_type_str); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str); if (!l_cert_str && !l_order_hash_str && !l_pkey_full_str) { printf("Command 'delegate' requires parameter -cert and/or -order and/or -pkey\n"); dap_enc_key_delete(l_enc_key); @@ -3576,7 +3621,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) return -1; } uint256_t l_value = uint256_0; - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-value", &l_value_str); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); if (!l_value_str) { if (!l_order_hash_str) { printf("Command 'delegate' requires parameter -value\n"); @@ -3605,9 +3650,8 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) return -4; } l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key); - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str); - } - else if (l_pkey_full_str) { + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str); + } else if (l_pkey_full_str) { dap_sign_type_t l_type = dap_sign_type_from_str(l_sign_type_str); if (l_type.type == SIG_TYPE_NULL) { printf("Wrong sign type\n"); @@ -3632,7 +3676,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) return -6; } dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(l_net_str)); - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-node_addr", &l_node_addr_str); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str); } dap_chain_node_addr_t l_node_addr = g_node_addr; @@ -3647,7 +3691,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) uint256_t l_tax; uint256_t l_value_max; int l_prev_tx_count = 0; - dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax); + dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, l_url_str, l_port); if (l_order->direction == SERV_DIR_BUY) { // Staker order if (!l_cert_str) { @@ -3666,9 +3710,9 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", - l_order->tx_cond_hash, l_net_str); + dap_chain_hash_fast_to_str_static(&l_order->tx_cond_hash), l_net_str); - json_object *response = s_request_command_to_rpc(data); + json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return -15; @@ -3691,7 +3735,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE; l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); - l_cond_tx->header.ts_expires = dap_time_from_str(json_object_get_string(json_object_object_get(item, "ts_expires"))); + l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr"))); if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) { printf("Error: Failed to parse signer node address\n"); @@ -3717,30 +3761,6 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) return -9; } - - - l_prev_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash); - if (!l_prev_tx) { - printf("The order's conditional transaction not found in ledger\n"); - dap_enc_key_delete(l_enc_key); - DAP_DELETE(l_order); - return -10; - } - int l_out_num = 0; - dap_chain_tx_out_cond_t *l_cond_tx = dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); - if (!l_cond) { - printf("The order's conditional transaction has invalid type\n"); - dap_enc_key_delete(l_enc_key); - DAP_DELETE(l_order); - return -11; - } - if (dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_order->tx_cond_hash, l_out_num, NULL)) { - printf("The order's conditional transaction is already spent\n"); - dap_enc_key_delete(l_enc_key); - DAP_DELETE(l_order); - return -12; - } - char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(l_net_str)); const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker")); @@ -3773,10 +3793,6 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) return -16; } l_value = l_order->price; - // dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR); - // l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE); - // l_sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t); - // MULT_256_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); } else { if (!l_value_str) { printf("Command 'delegate' requires parameter -value with this order type\n"); @@ -3784,7 +3800,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) return -1; } const char *l_sovereign_addr_str = NULL; - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str); if (l_sovereign_addr_str) { dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str); if (!l_spec_addr) { @@ -3819,10 +3835,10 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) DAP_DELETE(l_order); return -20; } - dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_net->pub.id); + dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, s_get_net_id(l_net_str)); l_pkey = dap_pkey_get_from_sign(l_sign); char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX]; - dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_net->pub.native_ticker); + dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, s_get_native_ticker(l_net_str)); if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) { printf("Specified order is invalid\n"); dap_enc_key_delete(l_enc_key); @@ -3854,7 +3870,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) } - uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str); + uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str, l_url_str, l_port); if (compare256(l_value, l_allowed_min) == -1) { const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str); printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n", @@ -3862,7 +3878,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) dap_enc_key_delete(l_enc_key); return -23; } - dap_cli_server_cmd_find_option_val(a_argv, &l_arg_index, a_argc, "-fee", &l_fee_str); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); if (!l_fee_str) { printf("Command 'delegate' requires parameter -fee\n"); dap_enc_key_delete(l_enc_key); @@ -3877,7 +3893,7 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) // Create conditional transaction dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr, - l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_prev_tx_count, l_pkey); + l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, l_url_str, l_port); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_pkey); @@ -3888,14 +3904,14 @@ static int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) } // Freeze staker's funds when delegating a key -dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc_key_t *a_key, +static dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, - dap_chain_datum_tx_t *a_prev_tx, int l_prev_tx_count, dap_pkey_t *a_pkey) + dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port) { - dap_return_val_if_pass (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr, NULL); - + if (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) + return NULL; const char *l_native_ticker = s_get_native_ticker(a_net_str); char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker); @@ -3904,17 +3920,34 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc dap_chain_addr_t l_owner_addr; dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str)); uint256_t l_net_fee, l_fee_total = a_fee; - dap_chain_addr_t l_net_fee_addr; - bool l_net_fee_used = get_remote_net_fee(a_net_str, l_native_ticker, &l_net_fee, &l_net_fee_addr); + dap_chain_addr_t * l_net_fee_addr = NULL; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, l_net_fee_addr, l_url_str, l_port); if (l_net_fee_used) SUM_256_256(l_fee_total, l_net_fee, &l_fee_total); dap_list_t *l_list_fee_out = NULL; - if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, &l_owner_addr, &l_list_fee_out, l_fee_total, &l_fee_transfer) == -101) - l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, - &l_owner_addr, l_fee_total, &l_fee_transfer); + + + json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); + if (!l_outs_native) { + return NULL; + } + + json_object *l_outs_delegated = dap_get_remote_tx_outs(l_delegated_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); + if (!l_outs_delegated) { + return NULL; + } + + int l_out_native_count = json_object_array_length(l_outs_native); + int l_out_delegated_count = json_object_array_length(l_outs_delegated); + + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, + l_fee_total, + &l_fee_transfer); if (!l_list_fee_out) { - log_it(L_WARNING, "Nothing to pay for fee (not enough funds)"); + printf("Not enough funds to pay fee"); + json_object_put(l_outs_native); + json_object_put(l_outs_delegated); return NULL; } @@ -3922,19 +3955,20 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); if (!a_prev_tx) { - dap_list_t *l_list_used_out = NULL ; - if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_delegated_ticker, &l_owner_addr, &l_list_used_out, a_value, &l_value_transfer) == -101) - l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_delegated_ticker, - &l_owner_addr, a_value, &l_value_transfer); + dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count, + a_value, + &l_value_transfer); if (!l_list_used_out) { - log_it(L_WARNING, "Nothing to pay for delegate (not enough funds)"); - goto tx_fail; + printf("Not enough funds to pay fee"); + json_object_put(l_outs_native); + json_object_put(l_outs_delegated); + return NULL; } // add 'in' items to pay for delegate uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); dap_list_free_full(l_list_used_out, NULL); if (!EQUAL_256(l_value_to_items, l_value_transfer)) { - log_it(L_ERROR, "Can't compose the transaction input"); + printf("Can't compose the transaction input\n"); goto tx_fail; } } else { @@ -3943,8 +3977,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc int l_out_num = 0; dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); // add 'in' item to buy from conditional transaction - if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_prev_tx_count, -1)) { - log_it(L_ERROR, "Can't compose the transaction conditional input"); + if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_out_num, -1)) { + printf("Can't compose the transaction conditional input\n"); goto tx_fail; } } @@ -3952,7 +3986,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); dap_list_free_full(l_list_fee_out, NULL); if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { - log_it(L_ERROR, "Can't compose the fee transaction input"); + printf("Can't compose the fee transaction input\n"); goto tx_fail; } @@ -3962,7 +3996,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc a_sovereign_addr, a_sovereign_tax, a_pkey); if (!l_tx_out) { - log_it(L_ERROR, "Can't compose the transaction conditional output"); + printf("Can't compose the transaction conditional output\n"); goto tx_fail; } dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); @@ -3973,7 +4007,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back); if (!IS_ZERO_256(l_value_back)) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) { - log_it(L_ERROR, "Cant add coin back output"); + printf("Cant add coin back output\n"); goto tx_fail; } } @@ -3982,13 +4016,13 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc // add fee items if (l_net_fee_used) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { - log_it(L_ERROR, "Cant add net fee output"); + printf("Cant add net fee output\n"); goto tx_fail; } } if (!IS_ZERO_256(a_fee)) { if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { - log_it(L_ERROR, "Cant add validator fee output"); + printf("Cant add validator fee output\n"); goto tx_fail; } } @@ -3997,14 +4031,14 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char *a_net_str, dap_enc SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back); if (!IS_ZERO_256(l_fee_back)) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) { - log_it(L_ERROR, "Cant add fee back output"); + printf("Cant add fee back output\n"); goto tx_fail; } } // add 'sign' item if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) { - log_it(L_ERROR, "Can't add sign output"); + printf("Can't add sign output\n"); goto tx_fail; } @@ -4014,7 +4048,6 @@ tx_fail: dap_chain_datum_tx_delete(l_tx); return NULL; } -*/ // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value> // int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) { diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 74773d5440..e8bf8ab3bd 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -63,6 +63,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv); int dap_cli_take_compose(int a_argc, char **a_argv); int dap_cli_voting_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv); +int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv); int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); @@ -101,6 +102,11 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port); dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port); +static dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, + uint256_t a_value, uint256_t a_fee, + dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, + dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, + dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port); #ifdef __cplusplus } -- GitLab From 6fa0a995905fa63b60d2cf9df926204a37b2f287 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Wed, 2 Apr 2025 12:47:02 +0700 Subject: [PATCH 32/53] [*] dap_request_command_to_rpc --- modules/compose/dap_chain_tx_compose.c | 99 +++++++++++++------ .../compose/include/dap_chain_tx_compose.h | 4 +- 2 files changed, 70 insertions(+), 33 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index e64e75107b..bb14cf0ec5 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -42,7 +42,6 @@ #include <netdb.h> #include <json-c/json.h> -static json_object* s_request_command_to_rpc(const char *a_request, const char * a_net_name, const char * a_url_str, uint16_t a_port); const char *arg_wallets_path = NULL; @@ -259,9 +258,14 @@ static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_ob static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) { json_object * l_response = NULL; - size_t l_response_size; + size_t l_response_size = 0; // Initialize to avoid potential undefined behavior struct cmd_request* l_cmd_request = s_cmd_request_init(); + if (!l_cmd_request) { + printf("Error: Failed to initialize command request\n"); + return NULL; + } + dap_client_http_request(dap_worker_get_auto(), a_url_str ? a_url_str : s_get_net_url(a_net_name), a_port ? a_port : s_get_net_port(a_net_name), @@ -276,17 +280,34 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a if (s_cmd_request_get_response(l_cmd_request, &l_response, &l_response_size)) { printf( "Response error code: %d", l_cmd_request->error_code); } + } else { + printf("Error: Command list wait failed with code %d\n", l_ret); + } + + s_cmd_request_free(l_cmd_request); + return l_response; +} + +static json_object* s_request_command_parse(json_object *l_response) { + if (!l_response) { + printf("Error: Response is NULL\n"); + return NULL; + } + + json_object * l_result = NULL; + if (!json_object_object_get_ex(l_response, "result", &l_result)) { + printf("Error: Failed to get 'result' from response\n"); + return NULL; } - json_object * l_result; - json_object_object_get_ex(l_response, "result", &l_result); - json_object *errors_array; + + json_object *errors_array = NULL; if (json_object_is_type(l_result, json_type_array) && json_object_array_length(l_result) > 0) { json_object *first_element = json_object_array_get_idx(l_result, 0); if (json_object_object_get_ex(first_element, "errors", &errors_array)) { int errors_len = json_object_array_length(errors_array); for (int j = 0; j < errors_len; j++) { json_object *error_obj = json_object_array_get_idx(errors_array, j); - json_object *error_code, *error_message; + json_object *error_code = NULL, *error_message = NULL; if (json_object_object_get_ex(error_obj, "code", &error_code) && json_object_object_get_ex(error_obj, "message", &error_message)) { printf("Error %d: %s\n", json_object_get_int(error_code), json_object_get_string(error_message)); @@ -295,9 +316,18 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a l_result = NULL; } } - s_cmd_request_free(l_cmd_request); - if (l_result) - json_object_get(l_result); + json_object_get(l_result); + return l_result; +} + +json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) { + json_object * l_response = s_request_command_to_rpc(request, a_net_name, a_url_str, a_port); + if (!l_response) { + printf("Error: Failed to get response from RPC request\n"); + return NULL; + } + + json_object * l_result = s_request_command_parse(l_response); json_object_put(l_response); return l_result; } @@ -306,7 +336,7 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, const char * a_url_str, uint16_t a_port) { char data[512]; snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name); - json_object *l_json_get_fee = s_request_command_to_rpc(data, l_net_name, a_url_str, a_port); + json_object *l_json_get_fee = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port); if (!l_json_get_fee) { return false; } @@ -357,7 +387,7 @@ bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const c snprintf(data, sizeof(data), "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name); - json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name, a_url_str, a_port); + json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port); if (!l_json_outs) { return false; } @@ -392,7 +422,7 @@ bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const c *l_outputs_count = json_object_array_length(*l_outs); json_object_get(*l_outs); - json_object_put(l_json_outs); // Clean up the JSON object + json_object_put(l_json_outs); return true; } @@ -1047,7 +1077,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name); - json_object *l_json_coins = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port); + json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port); if (!l_json_coins) { return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS } @@ -1061,7 +1091,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", dap_chain_addr_to_str(l_wallet_addr), a_net_name); DAP_DEL_Z(l_wallet_addr); - json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port); + json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port); uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell); uint256_t l_value_sell = a_datoshi_sell; @@ -1097,7 +1127,7 @@ json_object *dap_get_remote_tx_outs(const char *a_token_ticker, const char *a_ne snprintf(data, sizeof(data), "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name); - json_object *l_json_outs = s_request_command_to_rpc(data, a_net_name, a_url_str, a_port); + json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port); if (!l_json_outs) { return NULL; } @@ -1599,7 +1629,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name); - json_object *l_json_coins = s_request_command_to_rpc(data, l_net_name, l_url_str, l_port); + json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port); if (!l_json_coins) { return -4; } @@ -1733,7 +1763,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) dap_chain_addr_to_str(l_addr_holder), l_net_name); DAP_DEL_Z(l_addr_holder); - json_object *l_json_outs = s_request_command_to_rpc(data, l_net_name, l_url_str, l_port); + json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port); uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str); json_object_put(l_json_outs); if (compare256(l_value_balance, l_value) == -1) { @@ -2003,7 +2033,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv) "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_str, l_net_str); - json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return -15; @@ -2296,7 +2326,7 @@ uint256_t s_get_key_delegating_min_value(const char *a_net_str, const char *l_ur "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); - json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return l_key_delegating_min_value; @@ -2454,7 +2484,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str); - json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_coins) { printf("Error: Can't get ledger coins list\n"); return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; @@ -2739,7 +2769,7 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c char data[512]; snprintf(data, sizeof(data), "{\"method\": \"voting\",\"params\": [\"voting;dump;-hash;%s\"],\"id\": \"2\"}", l_hash_str); - json_object *l_json_voting = s_request_command_to_rpc(data); + json_object *l_json_voting = dap_request_command_to_rpc(data); if (!l_json_voting) { printf("Error: Can't get voting info\n"); return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; @@ -2793,7 +2823,7 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c char data[512]; snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); - json_object *l_json_coins = s_request_command_to_rpc(data); + json_object *l_json_coins = dap_request_command_to_rpc(data); if (!l_json_coins) { printf("Error: Failed to retrieve coins from ledger\n"); return -4; @@ -3075,7 +3105,7 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", l_net_str); - json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_coins) { printf("Error: Failed to retrieve coins from ledger\n"); return -4; @@ -3109,7 +3139,7 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str); - json_object *l_json_response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + json_object *l_json_response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_response) { printf("Error: Failed to retrieve transaction info from ledger\n"); return -4; @@ -3154,7 +3184,7 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash); snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str); - json_object *l_json_prev_tx = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + json_object *l_json_prev_tx = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_prev_tx) { printf("Previous transaction %s is not found\n", l_tx_hash_str_tmp); json_object_put(l_json_response); @@ -3170,7 +3200,7 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) char data[512]; snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", l_net_str); - json_object *l_json_coins = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!l_json_coins) { printf("Error: Failed to retrieve coins from ledger\n"); json_object_put(l_json_response); @@ -3219,7 +3249,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap "{\"method\": \"ledger\",\"params\": [\"ledger;info;-need_sign;-hash;%s;-net;%s\"],\"id\": \"1\"}", dap_hash_fast_to_str_static(a_tx_hash), a_net_str); - json_object *response = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return NULL; @@ -3268,7 +3298,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_prev_hash, a_net_str); - json_object *response_cond = s_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + json_object *response_cond = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); if (!response_cond) { printf("Error: Request conditional transaction failed\n"); json_object_put(response); @@ -3512,7 +3542,7 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", l_net_str); - json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return NULL; @@ -3525,7 +3555,7 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", l_net_str); - response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return NULL; @@ -3692,6 +3722,11 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) uint256_t l_value_max; int l_prev_tx_count = 0; dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, l_url_str, l_port); + if (!l_order) { + printf("Error: Failed to get order from remote node\n"); + dap_enc_key_delete(l_enc_key); + return -8; + } if (l_order->direction == SERV_DIR_BUY) { // Staker order if (!l_cert_str) { @@ -3712,7 +3747,7 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", dap_chain_hash_fast_to_str_static(&l_order->tx_cond_hash), l_net_str); - json_object *response = s_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); if (!response) { printf("Error: Failed to get response from remote node\n"); return -15; @@ -3904,7 +3939,7 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) } // Freeze staker's funds when delegating a key -static dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, +dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index e8bf8ab3bd..04300c7145 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -65,6 +65,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv); +json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port); int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer); @@ -102,12 +103,13 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port); dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port); -static dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, +dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port); + #ifdef __cplusplus } #endif \ No newline at end of file -- GitLab From 956571a6661973583ba0fb34e3001a23fa1e8e58 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Wed, 2 Apr 2025 15:37:28 +0700 Subject: [PATCH 33/53] [+] order sign --- modules/compose/dap_chain_tx_compose.c | 49 ++++++++++++++++--- modules/net/srv/dap_chain_net_srv.c | 7 +-- modules/net/srv/dap_chain_net_srv_order.c | 11 ++++- .../net/srv/include/dap_chain_net_srv_order.h | 2 +- .../dap_chain_net_srv_stake_pos_delegate.c | 2 +- 5 files changed, 58 insertions(+), 13 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index bb14cf0ec5..0e1d3964fb 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -3489,7 +3489,6 @@ dap_chain_net_srv_order_direction_t dap_chain_net_srv_order_direction_from_str(c return direction; } - dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, json_object* response){ dap_chain_net_srv_order_t* l_order = NULL; @@ -3515,15 +3514,19 @@ dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, con dap_chain_hash_fast_from_str(tx_cond_hash_str, &l_order->tx_cond_hash); } l_order->ext_size = json_object_get_int(json_object_object_get(order_obj, "ext_size")); + if (l_order->ext_size > 0) { - const char *tax_str = json_object_get_string(json_object_object_get(order_obj, "tax")); - const char *value_max_str = json_object_get_string(json_object_object_get(order_obj, "maximum_value")); - *a_tax = dap_uint256_scan_decimal(tax_str); - *a_value_max = dap_uint256_scan_decimal(value_max_str); + json_object *external_params = json_object_object_get(order_obj, "external_params"); + if (external_params) { + const char *tax_str = json_object_get_string(json_object_object_get(external_params, "tax")); + const char *value_max_str = json_object_get_string(json_object_object_get(external_params, "maximum_value")); + *a_tax = dap_uint256_scan_decimal(tax_str); + *a_value_max = dap_uint256_scan_decimal(value_max_str); + } } json_object *conditional_tx_params = json_object_object_get(order_obj, "conditional_tx_params"); - if (conditional_tx_params) { + if (conditional_tx_params && json_object_is_type(conditional_tx_params, json_type_object)) { const char *sovereign_tax_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_tax")); const char *sovereign_addr_str = json_object_get_string(json_object_object_get(conditional_tx_params, "sovereign_addr")); *a_sovereign_tax = dap_uint256_scan_decimal(sovereign_tax_str); @@ -3566,6 +3569,37 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const return l_order; } +dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_order_hash_str, size_t* a_sign_size, + const char* l_url_str, uint16_t l_port){ + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"net_srv\",\"params\": [\"net_srv;-net;%s;order;dump;-hash;%s;-need_sign\"],\"id\": \"1\"}", + l_net_str, l_order_hash_str); + json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return NULL; + } + const char *l_sign_b64_str = json_object_get_string(json_object_object_get(response, "sig_b64")); + if (!l_sign_b64_str) { + printf("Error: Can't get base64-encoded sign from SIG item\n"); + json_object_put(response); + return NULL; + } + + int64_t l_sign_b64_strlen = json_object_get_string_len(l_sign_b64_str); + int64_t l_sign_decoded_size = DAP_ENC_BASE64_DECODE_SIZE(l_sign_b64_strlen); + dap_chain_tx_sig_t *l_tx_sig = DAP_NEW_Z_SIZE(dap_chain_tx_sig_t, sizeof(dap_chain_tx_sig_t) + l_sign_decoded_size); + *l_tx_sig = (dap_chain_tx_sig_t) { + .header = { + .type = TX_ITEM_TYPE_SIG, .version = 1, + .sig_size = dap_enc_base64_decode(l_sign_b64_str, l_sign_b64_strlen, l_tx_sig->sig, DAP_ENC_DATA_TYPE_B64_URLSAFE) + } + }; + *a_sign_size = l_tx_sig->header.sig_size; + return dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); +} + @@ -3863,7 +3897,8 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) dap_enc_key_delete(l_enc_key); return -19; } - dap_sign_t *l_sign = (dap_sign_t *)(l_order->ext_n_sign + l_order->ext_size); + size_t l_sign_size = 0; + dap_sign_t *l_sign = dap_get_remote_srv_order_sign(l_net_str, l_order_hash_str, &l_sign_size, l_url_str, l_port); if (l_sign->header.type.type == SIG_TYPE_NULL) { printf("Specified order is unsigned\n"); dap_enc_key_delete(l_enc_key); diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c index f0a757bc49..c2ae7b50ce 100644 --- a/modules/net/srv/dap_chain_net_srv.c +++ b/modules/net/srv/dap_chain_net_srv.c @@ -404,7 +404,7 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply) for (dap_list_t *l_temp = l_orders; l_temp; l_temp = l_temp->next){ json_object* json_obj_order = json_object_new_object(); dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t*)l_temp->data; - dap_chain_net_srv_order_dump_to_json(l_order, json_obj_order, l_hash_out_type, l_net->pub.native_ticker); + dap_chain_net_srv_order_dump_to_json(l_order, json_obj_order, l_hash_out_type, l_net->pub.native_ticker, false); json_object_array_add(json_arr_out, json_obj_order); } json_object_object_add(json_obj_net_srv, "orders", json_arr_out); @@ -416,11 +416,12 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply) } } else if(!dap_strcmp( l_order_str, "dump" )) { // Select with specified service uid + bool l_need_sign = dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-need_sign", NULL); if ( l_order_hash_str ){ dap_chain_net_srv_order_t * l_order = dap_chain_net_srv_order_find_by_hash_str( l_net, l_order_hash_hex_str ); json_obj_net_srv = json_object_new_object(); if (l_order) { - dap_chain_net_srv_order_dump_to_json(l_order, json_obj_net_srv, l_hash_out_type, l_net->pub.native_ticker); + dap_chain_net_srv_order_dump_to_json(l_order, json_obj_net_srv, l_hash_out_type, l_net->pub.native_ticker, l_need_sign); l_ret = 0; }else{ if(!dap_strcmp(l_hash_out_type,"hex")) @@ -447,7 +448,7 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply) for(dap_list_t *l_temp = l_orders;l_temp; l_temp = l_orders->next) { json_object* json_obj_order = json_object_new_object(); dap_chain_net_srv_order_t *l_order =(dap_chain_net_srv_order_t *) l_temp->data; - dap_chain_net_srv_order_dump_to_json(l_order, json_obj_order, l_hash_out_type, l_net->pub.native_ticker); + dap_chain_net_srv_order_dump_to_json(l_order, json_obj_order, l_hash_out_type, l_net->pub.native_ticker, l_need_sign); json_object_array_add(json_arr_out, json_obj_order); } json_object_object_add(json_obj_net_srv, "orders", json_arr_out); diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c index d584f33e9a..8033ad28b2 100644 --- a/modules/net/srv/dap_chain_net_srv_order.c +++ b/modules/net/srv/dap_chain_net_srv_order.c @@ -28,6 +28,7 @@ #include "dap_chain_net_srv_order.h" #include "dap_hash.h" #include "dap_enc_base58.h" +#include "dap_enc_base64.h" #include "dap_global_db.h" #include "dap_chain_net_srv_countries.h" #include "dap_chain_net_srv_stake_pos_delegate.h" @@ -561,7 +562,7 @@ void dap_chain_net_srv_order_dump_to_string(const dap_chain_net_srv_order_t *a_o * @param a_str_out */ void dap_chain_net_srv_order_dump_to_json(const dap_chain_net_srv_order_t *a_order, json_object *a_json_obj_out, - const char *a_hash_out_type, const char *a_native_ticker) + const char *a_hash_out_type, const char *a_native_ticker, bool a_need_sign) { if (a_order && a_json_obj_out ){ dap_chain_hash_fast_t l_hash; @@ -632,6 +633,14 @@ void dap_chain_net_srv_order_dump_to_json(const dap_chain_net_srv_order_t *a_ord // DAP_DELETE(l_ext_out); // } dap_sign_t *l_sign = (dap_sign_t*)((byte_t*)a_order->ext_n_sign + a_order->ext_size); + if (a_need_sign) { + char *l_sign_b64 = DAP_NEW_Z_SIZE(char, DAP_ENC_BASE64_ENCODE_SIZE(dap_sign_get_size(l_sign)) + 1); + size_t l_sign_size = dap_sign_get_size(l_sign); + dap_enc_base64_encode(l_sign, l_sign_size, l_sign_b64, DAP_ENC_DATA_TYPE_B64_URLSAFE); + json_object_object_add(a_json_obj_out, "sig_b64", json_object_new_string(l_sign_b64)); + json_object_object_add(a_json_obj_out, "sig_b64_size", json_object_new_uint64(l_sign_size)); + } + dap_hash_fast_t l_sign_pkey = {0}; dap_sign_get_pkey_hash(l_sign, &l_sign_pkey); const char *l_sign_pkey_hash_str = dap_hash_fast_to_str_static(&l_sign_pkey); diff --git a/modules/net/srv/include/dap_chain_net_srv_order.h b/modules/net/srv/include/dap_chain_net_srv_order.h index e0271c10a8..93166f6d59 100644 --- a/modules/net/srv/include/dap_chain_net_srv_order.h +++ b/modules/net/srv/include/dap_chain_net_srv_order.h @@ -142,7 +142,7 @@ char *dap_chain_net_srv_order_save(dap_chain_net_t *a_net, dap_chain_net_srv_ord void dap_chain_net_srv_order_dump_to_string(const dap_chain_net_srv_order_t *a_order, dap_string_t *a_str_out, const char *a_hash_out_type, const char *a_native_ticker); void dap_chain_net_srv_order_dump_to_json(const dap_chain_net_srv_order_t *a_order, json_object *a_json_obj_out, - const char *a_hash_out_type, const char *a_native_ticker); + const char *a_hash_out_type, const char *a_native_ticker, bool a_need_sign); void dap_chain_net_srv_order_add_notify_callback(dap_chain_net_t *a_net, dap_store_obj_callback_notify_t a_callback, void *a_cb_arg); /** diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c index 73fe463d10..8b0e976581 100644 --- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c +++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c @@ -1987,7 +1987,7 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, voi } // TODO add filters to list (token, address, etc.) json_object* l_json_obj_order = json_object_new_object(); - dap_chain_net_srv_order_dump_to_json(l_order, l_json_obj_order, a_hash_out_type, l_net->pub.native_ticker); + dap_chain_net_srv_order_dump_to_json(l_order, l_json_obj_order, a_hash_out_type, l_net->pub.native_ticker, false); if (l_order->srv_uid.uint64 == DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ORDERS) { if (l_order->direction == SERV_DIR_SELL) { json_object_object_add(l_json_obj_order, "message", -- GitLab From adf4b8ce6ccd4d3a75ecfb9413d89ea90e2b8de8 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Wed, 2 Apr 2025 16:43:08 +0700 Subject: [PATCH 34/53] [*] fix delegate --- modules/compose/dap_chain_tx_compose.c | 57 +++++++++++++++++--------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 0e1d3964fb..48f0bb940d 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -3569,7 +3569,7 @@ dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const return l_order; } -dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_order_hash_str, size_t* a_sign_size, +dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_order_hash_str, const char* l_url_str, uint16_t l_port){ char data[512]; snprintf(data, sizeof(data), @@ -3580,14 +3580,22 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o printf("Error: Failed to get response from remote node\n"); return NULL; } - const char *l_sign_b64_str = json_object_get_string(json_object_object_get(response, "sig_b64")); + json_object *l_response_array = json_object_array_get_idx(response, 0); + if (!l_response_array) { + printf("Error: Can't get the first element from the response array\n"); + json_object_put(response); + return NULL; + } + + const char *l_sign_b64_str = json_object_get_string(json_object_object_get(l_response_array, "sig_b64")); if (!l_sign_b64_str) { printf("Error: Can't get base64-encoded sign from SIG item\n"); json_object_put(response); return NULL; } - int64_t l_sign_b64_strlen = json_object_get_string_len(l_sign_b64_str); + // *a_sign_size = json_object_get_int(json_object_object_get(l_response_array, "sig_b64_size")); + int64_t l_sign_b64_strlen = json_object_get_string_len(json_object_object_get(l_response_array, "sig_b64")); int64_t l_sign_decoded_size = DAP_ENC_BASE64_DECODE_SIZE(l_sign_b64_strlen); dap_chain_tx_sig_t *l_tx_sig = DAP_NEW_Z_SIZE(dap_chain_tx_sig_t, sizeof(dap_chain_tx_sig_t) + l_sign_decoded_size); *l_tx_sig = (dap_chain_tx_sig_t) { @@ -3596,8 +3604,11 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o .sig_size = dap_enc_base64_decode(l_sign_b64_str, l_sign_b64_strlen, l_tx_sig->sig, DAP_ENC_DATA_TYPE_B64_URLSAFE) } }; - *a_sign_size = l_tx_sig->header.sig_size; - return dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); + + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); + DAP_DELETE(l_tx_sig); + json_object_put(response); + return l_sign; } @@ -3761,6 +3772,7 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) dap_enc_key_delete(l_enc_key); return -8; } + l_sovereign_tax = l_tax; if (l_order->direction == SERV_DIR_BUY) { // Staker order if (!l_cert_str) { @@ -3898,8 +3910,8 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) return -19; } size_t l_sign_size = 0; - dap_sign_t *l_sign = dap_get_remote_srv_order_sign(l_net_str, l_order_hash_str, &l_sign_size, l_url_str, l_port); - if (l_sign->header.type.type == SIG_TYPE_NULL) { + dap_sign_t *l_sign = dap_get_remote_srv_order_sign(l_net_str, l_order_hash_str, l_url_str, l_port); + if (!l_sign) { printf("Specified order is unsigned\n"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); @@ -3932,12 +3944,13 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) return -6; } - int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr); - if (l_check_result) { - printf("Key and node verification error\n"); - dap_enc_key_delete(l_enc_key); - return l_check_result; - } + // TODO: need to make sure that the key and node are required verification + // int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr); + // if (l_check_result) { + // printf("Key and node verification error\n"); + // dap_enc_key_delete(l_enc_key); + // return l_check_result; + // } uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str, l_url_str, l_port); @@ -3967,6 +3980,10 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) dap_enc_key_delete(l_enc_key); DAP_DELETE(l_pkey); + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); DAP_DELETE(l_tx); return 0; @@ -3991,7 +4008,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str)); uint256_t l_net_fee, l_fee_total = a_fee; dap_chain_addr_t * l_net_fee_addr = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, l_net_fee_addr, l_url_str, l_port); + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_net_fee_addr, l_url_str, l_port); if (l_net_fee_used) SUM_256_256(l_fee_total, l_net_fee, &l_fee_total); @@ -4085,7 +4102,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en // add fee items if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { printf("Cant add net fee output\n"); goto tx_fail; } @@ -4106,11 +4123,11 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en } } - // add 'sign' item - if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) { - printf("Can't add sign output\n"); - goto tx_fail; - } + // // add 'sign' item + // if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) { + // printf("Can't add sign output\n"); + // goto tx_fail; + // } return l_tx; -- GitLab From 8c29d6c9ef71563d0226fd4018618846ec037e54 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Wed, 2 Apr 2025 17:09:45 +0700 Subject: [PATCH 35/53] [+] order create staker --- modules/compose/dap_chain_tx_compose.c | 161 ++++++++++++++++++ .../compose/include/dap_chain_tx_compose.h | 1 + 2 files changed, 162 insertions(+) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 48f0bb940d..2479a6d1c3 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -4136,6 +4136,167 @@ tx_fail: return NULL; } +static dap_chain_datum_tx_t *dap_order_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, + uint256_t a_value, uint256_t a_fee, + uint256_t a_sovereign_tax, dap_chain_addr_t *a_sovereign_addr, + const char *l_url_str, int l_port) +{ + dap_chain_node_addr_t l_node_addr = {}; + return dap_stake_tx_create_compose(a_net_str, a_key, a_value, a_fee, + (dap_chain_addr_t *)&c_dap_chain_addr_blank, &l_node_addr, + a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port); +} + +//srv_stake order create staker -net <net_name> -w <wallet_with_m_tokens> -value <stake_value> -fee <value> -tax <percent> [-addr <for_tax_collecting>] [-cert <for_order_signing>] [-H {hex(default) | base58}] +int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { + int l_arg_index = 1; + const char *l_value_str = NULL, + *l_wallet_str = NULL, + *l_tax_str = NULL, + *l_addr_str = NULL, + *l_fee_str = NULL, + *l_url_str = NULL, + *l_port_str = NULL, + *l_net_str = NULL; + int l_port = 0; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); + if (!l_net_str) { + printf("Command 'order' requires parameter -net"); + return -1; + } + + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { + l_url_str = s_get_net_url(l_net_str); + } + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { + l_port = s_get_net_port(l_net_str); + } else { + l_port = atoi(l_port_str); + } + + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + arg_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif + } else { + arg_wallets_path = dap_strdup(l_wallet_path); + } + + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); + if (!l_value_str) { + printf("Staker order creation requires parameter -value\n"); + return -1; + } + uint256_t l_value = dap_chain_balance_scan(l_value_str); + if (IS_ZERO_256(l_value)) { + printf("Format -value <256 bit integer>\n"); + return -2; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); + if (!l_fee_str) { + printf("Staker order creation requires parameter -fee\n"); + return -3; + } + uint256_t l_fee = dap_chain_balance_scan(l_fee_str); + if (IS_ZERO_256(l_fee)) { + printf("Format -fee <256 bit integer>\n"); + return -4; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax", &l_tax_str); + if (!l_tax_str) { + printf("Staker order creation requires parameter -tax\n"); + return -5; + } + uint256_t l_tax = dap_chain_coins_to_balance(l_tax_str); + if (compare256(l_tax, dap_chain_coins_to_balance("100.0")) == 1 || + compare256(l_tax, GET_256_FROM_64(100)) == -1) { + printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n"); + return -6; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); + if (!l_wallet_str) { + printf("Staker order creation requires parameter -w\n"); + return -7; + } + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); + if (!l_wallet) { + printf("Specified wallet not found\n"); + return -8; + } + // Create conditional transaction for order + const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet); + dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); + dap_chain_wallet_close(l_wallet); + dap_chain_addr_t l_addr = {}; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_addr_str); + if (l_addr_str) { + dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str); + if (!l_spec_addr) { + printf("Specified address is ivalid\n"); + DAP_DELETE(l_enc_key); + return -9; + } + l_addr = *l_spec_addr; + DAP_DELETE(l_spec_addr); + } else + dap_chain_addr_fill_from_key(&l_addr, l_enc_key, s_get_net_id(l_net_str)); + DIV_256(l_tax, GET_256_FROM_64(100), &l_tax); + dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, &l_addr, l_url_str, l_port); + DAP_DEL_Z(l_enc_key); + // char *l_tx_hash_str = NULL; + // if (!l_tx || !(l_tx_hash_str = s_stake_tx_put(l_tx, l_net, a_hash_out_type))) { + // printf("Can't compose transaction for order, examine log files for details\n"); + // DAP_DEL_Z(l_tx); + // return -10; + // } + + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); + DAP_DELETE(l_tx); + // Create the order & put it in GDB + + // dap_hash_fast_t l_tx_hash = {}; + // dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash); + // char *l_cert_str = NULL; + // dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", (const char **)&l_cert_str); + // if (!l_cert_str) + // l_cert_str = "node-addr"; + // dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str); + // if (!l_cert) { + // printf("Can't load cert %s\n", l_cert_str); + // DAP_DELETE(l_tx_hash_str); + // return -11; + // } + // if (!l_cert->enc_key || !l_cert->enc_key->priv_key_data || !l_cert->enc_key->priv_key_data_size) { + // printf("Certificate \"%s\" has no private key\n", l_cert_str); + // return -12; + // } + // char *l_order_hash_str = s_staker_order_create(l_net, l_value, &l_tx_hash, l_cert->enc_key, a_hash_out_type); + // if (!l_order_hash_str) { + // printf("Can't compose the order\n"); + // DAP_DELETE(l_tx_hash_str); + // return -13; + // } + // json_object * l_json_obj_create_val = json_object_new_object(); + // json_object_object_add(l_json_obj_create_val, "status", json_object_new_string("success")); + // if (dap_strcmp(l_sign_str, "")) + // json_object_object_add(l_json_obj_create_val, "sign", json_object_new_string(l_sign_str)); + // json_object_object_add(l_json_obj_create_val, "order_hash", json_object_new_string(l_order_hash_str)); + // json_object_object_add(l_json_obj_create_val, "tx_hash", json_object_new_string(l_tx_hash_str)); + // json_object_array_add(*a_json_arr_reply, l_json_obj_create_val); + // DAP_DELETE(l_order_hash_str); + // DAP_DELETE(l_tx_hash_str); +} + // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value> // int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) { // int arg_index = 1; diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 04300c7145..b01ad80d24 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -64,6 +64,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv); int dap_cli_voting_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv); +int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv); json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port); int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); -- GitLab From a8ae075e4cc49bdd9d24da79d9e63055039f7020 Mon Sep 17 00:00:00 2001 From: konstantin <konstantin.kuharenko@demlabs.net> Date: Thu, 3 Apr 2025 08:18:01 +0300 Subject: [PATCH 36/53] [*] fix enc method for wallet --- dap-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dap-sdk b/dap-sdk index e303f12da9..f4d4efa7f6 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit e303f12da9e8a8b632e296e8897319b952837a62 +Subproject commit f4d4efa7f6b4628eedf947b908438cc3db2b02e8 -- GitLab From 0ed0cbecca75fe206faad14553c2eb5649041ab5 Mon Sep 17 00:00:00 2001 From: konstantin <konstantin.kuharenko@demlabs.net> Date: Thu, 3 Apr 2025 13:59:28 +0300 Subject: [PATCH 37/53] [*] add extern C --- dap-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dap-sdk b/dap-sdk index f4d4efa7f6..b3dfc55196 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit f4d4efa7f6b4628eedf947b908438cc3db2b02e8 +Subproject commit b3dfc55196d4ce1815c2805a7211f3eb3d08940e -- GitLab From ea1819a12fe7168f345f39352e936b13dc1c9c52 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Mon, 7 Apr 2025 16:42:13 +0700 Subject: [PATCH 38/53] [+] xchange remove --- modules/compose/dap_chain_tx_compose.c | 571 ++++++++++++++++-- .../compose/include/dap_chain_tx_compose.h | 4 + 2 files changed, 515 insertions(+), 60 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 2479a6d1c3..4b742936b7 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -1470,8 +1470,8 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net size_t a_cond_size, const char *a_url_str, uint16_t a_port) { // check valid param - if (!a_net_name || !a_key_from || !a_key_cond || - !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value)) + if (!a_net_name || !*a_net_name || !a_key_from || !a_key_cond || + !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value) || !a_url_str || !*a_url_str || a_port == 0) return NULL; if (dap_strcmp(s_get_native_ticker(a_net_name), a_token_ticker)) { @@ -1669,8 +1669,6 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) return -9; } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_str); - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str); if (!l_chain_id_str) { printf("Error: Missing or invalid chain_id argument\n"); @@ -3243,7 +3241,9 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port) -{ +{ + if(!a_net_str || !*a_net_str || !a_tx_hash || !a_key || !l_url_str || !*l_url_str || l_port == 0) + return NULL; char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;info;-need_sign;-hash;%s;-net;%s\"],\"id\": \"1\"}", @@ -4159,9 +4159,9 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { *l_port_str = NULL, *l_net_str = NULL; int l_port = 0; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); - if (!l_net_str) { - printf("Command 'order' requires parameter -net"); + + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str) || !l_net_str) { + printf("Command 'order' requires parameter -net\n"); return -1; } @@ -4189,8 +4189,7 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { arg_wallets_path = dap_strdup(l_wallet_path); } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); - if (!l_value_str) { + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str) || !l_value_str) { printf("Staker order creation requires parameter -value\n"); return -1; } @@ -4199,8 +4198,8 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { printf("Format -value <256 bit integer>\n"); return -2; } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); - if (!l_fee_str) { + + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str) || !l_fee_str) { printf("Staker order creation requires parameter -fee\n"); return -3; } @@ -4209,8 +4208,8 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { printf("Format -fee <256 bit integer>\n"); return -4; } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax", &l_tax_str); - if (!l_tax_str) { + + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax", &l_tax_str) || !l_tax_str) { printf("Staker order creation requires parameter -tax\n"); return -5; } @@ -4220,8 +4219,8 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n"); return -6; } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); - if (!l_wallet_str) { + + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) { printf("Staker order creation requires parameter -w\n"); return -7; } @@ -4230,18 +4229,23 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { printf("Specified wallet not found\n"); return -8; } - // Create conditional transaction for order + const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet); dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); dap_chain_wallet_close(l_wallet); + + if (!l_enc_key) { + printf("Failed to retrieve encryption key\n"); + return -9; + } + dap_chain_addr_t l_addr = {}; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_addr_str); - if (l_addr_str) { + if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_addr_str) && l_addr_str) { dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str); if (!l_spec_addr) { - printf("Specified address is ivalid\n"); + printf("Specified address is invalid\n"); DAP_DELETE(l_enc_key); - return -9; + return -10; } l_addr = *l_spec_addr; DAP_DELETE(l_spec_addr); @@ -4250,53 +4254,500 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { DIV_256(l_tax, GET_256_FROM_64(100), &l_tax); dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, &l_addr, l_url_str, l_port); DAP_DEL_Z(l_enc_key); - // char *l_tx_hash_str = NULL; - // if (!l_tx || !(l_tx_hash_str = s_stake_tx_put(l_tx, l_net, a_hash_out_type))) { - // printf("Can't compose transaction for order, examine log files for details\n"); - // DAP_DEL_Z(l_tx); - // return -10; - // } - json_object * l_json_obj_ret = json_object_new_object(); + if (!l_tx) { + printf("Failed to create transaction\n"); + return -11; + } + + json_object *l_json_obj_ret = json_object_new_object(); + if (!l_json_obj_ret) { + printf("Failed to create JSON object\n"); + DAP_DELETE(l_tx); + return -12; + } + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); printf("%s", json_object_to_json_string(l_json_obj_ret)); json_object_put(l_json_obj_ret); DAP_DELETE(l_tx); - // Create the order & put it in GDB - - // dap_hash_fast_t l_tx_hash = {}; - // dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash); - // char *l_cert_str = NULL; - // dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", (const char **)&l_cert_str); - // if (!l_cert_str) - // l_cert_str = "node-addr"; - // dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str); - // if (!l_cert) { - // printf("Can't load cert %s\n", l_cert_str); - // DAP_DELETE(l_tx_hash_str); - // return -11; - // } - // if (!l_cert->enc_key || !l_cert->enc_key->priv_key_data || !l_cert->enc_key->priv_key_data_size) { - // printf("Certificate \"%s\" has no private key\n", l_cert_str); - // return -12; - // } - // char *l_order_hash_str = s_staker_order_create(l_net, l_value, &l_tx_hash, l_cert->enc_key, a_hash_out_type); - // if (!l_order_hash_str) { - // printf("Can't compose the order\n"); - // DAP_DELETE(l_tx_hash_str); - // return -13; + return 0; +} + +int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) { + int l_arg_index = 1; + const char * l_order_hash_str = NULL; + const char * l_fee_str = NULL; + const char * l_net_str = NULL; + const char * l_wallet_str = NULL; + const char * l_url_str = NULL; + const char * l_port_str = NULL; + int l_port = 0; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); + if (!l_net_str) { + printf("Command 'order remove' requires parameter -net\n"); + return -1; + } + + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { + l_url_str = s_get_net_url(l_net_str); + } + if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { + l_port = s_get_net_port(l_net_str); + } else { + l_port = atoi(l_port_str); + } + + const char *l_wallet_path = NULL; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); + if (!l_wallet_path) { + arg_wallets_path = + #ifdef DAP_OS_WINDOWS + dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); + #elif defined DAP_OS_MAC + dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); + #elif defined DAP_OS_UNIX + dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); + #endif + } else { + arg_wallets_path = dap_strdup(l_wallet_path); + } + + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); + if (!l_wallet_str) { + printf("Command 'order remove' requires parameter -w\n"); + return -3; + } + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); + if (!l_wallet) { + printf("Specified wallet not found\n"); + return -4; + } + const char* l_sign_str = dap_chain_wallet_check_sign(l_wallet); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str); + if (!l_order_hash_str) { + printf("Command 'order remove' requires parameter -order\n"); + return -5; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); + if (!l_fee_str) { + printf("Command 'order remove' requires parameter -fee\n"); + return -6; + } + uint256_t l_fee = dap_chain_balance_scan(l_fee_str); + dap_hash_fast_t l_tx_hash = {}; + dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash); + char *l_tx_hash_ret = NULL; + dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_remove_compose(l_net_str, &l_tx_hash, l_fee, l_wallet, l_url_str, l_port); + dap_chain_wallet_close(l_wallet); + + return 0; +} + +bool process_ledger_response(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, + dap_chain_hash_fast_t *a_tx_hash, const char *a_url_str, int a_port, dap_chain_hash_fast_t *a_out_hash) { + *a_out_hash = *a_tx_hash; + int l_prev_tx_count = 0; + dap_chain_hash_fast_t l_hash = {}; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_hash_fast_to_str_static(a_tx_hash), a_net_str); + + json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return false; + } + + json_object *l_response_array = json_object_array_get_idx(response, 0); + if (!l_response_array) { + printf("Error: Can't get the first element from the response array\n"); + json_object_put(response); + return false; + } + + json_object *items = json_object_object_get(l_response_array, "ITEMS"); + if (!items) { + printf("Error: No items found in response\n"); + return false; + } + bool l_found = false; + int items_count = json_object_array_length(items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (dap_strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (!dap_strcmp(subtype, dap_chain_tx_out_cond_subtype_to_str(a_cond_type))) { + dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(item, "hash")), &l_hash); + l_prev_tx_count++; + l_found = true; + break; + } + } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) { + l_prev_tx_count++; + } + } + if (!l_found) { + return false; + } + bool l_another_tx = false; + json_object *spent_outs = json_object_object_get(l_response_array, "Spent OUTs"); + if (spent_outs) { + int spent_outs_count = json_object_array_length(spent_outs); + for (int i = 0; i < spent_outs_count; i++) { + json_object *spent_out = json_object_array_get_idx(spent_outs, i); + int out_index = json_object_get_int(json_object_object_get(spent_out, "OUT - ")); + if (out_index == l_prev_tx_count) { + dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(spent_out, "is spent by tx")), &l_hash); + l_another_tx = true; + break; + } + } + } + if (l_another_tx) { + *a_out_hash = l_hash; + return true; + } + return false; +} + +dap_chain_hash_fast_t dap_ledger_get_final_chain_tx_hash_compose(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash, bool a_unspent_only, const char *a_url_str, int a_port) +{ + dap_chain_hash_fast_t l_hash = { }; + if(!a_net_str || !a_tx_hash || dap_hash_fast_is_blank(a_tx_hash)) + return l_hash; + l_hash = *a_tx_hash; + + while(process_ledger_response(a_net_str, a_cond_type, a_tx_hash, a_url_str, a_port, &l_hash)); + + return l_hash; +} + +dap_chain_net_srv_xchange_price_t *dap_chain_net_srv_xchange_price_from_order_compose(const char *a_net_str, dap_chain_tx_out_cond_t *a_cond_tx, + dap_time_t a_ts_created, const char *a_token_ticker, dap_hash_fast_t *a_order_hash, + uint256_t *a_fee, bool a_ret_is_invalid, const char *a_url_str, int a_port) +{ + if (!a_net_str || !*a_net_str || !a_cond_tx || !a_token_ticker || !a_order_hash || !a_url_str || !*a_url_str || a_port == 0) + return NULL; + dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); + if (!l_price) + return NULL; + l_price->creation_date = a_ts_created; + dap_strncpy(l_price->token_buy, a_cond_tx->subtype.srv_xchange.buy_token, sizeof(l_price->token_buy) - 1); + + l_price->order_hash = *a_order_hash; + strncpy(l_price->token_sell, a_token_ticker, sizeof(l_price->token_sell) - 1); + + if (a_fee) + l_price->fee = *a_fee; + + l_price->datoshi_sell = a_cond_tx->header.value; + l_price->creator_addr = a_cond_tx->subtype.srv_xchange.seller_addr; + l_price->rate = a_cond_tx->subtype.srv_xchange.rate; + dap_chain_hash_fast_t l_final_hash = dap_ledger_get_final_chain_tx_hash_compose(a_net_str, + DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->order_hash, false, a_url_str, a_port); + if ( !dap_hash_fast_is_blank(&l_final_hash) ) { + l_price->tx_hash = l_final_hash; + return l_price; + } else { + printf( "This order have no active conditional transaction"); + if (a_ret_is_invalid) { + dap_hash_fast_t l_tx_hash_zero = {0}; + l_price->tx_hash = l_tx_hash_zero; + return l_price; + } + } + + return NULL; +} + + +dap_chain_datum_tx_t* dap_xchange_tx_invalidate_compose(const char *a_net_str, dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) +{ + char * l_ret = NULL; + + if (!a_price) { + printf("An a_price NULL argument was passed to the s_xchange_tx_invalidate() function."); + return NULL; + } + if (!a_wallet) { + printf("An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function."); + return NULL; + } + const char *l_native_ticker = s_get_native_ticker(a_net_str); + + dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str)); + dap_chain_addr_t l_seller_addr = *l_wallet_addr; + DAP_DELETE(l_wallet_addr); + + + dap_chain_tx_out_cond_t *l_cond_tx = NULL; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_hash_fast_to_str_static(&a_price->tx_hash), a_net_str); + + json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return NULL; + } + + json_object *l_response_array = json_object_array_get_idx(response, 0); + if (!l_response_array) { + printf("Error: Can't get the first element from the response array\n"); + json_object_put(response); + return NULL; + } + + json_object *items = json_object_object_get(l_response_array, "ITEMS"); + if (!items) { + printf("Error: No items found in response\n"); + return NULL; + } + int l_prev_cond_idx = 0; + int items_count = json_object_array_length(items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (dap_strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { + l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); + l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; + l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); + l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; + l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); + l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); + strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); + l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; + l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); + l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); + break; + } else if (dap_strcmp(subtype, "OUT") == 0 || dap_strcmp(subtype, "OUT COND") == 0 || dap_strcmp(subtype, "OUT OLD") == 0) { + l_prev_cond_idx++; + } + } + } + if (!l_cond_tx) { + printf("Error: No transaction output condition found\n"); + return NULL; + } + + const char *l_tx_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); + if (!l_tx_ticker) { + printf("Error: Token_ticker not found in response\n"); + return NULL; + } + + bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker); + + json_object *spent_outs = json_object_object_get(l_response_array, "all OUTs yet unspent"); + const char *spent_outs_value = json_object_get_string(spent_outs); + if (spent_outs_value && !dap_strcmp(spent_outs_value, "yes")) { + printf("Error: Transaction output item already used\n"); + return NULL; + } + + if (!dap_chain_addr_compare(&l_seller_addr, &l_cond_tx->subtype.srv_xchange.seller_addr)) { + printf("Only owner can invalidate exchange transaction"); + return NULL; + } + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // add 'in' item to buy from conditional transaction + dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0); + uint256_t l_net_fee = {}; + dap_chain_addr_t* l_addr_fee = NULL; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port); + uint256_t l_total_fee = a_price->fee; + if (l_net_fee_used) + SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); + + if (!l_single_channel) { + json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_seller_addr, l_url_str, l_port); + if (!l_outs_native) { + return NULL; + } + int l_out_native_count = json_object_array_length(l_outs_native); + uint256_t l_transfer_fee = {}, l_fee_back = {}; + // list of transaction with 'out' items to get net fee + dap_list_t *l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, + l_total_fee, + &l_transfer_fee); + if (!l_list_fee_out) { + printf("Not enough funds to pay fee"); + json_object_put(l_outs_native); + return NULL; + } + + + // add 'in' items to net fee + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + dap_list_free_full(l_list_fee_out, NULL); + if (!EQUAL_256(l_value_to_items, l_transfer_fee)) { + dap_chain_datum_tx_delete(l_tx); + printf("Can't compose the transaction input"); + return NULL; + } + // return coins to owner + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_cond_tx->header.value, l_tx_ticker) == -1) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add returning coins output"); + return NULL; + } + // Network fee + if (l_net_fee_used && + dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add network fee output"); + return NULL; + } + // put fee coinback + SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back); + if (!IS_ZERO_256(l_fee_back) && + dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add fee cachback output"); + return NULL; + } + } else { + uint256_t l_coin_back = {}; + if (compare256(l_total_fee, l_cond_tx->header.value) >= 0) { + dap_chain_datum_tx_delete(l_tx); + printf("Total fee is greater or equal than order liquidity"); + return NULL; + } + SUBTRACT_256_256(l_cond_tx->header.value, l_total_fee, &l_coin_back); + // return coins to owner + if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add returning coins output"); + return NULL; + } + // Network fee + if (l_net_fee_used && + dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add network fee output"); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_price->fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) { + dap_chain_datum_tx_delete(l_tx); + printf("Cant add validator's fee output"); + return NULL; + } + } + // // add 'sign' items + // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); + // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) { + // dap_chain_datum_tx_delete(l_tx); + // dap_enc_key_delete(l_seller_key); + // log_it( L_ERROR, "Can't add sign output"); + // return false; // } - // json_object * l_json_obj_create_val = json_object_new_object(); - // json_object_object_add(l_json_obj_create_val, "status", json_object_new_string("success")); - // if (dap_strcmp(l_sign_str, "")) - // json_object_object_add(l_json_obj_create_val, "sign", json_object_new_string(l_sign_str)); - // json_object_object_add(l_json_obj_create_val, "order_hash", json_object_new_string(l_order_hash_str)); - // json_object_object_add(l_json_obj_create_val, "tx_hash", json_object_new_string(l_tx_hash_str)); - // json_object_array_add(*a_json_arr_reply, l_json_obj_create_val); - // DAP_DELETE(l_order_hash_str); - // DAP_DELETE(l_tx_hash_str); + // dap_enc_key_delete(l_seller_key); + // l_ret = s_xchange_tx_put(l_tx, a_price->net); + + return l_tx; } + +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, + dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) { + if (!a_net_str || !a_hash_tx || !a_wallet) { + return NULL; + } + if(IS_ZERO_256(a_fee)){ + return NULL; + } + + dap_time_t ts_created = 0; + + dap_chain_tx_out_cond_t *l_cond_tx = NULL; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_hash_fast_to_str_static(a_hash_tx), a_net_str); + + json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return NULL; + } + + const char *items_str = json_object_get_string(response); + json_object *l_response_array = json_object_array_get_idx(response, 0); + if (!l_response_array) { + printf("Error: Can't get the first element from the response array\n"); + json_object_put(response); + return NULL; + } + json_object *items = json_object_object_get(l_response_array, "ITEMS"); + if (!items) { + printf("Error: No items found in response\n"); + return NULL; + } + int items_count = json_object_array_length(items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (dap_strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { + l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); + l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; + l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); + l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; + l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); + l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); + strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); + l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; + l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); + l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); + break; + } + } + } + if (!l_cond_tx) { + printf("Error: No transaction output condition found\n"); + return NULL; + } + + const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); + if (!token_ticker) { + printf("Error: Token_ticker not found in response\n"); + return NULL; + } + const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created")); + if (ts_created_str) { + ts_created = dap_time_from_str_rfc822(ts_created_str); + } else { + printf("Error: TS_Created not found in response\n"); + return NULL; + } + + dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(a_net_str, l_cond_tx, ts_created, token_ticker, a_hash_tx, &a_fee, false, l_url_str, l_port); + if (!l_price) { + return NULL; + } + dap_chain_datum_tx_t *l_tx = dap_xchange_tx_invalidate_compose(a_net_str, l_price, a_wallet, l_url_str, l_port); + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); + + DAP_DELETE(l_price); + return l_tx; +} + + // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value> // int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) { // int arg_index = 1; diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index b01ad80d24..78c4cee86e 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -65,6 +65,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv); +int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv); json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port); int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); @@ -110,6 +111,9 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port); +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, + dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port); + #ifdef __cplusplus } -- GitLab From b8f266943f69e9dad2a3c32ed774274f12517254 Mon Sep 17 00:00:00 2001 From: "Constantin P." <papizh.konstantin@demlabs.net> Date: Mon, 7 Apr 2025 16:56:03 +0700 Subject: [PATCH 39/53] Subs up --- dap-sdk | 2 +- modules/compose/dap_chain_tx_compose.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dap-sdk b/dap-sdk index b3dfc55196..e46c5449c2 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit b3dfc55196d4ce1815c2805a7211f3eb3d08940e +Subproject commit e46c5449c2c2021f51db1b194654b44b177d0449 diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 2479a6d1c3..e8c3bfb586 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -39,7 +39,6 @@ #include "dap_chain_net_srv_order.h" #include "dap_chain_net_srv_stake_pos_delegate.h" -#include <netdb.h> #include <json-c/json.h> -- GitLab From 02dac63aa351fc227d68d9db58acd8cfbc901282 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Wed, 9 Apr 2025 14:40:56 +0700 Subject: [PATCH 40/53] [*] invalidate refactor --- dap-sdk | 2 +- modules/compose/dap_chain_tx_compose.c | 220 ++++++++++++------ .../compose/include/dap_chain_tx_compose.h | 39 +++- 3 files changed, 193 insertions(+), 68 deletions(-) diff --git a/dap-sdk b/dap-sdk index e46c5449c2..6cfac2c1c6 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit e46c5449c2c2021f51db1b194654b44b177d0449 +Subproject commit 6cfac2c1c65127d8f9cf9cf4c65afb054af8ce1f diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 97f76ecd59..99751e1b64 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -257,7 +257,7 @@ static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_ob static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) { json_object * l_response = NULL; - size_t l_response_size = 0; // Initialize to avoid potential undefined behavior + size_t l_response_size = 0; struct cmd_request* l_cmd_request = s_cmd_request_init(); if (!l_cmd_request) { @@ -3010,7 +3010,7 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c */ -int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) +int dap_compose_srv_stake_invalidate(int a_argc, char **a_argv) { const char *l_net_str = NULL, *l_wallet_str = NULL, @@ -3076,36 +3076,129 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) return -1; } } + json_object *l_json_obj_ret = json_object_new_object(); + int ret = dap_cli_srv_stake_invalidate_compose(l_json_obj_ret, l_net_str, l_tx_hash_str, l_wallet_str, l_wallet_path, l_cert_str, l_fee, l_url_str, l_port); + switch (ret) { + case DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND: + printf("Error: Specified certificate not found\n"); + break; + case DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING: + printf("Error: It is not possible to invalidate a stake using a public key.\n"); + break; + case DAP_CLI_STAKE_INVALIDATE_WRONG_CERT: + printf("Error: Specified certificate is wrong\n"); + break; + case DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR: + printf("Error: Failed to retrieve coins from ledger\n"); + break; + case DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH: + printf("Error: Invalid transaction hash format\n"); + break; + case DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED: + printf("Error: Specified address is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n"); + break; + case DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT: + printf("Error: Transaction does not have a delegate out\n"); + break; + case DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND: + printf("Error: Previous transaction is not found\n"); + break; + case DAP_CLI_STAKE_INVALIDATE_TX_EXISTS: + printf("Error: Transaction already exists in the ledger\n"); + break; + case DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND: + printf("Error: Specified wallet not found\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR: + printf("Error: Failed to get response from remote node\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND: + printf("Error: ITEMS array not found in JSON response\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT: + printf("Error: All outputs are spent\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND: + printf("Error: Tx_prev_hash not found in ITEMS array\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR: + printf("Error: Request conditional transaction failed\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND: + printf("Error: Required conditional transaction structures not found\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND: + printf("Error: SIG item not found in ITEMS array\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR: + printf("Error: Can't get base64-encoded sign from SIG item\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER: + printf("Trying to invalidate delegating tx with not a owner wallet\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND: + printf("Error: Token ticker not found in response\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND: + printf("Error: Failed to get transaction outputs\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS: + printf("Error: Not enough funds to pay fee\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR: + printf("Error: Can't compose the transaction input\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR: + printf("Error:Cant add returning coins output\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR: + printf("Error: Can't add network fee output\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR: + printf("Error: Can't add fee output\n"); + break; + case DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR: + printf("Error: Can't add fee back output\n"); + break; + case DAP_CLI_STAKE_INVALIDATE_OK: + printf("%s", json_object_to_json_string(l_json_obj_ret)); + break; + default: + printf("Error: Unknown error code: %d\n", ret); + } + + json_object_put(l_json_obj_ret); + return ret; +} +int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, + const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port) +{ dap_hash_fast_t l_tx_hash = {}; - if (l_tx_hash_str) { - dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash); + if (a_tx_hash_str) { + dap_chain_hash_fast_from_str(a_tx_hash_str, &l_tx_hash); } else { dap_chain_addr_t l_signing_addr; - if (l_cert_str) { - dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str); + if (a_cert_str) { + dap_cert_t *l_cert = dap_cert_find_by_name(a_cert_str); if (!l_cert) { - printf("Specified certificate not found\n"); - return -4; + return DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND; } if (!l_cert->enc_key->priv_key_data || l_cert->enc_key->priv_key_data_size == 0) { - printf("It is not possible to invalidate a stake using a public key.\n"); - return -5; + return DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING; } - if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, s_get_net_id(l_net_str))) { - printf("Specified certificate is wrong\n"); - return -6; + if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, s_get_net_id(a_net_str))) { + return DAP_CLI_STAKE_INVALIDATE_WRONG_CERT; } } const char *l_addr_str = dap_chain_addr_to_str_static(&l_signing_addr); char data[512]; snprintf(data, sizeof(data), - "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", l_net_str); - json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); + json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); if (!l_json_coins) { - printf("Error: Failed to retrieve coins from ledger\n"); - return -4; + return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR; } int items_count = json_object_array_length(l_json_coins); @@ -3116,9 +3209,8 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) if (node_addr_str && !dap_strcmp(l_addr_str, node_addr_str)) { const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash")); if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) { - printf("Invalid transaction hash format\n"); json_object_put(l_json_coins); - return -8; + return DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH; } found = true; break; @@ -3126,20 +3218,18 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) } json_object_put(l_json_coins); if (!found) { - printf("Specified address is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n"); - return -9; + return DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED; } } - const char *l_tx_hash_str_tmp = l_tx_hash_str ? l_tx_hash_str : dap_hash_fast_to_str_static(&l_tx_hash); + const char *l_tx_hash_str_tmp = a_tx_hash_str ? a_tx_hash_str : dap_hash_fast_to_str_static(&l_tx_hash); char data[512]; snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str); - json_object *l_json_response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, a_net_str); + json_object *l_json_response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); if (!l_json_response) { - printf("Error: Failed to retrieve transaction info from ledger\n"); - return -4; + return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR; } json_object *l_json_items = json_object_array_get_idx(l_json_response, 0); @@ -3161,9 +3251,8 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) } if (!has_delegate_out) { - printf("Transaction %s does not have a delegate out\n", l_tx_hash_str_tmp); json_object_put(l_json_response); - return -11; + return DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT; } json_object *l_json_spents = json_object_object_get(l_json_response, "Spent OUTs"); @@ -3174,18 +3263,16 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) const char *spent_by_tx = json_object_get_string(json_object_object_get(spent_item, "is spent by tx")); if (spent_by_tx) { if (dap_chain_hash_fast_from_str(spent_by_tx, &l_tx_hash)) { - printf("Invalid transaction hash format in response\n"); json_object_put(l_json_response); - return -8; + return DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH; } l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash); snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_net_str); - json_object *l_json_prev_tx = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, a_net_str); + json_object *l_json_prev_tx = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); if (!l_json_prev_tx) { - printf("Previous transaction %s is not found\n", l_tx_hash_str_tmp); json_object_put(l_json_response); - return -12; + return DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND; } json_object_put(l_json_prev_tx); break; @@ -3193,15 +3280,14 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) } } - if (l_tx_hash_str) { + if (a_tx_hash_str) { char data[512]; snprintf(data, sizeof(data), - "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", l_net_str); - json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", a_net_str); + json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); if (!l_json_coins) { - printf("Error: Failed to retrieve coins from ledger\n"); json_object_put(l_json_response); - return -4; + return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR; } bool tx_exists = false; @@ -3210,36 +3296,36 @@ int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv) json_object *tx_item = json_object_array_get_idx(l_json_coins, i); const char *tx_hash = json_object_get_string(json_object_object_get(tx_item, "tx_hash")); if (tx_hash && strcmp(tx_hash, l_tx_hash_str_tmp) == 0) { - printf("Error: Transaction %s already exists in the ledger\n", l_tx_hash_str_tmp); json_object_put(l_json_coins); json_object_put(l_json_response); - return -13; + return DAP_CLI_STAKE_INVALIDATE_TX_EXISTS; } } json_object_put(l_json_coins); } dap_chain_datum_tx_t *l_tx = NULL; - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path,NULL); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path,NULL); if (!l_wallet) { - printf("Specified wallet not found\n"); json_object_put(l_json_response); - return -14; + return DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND; } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); - l_tx = dap_stake_tx_invalidate_compose(l_net_str, &l_tx_hash, l_fee, l_enc_key, l_url_str, l_port); - json_object * l_json_obj_ret = json_object_new_object(); - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); - printf("%s", json_object_to_json_string(l_json_obj_ret)); - json_object_put(l_json_obj_ret); + int l_ret = 0; + l_tx = dap_stake_tx_invalidate_compose(a_net_str, &l_tx_hash, a_fee, l_enc_key, a_url_str, a_port, &l_ret); + if (!l_tx) { + json_object_put(l_json_response); + return l_ret; + } + dap_chain_net_tx_to_json(l_tx, a_json_obj_ret); + dap_chain_wallet_close(l_wallet); dap_enc_key_delete(l_enc_key); json_object_put(l_json_response); - return 0; + return DAP_CLI_STAKE_INVALIDATE_OK; } - -dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port) +dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, int *l_ret) { if(!a_net_str || !*a_net_str || !a_tx_hash || !a_key || !l_url_str || !*l_url_str || l_port == 0) return NULL; @@ -3250,14 +3336,14 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); if (!response) { - printf("Error: Failed to get response from remote node\n"); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR; return NULL; } json_object *l_items_array = json_object_array_get_idx(response, 0); l_items_array = json_object_object_get(l_items_array, "ITEMS"); if (!l_items_array) { - printf("Error: ITEMS array not found in JSON response\n"); json_object_put(response); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND; return NULL; } @@ -3265,8 +3351,8 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (l_unspent_outs) { const char *all_unspent = json_object_get_string(l_unspent_outs); if (all_unspent && strcmp(all_unspent, "yes") == 0) { - printf("Error: All outputs are spent\n"); json_object_put(response); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT; return NULL; } } @@ -3287,9 +3373,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap } else if (item_type && strcmp(item_type, "IN COND") == 0) { l_tx_prev_hash = json_object_get_string(json_object_object_get(l_item, "Tx_prev_hash")); if (!l_tx_prev_hash) { - printf("Error: Tx_prev_hash not found in ITEMS array\n"); json_object_put(response); DAP_DELETE(l_tx_out_cond); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND; return NULL; } l_prev_cond_idx = json_object_get_int(json_object_object_get(l_item, "Tx_out_prev_idx")); @@ -3299,9 +3385,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object *response_cond = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); if (!response_cond) { - printf("Error: Request conditional transaction failed\n"); json_object_put(response); DAP_DELETE(l_tx_out_cond); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR; return NULL; } json_object_put(response_cond); @@ -3309,9 +3395,9 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap } if (!l_tx_out_cond || !l_tx_prev_hash) { - printf("Error: Required conditional transaction structures not found\n"); json_object_put(response); DAP_DELETE(l_tx_out_cond); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND; return NULL; } @@ -3326,17 +3412,17 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap } if (!l_sig_item) { - printf("Error: SIG item not found in ITEMS array\n"); json_object_put(response); DAP_DELETE(l_tx_out_cond); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND; return NULL; } const char *l_sign_b64_str = json_object_get_string(json_object_object_get(l_sig_item, "sig_b64")); if (!l_sign_b64_str) { - printf("Error: Can't get base64-encoded sign from SIG item\n"); json_object_put(response); DAP_DELETE(l_tx_out_cond); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR; return NULL; } @@ -3356,10 +3442,10 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap dap_chain_addr_t l_wallet_addr; dap_chain_addr_fill_from_key(&l_wallet_addr, a_key, s_get_net_id(a_net_str)); if (!dap_chain_addr_compare(&l_owner_addr, &l_wallet_addr)) { - printf("Trying to invalidate delegating tx with not a owner wallet\n"); json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER; return NULL; } @@ -3370,10 +3456,10 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!token_ticker_obj) { token_ticker_obj = json_object_object_get(l_json_tiker, "token ticker"); if (!token_ticker_obj) { - printf("Error: Token ticker not found in response\n"); json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND; return NULL; } } @@ -3384,6 +3470,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND; return NULL; } @@ -3400,11 +3487,11 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap l_fee_total, &l_fee_transfer); if (!l_list_fee_out) { - printf("Not enough funds to pay fee"); json_object_put(l_outs_native); json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS; return NULL; } @@ -3418,23 +3505,23 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); dap_list_free_full(l_list_fee_out, NULL); if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { - printf("Can't compose the transaction input\n"); dap_chain_datum_tx_delete(l_tx); json_object_put(l_outs_native); json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR; return NULL; } // add 'out_ext' item if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_tx_out_cond->header.value, l_delegated_ticker) == -1) { dap_chain_datum_tx_delete(l_tx); - printf("Cant add returning coins output\n"); json_object_put(l_outs_native); json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR; return NULL; } // add fee items @@ -3445,6 +3532,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR; return NULL; } } @@ -3455,6 +3543,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR; return NULL; } } @@ -3468,6 +3557,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); + if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR; return NULL; } } diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 78c4cee86e..eed34cd883 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -62,11 +62,47 @@ int dap_tx_cond_create_compose(int argc, char ** argv); int dap_cli_hold_compose(int a_argc, char **a_argv); int dap_cli_take_compose(int a_argc, char **a_argv); int dap_cli_voting_compose(int a_argc, char **a_argv); -int dap_cli_srv_stake_invalidate_compose(int a_argc, char **a_argv); +int dap_compose_srv_stake_invalidate(int a_argc, char **a_argv); int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv); + +typedef enum { + DAP_CLI_STAKE_INVALIDATE_OK = 0, + DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND = -1, + DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING = -2, + DAP_CLI_STAKE_INVALIDATE_WRONG_CERT = -3, + DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR = -4, + DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH = -5, + DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED = -6, + DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT = -7, + DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND = -8, + DAP_CLI_STAKE_INVALIDATE_TX_EXISTS = -9, + DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND = -10, + DAP_CLI_STAKE_INVALIDATE_COMPOSE_ERROR = -11, + DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR = -12, + DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND = -13, + DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT = -14, + DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND = -15, + DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR = -16, + DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND = -17, + DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND = -18, + DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR = -19, + DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER = -20, + DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND = -21, + DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND = -22, + DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS = -23, + DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR = -24, + DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR = -25, + DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR = -26, + DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27, + DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28 +} dap_cli_stake_invalidate_error_t; +int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, + const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port); +dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, int *l_ret); + json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port); int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); @@ -104,7 +140,6 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port); -dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port); dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, -- GitLab From ca166c2f5dcd3ba755ecb8bf5373c799df51a5d0 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Wed, 9 Apr 2025 16:15:17 +0700 Subject: [PATCH 41/53] [*] delegate --- modules/compose/dap_chain_tx_compose.c | 438 ++++-------------- .../compose/include/dap_chain_tx_compose.h | 45 +- 2 files changed, 138 insertions(+), 345 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 99751e1b64..9306e634de 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -3010,166 +3010,6 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c */ -int dap_compose_srv_stake_invalidate(int a_argc, char **a_argv) -{ - const char *l_net_str = NULL, - *l_wallet_str = NULL, - *l_cert_str = NULL, - *l_fee_str = NULL, - *l_tx_hash_str = NULL, - *l_url_str = NULL, - *l_port_str = NULL; - uint16_t l_port = 0; - - int l_arg_index = 1; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); - if (!l_net_str) { - printf("Command 'invalidate' requires parameter -net\n"); - return -1; - } - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { - l_url_str = s_get_net_url(l_net_str); - } - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { - l_port = s_get_net_port(l_net_str); - } else { - l_port = atoi(l_port_str); - } - - const char *l_wallet_path = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); - if (!l_wallet_path) { - arg_wallets_path = - #ifdef DAP_OS_WINDOWS - dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); - #elif defined DAP_OS_MAC - dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); - #elif defined DAP_OS_UNIX - dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); - #endif - } else { - arg_wallets_path = dap_strdup(l_wallet_path); - } - - uint256_t l_fee = {}; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); - if (!l_wallet_str) { - printf("Command 'invalidate' requires parameter -w\n"); - return -1; - } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); - if (!l_fee_str) { - printf("Command 'delegate' requires parameter -fee\n"); - return -1; - } - l_fee = dap_chain_balance_scan(l_fee_str); - if (IS_ZERO_256(l_fee)) { - printf("Unrecognized number in '-fee' param\n"); - return -1; - } - - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tx", &l_tx_hash_str); - if (!l_tx_hash_str) { - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str); - if (!l_cert_str) { - printf("Command 'invalidate' requires parameter -tx or -cert\n"); - return -1; - } - } - json_object *l_json_obj_ret = json_object_new_object(); - int ret = dap_cli_srv_stake_invalidate_compose(l_json_obj_ret, l_net_str, l_tx_hash_str, l_wallet_str, l_wallet_path, l_cert_str, l_fee, l_url_str, l_port); - switch (ret) { - case DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND: - printf("Error: Specified certificate not found\n"); - break; - case DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING: - printf("Error: It is not possible to invalidate a stake using a public key.\n"); - break; - case DAP_CLI_STAKE_INVALIDATE_WRONG_CERT: - printf("Error: Specified certificate is wrong\n"); - break; - case DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR: - printf("Error: Failed to retrieve coins from ledger\n"); - break; - case DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH: - printf("Error: Invalid transaction hash format\n"); - break; - case DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED: - printf("Error: Specified address is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n"); - break; - case DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT: - printf("Error: Transaction does not have a delegate out\n"); - break; - case DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND: - printf("Error: Previous transaction is not found\n"); - break; - case DAP_CLI_STAKE_INVALIDATE_TX_EXISTS: - printf("Error: Transaction already exists in the ledger\n"); - break; - case DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND: - printf("Error: Specified wallet not found\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR: - printf("Error: Failed to get response from remote node\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND: - printf("Error: ITEMS array not found in JSON response\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT: - printf("Error: All outputs are spent\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND: - printf("Error: Tx_prev_hash not found in ITEMS array\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR: - printf("Error: Request conditional transaction failed\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND: - printf("Error: Required conditional transaction structures not found\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND: - printf("Error: SIG item not found in ITEMS array\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR: - printf("Error: Can't get base64-encoded sign from SIG item\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER: - printf("Trying to invalidate delegating tx with not a owner wallet\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND: - printf("Error: Token ticker not found in response\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND: - printf("Error: Failed to get transaction outputs\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS: - printf("Error: Not enough funds to pay fee\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR: - printf("Error: Can't compose the transaction input\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR: - printf("Error:Cant add returning coins output\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR: - printf("Error: Can't add network fee output\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR: - printf("Error: Can't add fee output\n"); - break; - case DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR: - printf("Error: Can't add fee back output\n"); - break; - case DAP_CLI_STAKE_INVALIDATE_OK: - printf("%s", json_object_to_json_string(l_json_obj_ret)); - break; - default: - printf("Error: Unknown error code: %d\n", ret); - } - - json_object_put(l_json_obj_ret); - return ret; -} int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port) @@ -3703,195 +3543,118 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o -int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) -{ - int l_arg_index = 0; - const char *l_net_str = NULL, - *l_wallet_str = NULL, - *l_cert_str = NULL, - *l_pkey_str = NULL, - *l_pkey_full_str = NULL, - *l_sign_type_str = NULL, - *l_value_str = NULL, - *l_fee_str = NULL, - *l_node_addr_str = NULL, - *l_order_hash_str = NULL, - *l_url_str = NULL, - *l_port_str = NULL; - int l_port = 0; - - dap_pkey_t *l_pkey = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); - if (!l_net_str) { - printf("Command 'delegate' requires parameter -net\n"); - return -1; - } - - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { - l_url_str = s_get_net_url(l_net_str); - } - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { - l_port = s_get_net_port(l_net_str); - } else { - l_port = atoi(l_port_str); - } - - const char *l_wallet_path = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); - if (!l_wallet_path) { - arg_wallets_path = - #ifdef DAP_OS_WINDOWS - dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); - #elif defined DAP_OS_MAC - dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); - #elif defined DAP_OS_UNIX - dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); - #endif - } else { - arg_wallets_path = dap_strdup(l_wallet_path); - } - - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); - if (!l_wallet_str) { - printf("Command 'delegate' requires parameter -w\n"); - return -1; - } - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL); +int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, + const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, + const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str) { + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, arg_wallets_path, NULL); if (!l_wallet) { printf("Specified wallet not found\n"); - return -2; + return STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND; } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); dap_chain_wallet_close(l_wallet); dap_chain_addr_t l_signing_addr, l_sovereign_addr = {}; uint256_t l_sovereign_tax = uint256_0; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str); - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-pkey_full", &l_pkey_full_str); - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-sign_type", &l_sign_type_str); - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str); - if (!l_cert_str && !l_order_hash_str && !l_pkey_full_str) { - printf("Command 'delegate' requires parameter -cert and/or -order and/or -pkey\n"); - dap_enc_key_delete(l_enc_key); - return -1; - } - if (l_pkey_full_str) { - printf("Command 'delegate' requires only one, -pkey or -pkey_full\n"); - dap_enc_key_delete(l_enc_key); - return -1; - } - if (( l_pkey_full_str) && !l_sign_type_str) { - printf("Command 'delegate' requires parameter -sign_type for pkey\n"); - dap_enc_key_delete(l_enc_key); - return -1; - } uint256_t l_value = uint256_0; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); - if (!l_value_str) { - if (!l_order_hash_str) { - printf("Command 'delegate' requires parameter -value\n"); - dap_enc_key_delete(l_enc_key); - return -1; - } - } else { - l_value = dap_chain_balance_scan(l_value_str); + if (a_value_str) { + l_value = dap_chain_balance_scan(a_value_str); if (IS_ZERO_256(l_value)) { printf("Unrecognized number in '-value' param\n"); dap_enc_key_delete(l_enc_key); - return -1; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE; } } + dap_pkey_t *l_pkey = NULL; dap_chain_datum_tx_t *l_prev_tx = NULL; - if (l_cert_str) { - dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str); + if (a_cert_str) { + dap_cert_t *l_signing_cert = dap_cert_find_by_name(a_cert_str); if (!l_signing_cert) { printf("Specified certificate not found\n"); dap_enc_key_delete(l_enc_key); - return -3; + return STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND; } - if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(l_net_str))) { + if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(a_net_str))) { printf("Specified certificate is wrong\n"); dap_enc_key_delete(l_enc_key); - return -4; + return STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG; } l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key); - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str); - } else if (l_pkey_full_str) { - dap_sign_type_t l_type = dap_sign_type_from_str(l_sign_type_str); + } else if (a_pkey_full_str) { + dap_sign_type_t l_type = dap_sign_type_from_str(a_sign_type_str); if (l_type.type == SIG_TYPE_NULL) { printf("Wrong sign type\n"); dap_enc_key_delete(l_enc_key); - return -5; + return STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE; } - l_pkey = dap_pkey_get_from_str(l_pkey_full_str); + l_pkey = dap_pkey_get_from_str(a_pkey_full_str); if (!l_pkey) { printf("Invalid pkey string format, can't get pkey_full\n"); dap_enc_key_delete(l_enc_key); - return -6; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY; } if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) { printf("pkey and sign types is different\n"); dap_enc_key_delete(l_enc_key); - return -6; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY; } dap_chain_hash_fast_t l_hash_public_key = {0}; if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) { printf("Invalid pkey hash format\n"); dap_enc_key_delete(l_enc_key); - return -6; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY; } - dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(l_net_str)); - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str); + dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(a_net_str)); } dap_chain_node_addr_t l_node_addr = g_node_addr; - if (l_node_addr_str) { - if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) { - printf("Unrecognized node addr %s\n", l_node_addr_str); + if (a_node_addr_str) { + if (dap_chain_node_addr_from_str(&l_node_addr, a_node_addr_str)) { + printf("Unrecognized node addr %s\n", a_node_addr_str); dap_enc_key_delete(l_enc_key); - return -7; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR; } } - if (l_order_hash_str) { + if (a_order_hash_str) { uint256_t l_tax; uint256_t l_value_max; int l_prev_tx_count = 0; - dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(l_net_str, l_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, l_url_str, l_port); + dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(a_net_str, a_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, a_url_str, a_port); if (!l_order) { printf("Error: Failed to get order from remote node\n"); dap_enc_key_delete(l_enc_key); - return -8; + return STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND; } l_sovereign_tax = l_tax; if (l_order->direction == SERV_DIR_BUY) { // Staker order - if (!l_cert_str) { + if (!a_cert_str) { printf("Command 'delegate' requires parameter -cert with this order type\n"); dap_enc_key_delete(l_enc_key); - return -1; + return STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED; } if (l_order->ext_size != 0) { printf("Specified order has invalid size\n"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return -9; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE; } dap_chain_tx_out_cond_t *l_cond_tx = NULL; char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", - dap_chain_hash_fast_to_str_static(&l_order->tx_cond_hash), l_net_str); + dap_chain_hash_fast_to_str_static(&l_order->tx_cond_hash), a_net_str); - json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); if (!response) { printf("Error: Failed to get response from remote node\n"); - return -15; + return STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE; } json_object *items = json_object_object_get(response, "ITEMS"); if (!items) { printf("Error: No items found in response\n"); - return -16; + return STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS; } int items_count = json_object_array_length(items); for (int i = 0; i < items_count; i++) { @@ -3909,7 +3672,7 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr"))); if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) { printf("Error: Failed to parse signer node address\n"); - return -17; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR; } l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); l_prev_tx_count++; @@ -3921,100 +3684,98 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) } if (!l_cond_tx) { printf("Error: No transaction output condition found\n"); - return -7; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR; } json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); const char *spent_outs_value = json_object_get_string(spent_outs); if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { printf("Error: Transaction output item already used\n"); - return -9; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE; } char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; - dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(l_net_str)); + dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(a_net_str)); const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker")); if (!l_token_ticker) { printf("Error: Token ticker not found in response\n"); - return -18; + return STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER; } json_object_put(response); if (dap_strcmp(l_token_ticker, l_delegated_ticker)) { printf("Requested conditional transaction have another ticker (not %s)\n", l_delegated_ticker); - return -13; + return STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER; } if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) { printf("The order's conditional transaction has invalid format\n"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return -14; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT; } if (compare256(l_cond_tx->header.value, l_order->price)) { printf("The order's conditional transaction has different value\n"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return -15; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE; } if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) || l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) { printf("The order's conditional transaction gas not blank address or key\n"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return -16; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR; } l_value = l_order->price; } else { - if (!l_value_str) { + if (!a_value_str) { printf("Command 'delegate' requires parameter -value with this order type\n"); dap_enc_key_delete(l_enc_key); - return -1; + return STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED; } - const char *l_sovereign_addr_str = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str); - if (l_sovereign_addr_str) { - dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str); + if (a_sovereign_addr_str) { + dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(a_sovereign_addr_str); if (!l_spec_addr) { printf("Specified address is ivalid\n"); - return -17; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR; } l_sovereign_addr = *l_spec_addr; DAP_DELETE(l_spec_addr); } else - dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, s_get_net_id(l_net_str)); + dap_chain_addr_fill_from_key(&l_sovereign_addr, l_enc_key, s_get_net_id(a_net_str)); - if (l_order_hash_str && compare256(l_value, l_order->price) == -1) { + if (a_order_hash_str && compare256(l_value, l_order->price) == -1) { const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_order->price, &l_coin_min_str); printf("Number in '-value' param %s is lower than order minimum allowed value %s(%s)\n", - l_value_str, l_coin_min_str, l_value_min_str); + a_value_str, l_coin_min_str, l_value_min_str); dap_enc_key_delete(l_enc_key); - return -18; + return STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW; } - if (l_order_hash_str && compare256(l_value, l_value_max) == 1) { + if (a_order_hash_str && compare256(l_value, l_value_max) == 1) { const char *l_coin_max_str, *l_value_max_str = dap_uint256_to_char(l_value_max, &l_coin_max_str); printf("Number in '-value' param %s is higher than order minimum allowed value %s(%s)\n", - l_value_str, l_coin_max_str, l_value_max_str); + a_value_str, l_coin_max_str, l_value_max_str); dap_enc_key_delete(l_enc_key); - return -19; + return STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH; } size_t l_sign_size = 0; - dap_sign_t *l_sign = dap_get_remote_srv_order_sign(l_net_str, l_order_hash_str, l_url_str, l_port); + dap_sign_t *l_sign = dap_get_remote_srv_order_sign(a_net_str, a_order_hash_str, a_url_str, a_port); if (!l_sign) { printf("Specified order is unsigned\n"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return -20; + return STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER; } - dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, s_get_net_id(l_net_str)); + dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, s_get_net_id(a_net_str)); l_pkey = dap_pkey_get_from_sign(l_sign); char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX]; - dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, s_get_native_ticker(l_net_str)); + dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, s_get_native_ticker(a_net_str)); if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) { printf("Specified order is invalid\n"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return -21; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER; } l_node_addr = l_order->node_addr; } @@ -4023,14 +3784,14 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) { printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n"); dap_enc_key_delete(l_enc_key); - return -22; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX; } DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); } if (!l_pkey) { printf("pkey not defined\n"); dap_enc_key_delete(l_enc_key); - return -6; + return STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED; } // TODO: need to make sure that the key and node are required verification @@ -4042,52 +3803,49 @@ int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv) // } - uint256_t l_allowed_min = s_get_key_delegating_min_value(l_net_str, l_url_str, l_port); + uint256_t l_allowed_min = s_get_key_delegating_min_value(a_net_str, a_url_str, a_port); if (compare256(l_value, l_allowed_min) == -1) { const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str); printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n", - l_value_str, l_coin_min_str, l_value_min_str); + a_value_str, l_coin_min_str, l_value_min_str); dap_enc_key_delete(l_enc_key); - return -23; - } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); - if (!l_fee_str) { - printf("Command 'delegate' requires parameter -fee\n"); - dap_enc_key_delete(l_enc_key); - return -1; + return STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN; } - uint256_t l_fee = dap_chain_balance_scan(l_fee_str); + + uint256_t l_fee = dap_chain_balance_scan(a_fee_str); if (IS_ZERO_256(l_fee)) { printf("Unrecognized number in '-fee' param\n"); dap_enc_key_delete(l_enc_key); - return -1; + return STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE; } - - // Create conditional transaction - dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr, - l_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, l_url_str, l_port); + int l_ret = 0; + dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(a_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr, + a_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, a_url_str, a_port, &l_ret); + dap_enc_key_delete(l_enc_key); DAP_DELETE(l_pkey); - json_object * l_json_obj_ret = json_object_new_object(); - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); - printf("%s", json_object_to_json_string(l_json_obj_ret)); - json_object_put(l_json_obj_ret); + if (l_ret) { + return l_ret; + } + dap_chain_net_tx_to_json(l_tx, a_json_obj_ret); DAP_DELETE(l_tx); - return 0; + return STAKE_DELEGATE_COMPOSE_OK; } -// Freeze staker's funds when delegating a key + dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, - dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port) + dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, int *l_ret) { - if (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) + if (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) { + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS; return NULL; + } const char *l_native_ticker = s_get_native_ticker(a_net_str); char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker); @@ -4106,11 +3864,13 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); if (!l_outs_native) { + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE; return NULL; } json_object *l_outs_delegated = dap_get_remote_tx_outs(l_delegated_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); if (!l_outs_delegated) { + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE; return NULL; } @@ -4121,9 +3881,9 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en l_fee_total, &l_fee_transfer); if (!l_list_fee_out) { - printf("Not enough funds to pay fee"); json_object_put(l_outs_native); json_object_put(l_outs_delegated); + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE; return NULL; } @@ -4135,16 +3895,16 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en a_value, &l_value_transfer); if (!l_list_used_out) { - printf("Not enough funds to pay fee"); json_object_put(l_outs_native); json_object_put(l_outs_delegated); + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE; return NULL; } // add 'in' items to pay for delegate uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); dap_list_free_full(l_list_used_out, NULL); if (!EQUAL_256(l_value_to_items, l_value_transfer)) { - printf("Can't compose the transaction input\n"); + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR; goto tx_fail; } } else { @@ -4154,7 +3914,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); // add 'in' item to buy from conditional transaction if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_out_num, -1)) { - printf("Can't compose the transaction conditional input\n"); + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR; goto tx_fail; } } @@ -4162,7 +3922,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); dap_list_free_full(l_list_fee_out, NULL); if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { - printf("Can't compose the fee transaction input\n"); + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR; goto tx_fail; } @@ -4172,7 +3932,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en a_sovereign_addr, a_sovereign_tax, a_pkey); if (!l_tx_out) { - printf("Can't compose the transaction conditional output\n"); + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR; goto tx_fail; } dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); @@ -4183,7 +3943,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back); if (!IS_ZERO_256(l_value_back)) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) { - printf("Cant add coin back output\n"); + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR; goto tx_fail; } } @@ -4192,13 +3952,13 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en // add fee items if (l_net_fee_used) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { - printf("Cant add net fee output\n"); + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR; goto tx_fail; } } if (!IS_ZERO_256(a_fee)) { if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { - printf("Cant add validator fee output\n"); + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR; goto tx_fail; } } @@ -4207,17 +3967,11 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back); if (!IS_ZERO_256(l_fee_back)) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) { - printf("Cant add fee back output\n"); + if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR; goto tx_fail; } } - // // add 'sign' item - // if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key) != 1) { - // printf("Can't add sign output\n"); - // goto tx_fail; - // } - return l_tx; tx_fail: diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index eed34cd883..221b35b954 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -62,12 +62,51 @@ int dap_tx_cond_create_compose(int argc, char ** argv); int dap_cli_hold_compose(int a_argc, char **a_argv); int dap_cli_take_compose(int a_argc, char **a_argv); int dap_cli_voting_compose(int a_argc, char **a_argv); -int dap_compose_srv_stake_invalidate(int a_argc, char **a_argv); -int dap_cli_srv_stake_delegate_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv); int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv); - +typedef enum { + STAKE_DELEGATE_COMPOSE_OK = 0, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE = -1, + STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND = -2, + STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND = -3, + STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG = -4, + STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE = -5, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY = -6, + STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED = -6, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR = -7, + STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND = -8, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE = -9, + STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED = -10, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED = -11, + STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER = -13, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT = -14, + STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE = -15, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE = -15, + STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS = -16, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR = -16, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR = -17, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR = -17, + STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER = -18, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW = -18, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH = -19, + STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER = -20, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER = -21, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX = -22, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN = -23, + DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS = -24, + DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE = -25, + DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE = -26, + DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR = -27, + DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR = -28, + DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR = -29, + DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR = -30, + DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -31, + DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -32 +} stake_delegate_error_t; +int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, + const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, + const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str); typedef enum { DAP_CLI_STAKE_INVALIDATE_OK = 0, DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND = -1, -- GitLab From 5d5bd7ce870cb1d9a2bed594dbef1d390052fcdd Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Wed, 9 Apr 2025 16:34:41 +0700 Subject: [PATCH 42/53] [*] fix build --- modules/compose/dap_chain_tx_compose.c | 134 ++++++++---------- .../compose/include/dap_chain_tx_compose.h | 65 +++++---- 2 files changed, 92 insertions(+), 107 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 9306e634de..f0b96bcc50 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -41,45 +41,41 @@ #include <json-c/json.h> - - -const char *arg_wallets_path = NULL; - -static const char* s_get_native_ticker(const char* name) { +const char* dap_compose_get_net_url(const char* name) { for (int i = 0; i < NET_COUNT; i++) { if (strcmp(netinfo[i].name, name) == 0) { - return netinfo[i].native_ticker; + return netinfo[i].url; } } return NULL; } -static dap_chain_net_id_t s_get_net_id(const char* name) { +uint16_t dap_compose_get_net_port(const char* name) { for (int i = 0; i < NET_COUNT; i++) { if (strcmp(netinfo[i].name, name) == 0) { - return netinfo[i].net_id; + return netinfo[i].port; } } - dap_chain_net_id_t empty_id = {.uint64 = 0}; - return empty_id; + return 0; } -static const char* s_get_net_url(const char* name) { +static const char* s_get_native_ticker(const char* name) { for (int i = 0; i < NET_COUNT; i++) { if (strcmp(netinfo[i].name, name) == 0) { - return netinfo[i].url; + return netinfo[i].native_ticker; } } return NULL; } -static uint16_t s_get_net_port(const char* name) { +static dap_chain_net_id_t s_get_net_id(const char* name) { for (int i = 0; i < NET_COUNT; i++) { if (strcmp(netinfo[i].name, name) == 0) { - return netinfo[i].port; + return netinfo[i].net_id; } } - return 0; + dap_chain_net_id_t empty_id = {.uint64 = 0}; + return empty_id; } @@ -266,8 +262,8 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a } dap_client_http_request(dap_worker_get_auto(), - a_url_str ? a_url_str : s_get_net_url(a_net_name), - a_port ? a_port : s_get_net_port(a_net_name), + a_url_str ? a_url_str : dap_compose_get_net_url(a_net_name), + a_port ? a_port : dap_compose_get_net_port(a_net_name), "POST", "application/json", NULL, request, strlen(request), NULL, s_cmd_response_handler, s_cmd_error_handler, @@ -442,7 +438,7 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) { const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); if (!l_wallet_path) { - arg_wallets_path = + l_wallet_path = #ifdef DAP_OS_WINDOWS dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); #elif defined DAP_OS_MAC @@ -450,8 +446,6 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) { #elif defined DAP_OS_UNIX dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); #endif - } else { - arg_wallets_path = dap_strdup(l_wallet_path); } dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); @@ -470,11 +464,11 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) { } if (!l_url_str) { - l_url_str = s_get_net_url(l_net_name); + l_url_str = dap_compose_get_net_url(l_net_name); } if (!l_port_str) { - l_port = s_get_net_port(l_net_name); + l_port = dap_compose_get_net_port(l_net_name); } else { l_port = atoi(l_port_str); } @@ -509,7 +503,7 @@ int dap_tx_create_xchange_compose(int argc, char ** argv) { return -1; } - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, arg_wallets_path, NULL); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL); if(!l_wallet) { printf("wallet %s does not exist", l_wallet_name); return -1; @@ -560,7 +554,7 @@ int dap_tx_create_compose(int argc, char ** argv) { const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); if (!l_wallet_path) { - arg_wallets_path = + l_wallet_path = #ifdef DAP_OS_WINDOWS dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); #elif defined DAP_OS_MAC @@ -568,9 +562,7 @@ int dap_tx_create_compose(int argc, char ** argv) { #elif defined DAP_OS_UNIX dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); #endif - } else { - arg_wallets_path = dap_strdup(l_wallet_path); - } + } dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); if (!l_net_name) { @@ -579,11 +571,11 @@ int dap_tx_create_compose(int argc, char ** argv) { } if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str)) { - l_url_str = s_get_net_url(l_net_name); + l_url_str = dap_compose_get_net_url(l_net_name); } const char *l_port_str = NULL; if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str)) { - l_port = s_get_net_port(l_net_name); + l_port = dap_compose_get_net_port(l_net_name); } else { l_port = atoi(l_port_str); } @@ -688,7 +680,7 @@ int dap_tx_create_compose(int argc, char ** argv) { DAP_DELETE(l_addr_base58_to_array); } - dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, arg_wallets_path, NULL); + dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, l_wallet_path, NULL); if(!l_wallet) { printf("Can't open wallet %s", l_from_wallet_name); return -12; @@ -1331,7 +1323,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv) const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); if (!l_wallet_path) { - arg_wallets_path = + l_wallet_path = #ifdef DAP_OS_WINDOWS dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); #elif defined DAP_OS_MAC @@ -1339,9 +1331,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv) #elif defined DAP_OS_UNIX dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); #endif - } else { - arg_wallets_path = dap_strdup(l_wallet_path); - } + } dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker); dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_str); @@ -1379,10 +1369,10 @@ int dap_tx_cond_create_compose(int argc, char ** argv) return -7; } if(!l_url_str) { - l_url_str = s_get_net_url(l_net_name); + l_url_str = dap_compose_get_net_url(l_net_name); } if(!l_port_str) { - l_port = s_get_net_port(l_net_name); + l_port = dap_compose_get_net_port(l_net_name); } else { l_port = atoi(l_port_str); } @@ -1421,7 +1411,7 @@ int dap_tx_cond_create_compose(int argc, char ** argv) return -13; } - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); if(!l_wallet) { printf("Can't open wallet '%s'\n", l_wallet_str); return -15; @@ -1566,7 +1556,6 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL, *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL; - const char *l_wallets_path = arg_wallets_path; char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; dap_time_t l_time_staking = 0; uint256_t l_reinvest_percent = {}; @@ -1582,7 +1571,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); if (!l_wallet_path) { - arg_wallets_path = + l_wallet_path = #ifdef DAP_OS_WINDOWS dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); #elif defined DAP_OS_MAC @@ -1590,9 +1579,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) #elif defined DAP_OS_UNIX dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); #endif - } else { - arg_wallets_path = dap_strdup(l_wallet_path); - } + } const char *l_hash_out_type = NULL; @@ -1615,12 +1602,12 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) } if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) { - l_url_str = s_get_net_url(l_net_name); + l_url_str = dap_compose_get_net_url(l_net_name); } const char *l_port_str = NULL; if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) { - l_port = s_get_net_port(l_net_name); + l_port = dap_compose_get_net_port(l_net_name); } else { l_port = atoi(l_port_str); } @@ -1743,7 +1730,7 @@ int dap_cli_hold_compose(int a_argc, char **a_argv) } } - if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallets_path, NULL))) { + if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) { printf("Error: Unable to open wallet '%s'\n", l_wallet_str); return -22; } @@ -1971,7 +1958,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv) const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); if (!l_wallet_path) { - arg_wallets_path = + l_wallet_path = #ifdef DAP_OS_WINDOWS dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); #elif defined DAP_OS_MAC @@ -1979,9 +1966,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv) #elif defined DAP_OS_UNIX dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); #endif - } else { - arg_wallets_path = dap_strdup(l_wallet_path); - } + } const char *l_hash_out_type = NULL; @@ -1999,12 +1984,12 @@ int dap_cli_take_compose(int a_argc, char **a_argv) } if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) { - l_url_str = s_get_net_url(l_net_str); + l_url_str = dap_compose_get_net_url(l_net_str); } const char *l_port_str = NULL; if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) { - l_port = s_get_net_port(l_net_str); + l_port = dap_compose_get_net_port(l_net_str); } else { l_port = atoi(l_port_str); } @@ -2117,7 +2102,7 @@ int dap_cli_take_compose(int a_argc, char **a_argv) return -15; } - if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL))) { + if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) { printf("Error: Unable to open wallet\n"); return -16; } @@ -2379,7 +2364,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); if (!l_wallet_path) { - arg_wallets_path = + l_wallet_path = #ifdef DAP_OS_WINDOWS dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); #elif defined DAP_OS_MAC @@ -2387,9 +2372,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) #elif defined DAP_OS_UNIX dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); #endif - } else { - arg_wallets_path = dap_strdup(l_wallet_path); - } + } dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); // Select chain network @@ -2399,12 +2382,12 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) } if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-url", &l_url_str)) { - l_url_str = s_get_net_url(l_net_str); + l_url_str = dap_compose_get_net_url(l_net_str); } const char *l_port_str = NULL; if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str)) { - l_port = s_get_net_port(l_net_str); + l_port = dap_compose_get_net_port(l_net_str); } else { l_port = atoi(l_port_str); } @@ -2466,7 +2449,7 @@ int dap_cli_voting_compose(int a_argc, char **a_argv) bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false; bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false; - dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, arg_wallets_path, NULL); + dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); if (!l_wallet_fee) { printf("Wallet %s does not exist\n", l_wallet_str); return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; @@ -2740,8 +2723,8 @@ int dap_cli_vote_compose(int a_argc, char **a_argv){ return -DAP_CHAIN_NET_VOTE_VOTING_OPTION_IDX_PARAM_NOT_VALID; } - const char *arg_wallets_path = dap_chain_wallet_get_path(g_config); - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, arg_wallets_path,NULL); + const char *l_wallet_path = dap_chain_wallet_get_path(g_config); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path,NULL); if (!l_wallet) { printf("Wallet %s does not exist\n", l_wallet_str); return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST; @@ -3545,8 +3528,8 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, - const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str) { - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, arg_wallets_path, NULL); + const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path) { + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallets_path, NULL); if (!l_wallet) { printf("Specified wallet not found\n"); return STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND; @@ -3985,9 +3968,10 @@ static dap_chain_datum_tx_t *dap_order_tx_create_compose(const char * a_net_str, const char *l_url_str, int l_port) { dap_chain_node_addr_t l_node_addr = {}; + int l_ret = 0; return dap_stake_tx_create_compose(a_net_str, a_key, a_value, a_fee, (dap_chain_addr_t *)&c_dap_chain_addr_blank, &l_node_addr, - a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port); + a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, &l_ret); } //srv_stake order create staker -net <net_name> -w <wallet_with_m_tokens> -value <stake_value> -fee <value> -tax <percent> [-addr <for_tax_collecting>] [-cert <for_order_signing>] [-H {hex(default) | base58}] @@ -4009,10 +3993,10 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { } if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { - l_url_str = s_get_net_url(l_net_str); + l_url_str = dap_compose_get_net_url(l_net_str); } if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { - l_port = s_get_net_port(l_net_str); + l_port = dap_compose_get_net_port(l_net_str); } else { l_port = atoi(l_port_str); } @@ -4020,7 +4004,7 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); if (!l_wallet_path) { - arg_wallets_path = + l_wallet_path = #ifdef DAP_OS_WINDOWS dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); #elif defined DAP_OS_MAC @@ -4028,9 +4012,7 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { #elif defined DAP_OS_UNIX dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); #endif - } else { - arg_wallets_path = dap_strdup(l_wallet_path); - } + } if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str) || !l_value_str) { printf("Staker order creation requires parameter -value\n"); @@ -4133,10 +4115,10 @@ int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) { } if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { - l_url_str = s_get_net_url(l_net_str); + l_url_str = dap_compose_get_net_url(l_net_str); } if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { - l_port = s_get_net_port(l_net_str); + l_port = dap_compose_get_net_port(l_net_str); } else { l_port = atoi(l_port_str); } @@ -4144,7 +4126,7 @@ int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) { const char *l_wallet_path = NULL; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); if (!l_wallet_path) { - arg_wallets_path = + l_wallet_path = #ifdef DAP_OS_WINDOWS dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); #elif defined DAP_OS_MAC @@ -4152,9 +4134,7 @@ int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) { #elif defined DAP_OS_UNIX dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); #endif - } else { - arg_wallets_path = dap_strdup(l_wallet_path); - } + } dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); if (!l_wallet_str) { @@ -4611,7 +4591,7 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net // printf("Error: Command 'purchase' requires parameter -w\n"); // return -1; // } -// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, arg_wallets_path, NULL); +// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL); // if (!l_wallet) { // printf("Error: Specified wallet not found\n"); // return -2; diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 221b35b954..24cd70ee3e 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -52,6 +52,11 @@ static NetInfo netinfo[NET_COUNT] = { {"subzero", "tCELL", {.uint64 = 0x000000000000acca}, "http://rpc.cellframe.net", 8081} }; + +const char* dap_compose_get_net_url(const char* name); +uint16_t dap_compose_get_net_port(const char* name); + + #ifdef __cplusplus extern "C" { #endif @@ -68,45 +73,45 @@ int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv); typedef enum { STAKE_DELEGATE_COMPOSE_OK = 0, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE = -1, - STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND = -2, + STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND = -2, STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND = -3, STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG = -4, STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE = -5, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY = -6, - STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED = -6, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR = -7, - STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND = -8, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE = -9, - STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED = -10, - STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED = -11, + STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED = -7, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR = -8, + STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND = -9, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE = -10, + STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED = -11, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED = -12, STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER = -13, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT = -14, STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE = -15, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE = -15, - STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS = -16, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR = -16, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR = -17, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR = -17, - STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER = -18, - STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW = -18, - STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH = -19, - STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER = -20, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER = -21, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX = -22, - STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN = -23, - DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS = -24, - DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE = -25, - DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE = -26, - DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR = -27, - DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR = -28, - DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR = -29, - DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR = -30, - DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -31, - DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -32 + STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE = -16, + STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS = -17, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR = -18, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR = -19, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR = -20, + STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER = -21, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW = -22, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH = -23, + STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER = -24, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER = -25, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX = -26, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN = -27, + DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS = -28, + DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE = -29, + DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE = -30, + DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR = -31, + DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR = -32, + DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR = -33, + DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR = -34, + DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -35, + DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -36 } stake_delegate_error_t; int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, - const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str); + const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path); typedef enum { DAP_CLI_STAKE_INVALIDATE_OK = 0, DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND = -1, @@ -183,7 +188,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, - dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port); + dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, int *l_ret); dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port); -- GitLab From 922f20d6e668e297f3c73a994be609b9a094ab88 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Wed, 9 Apr 2025 16:56:46 +0700 Subject: [PATCH 43/53] [*] create staker --- modules/compose/dap_chain_tx_compose.c | 98 ++++--------------- .../compose/include/dap_chain_tx_compose.h | 14 ++- 2 files changed, 30 insertions(+), 82 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index f0b96bcc50..ed84d7b71b 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -3832,7 +3832,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en const char *l_native_ticker = s_get_native_ticker(a_net_str); char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker); - uint256_t l_value_transfer = {}, l_fee_transfer = {}; // how many coins to transfer + uint256_t l_value_transfer = {}, l_fee_transfer = {}; // list of transaction with 'out' items to sell dap_chain_addr_t l_owner_addr; dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str)); @@ -3965,94 +3965,38 @@ tx_fail: static dap_chain_datum_tx_t *dap_order_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, uint256_t a_sovereign_tax, dap_chain_addr_t *a_sovereign_addr, - const char *l_url_str, int l_port) + const char *l_url_str, int l_port, int *l_ret) { dap_chain_node_addr_t l_node_addr = {}; - int l_ret = 0; return dap_stake_tx_create_compose(a_net_str, a_key, a_value, a_fee, (dap_chain_addr_t *)&c_dap_chain_addr_blank, &l_node_addr, - a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, &l_ret); + a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, l_ret); } -//srv_stake order create staker -net <net_name> -w <wallet_with_m_tokens> -value <stake_value> -fee <value> -tax <percent> [-addr <for_tax_collecting>] [-cert <for_order_signing>] [-H {hex(default) | base58}] -int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { - int l_arg_index = 1; - const char *l_value_str = NULL, - *l_wallet_str = NULL, - *l_tax_str = NULL, - *l_addr_str = NULL, - *l_fee_str = NULL, - *l_url_str = NULL, - *l_port_str = NULL, - *l_net_str = NULL; - int l_port = 0; - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str) || !l_net_str) { - printf("Command 'order' requires parameter -net\n"); - return -1; - } - - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { - l_url_str = dap_compose_get_net_url(l_net_str); - } - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { - l_port = dap_compose_get_net_port(l_net_str); - } else { - l_port = atoi(l_port_str); - } - const char *l_wallet_path = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); - if (!l_wallet_path) { - l_wallet_path = - #ifdef DAP_OS_WINDOWS - dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); - #elif defined DAP_OS_MAC - dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); - #elif defined DAP_OS_UNIX - dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); - #endif - } - - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str) || !l_value_str) { - printf("Staker order creation requires parameter -value\n"); - return -1; - } +int dap_cli_srv_stake_order_create_staker_compose(json_object* a_json_obj_ret, const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) { uint256_t l_value = dap_chain_balance_scan(l_value_str); if (IS_ZERO_256(l_value)) { printf("Format -value <256 bit integer>\n"); - return -2; - } - - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str) || !l_fee_str) { - printf("Staker order creation requires parameter -fee\n"); - return -3; + return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE; } uint256_t l_fee = dap_chain_balance_scan(l_fee_str); if (IS_ZERO_256(l_fee)) { printf("Format -fee <256 bit integer>\n"); - return -4; - } - - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax", &l_tax_str) || !l_tax_str) { - printf("Staker order creation requires parameter -tax\n"); - return -5; + return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE; } uint256_t l_tax = dap_chain_coins_to_balance(l_tax_str); if (compare256(l_tax, dap_chain_coins_to_balance("100.0")) == 1 || compare256(l_tax, GET_256_FROM_64(100)) == -1) { printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n"); - return -6; + return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX; } - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) { - printf("Staker order creation requires parameter -w\n"); - return -7; - } dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); if (!l_wallet) { printf("Specified wallet not found\n"); - return -8; + return STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND; } const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet); @@ -4061,42 +4005,34 @@ int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv) { if (!l_enc_key) { printf("Failed to retrieve encryption key\n"); - return -9; + return STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND; } dap_chain_addr_t l_addr = {}; - if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_addr_str) && l_addr_str) { + if (l_addr_str) { dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str); if (!l_spec_addr) { printf("Specified address is invalid\n"); DAP_DELETE(l_enc_key); - return -10; + return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR; } l_addr = *l_spec_addr; DAP_DELETE(l_spec_addr); } else dap_chain_addr_fill_from_key(&l_addr, l_enc_key, s_get_net_id(l_net_str)); DIV_256(l_tax, GET_256_FROM_64(100), &l_tax); - dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, &l_addr, l_url_str, l_port); + int l_ret = 0; + dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, &l_addr, l_url_str, l_port, &l_ret); DAP_DEL_Z(l_enc_key); - if (!l_tx) { - printf("Failed to create transaction\n"); - return -11; + if (l_ret) { + return l_ret; } - json_object *l_json_obj_ret = json_object_new_object(); - if (!l_json_obj_ret) { - printf("Failed to create JSON object\n"); - DAP_DELETE(l_tx); - return -12; - } + dap_chain_net_tx_to_json(l_tx, a_json_obj_ret); - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); - printf("%s", json_object_to_json_string(l_json_obj_ret)); - json_object_put(l_json_obj_ret); DAP_DELETE(l_tx); - return 0; + return STAKE_ORDER_CREATE_STAKER_OK; } int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) { diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 24cd70ee3e..f06ba28a1d 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -67,7 +67,19 @@ int dap_tx_cond_create_compose(int argc, char ** argv); int dap_cli_hold_compose(int a_argc, char **a_argv); int dap_cli_take_compose(int a_argc, char **a_argv); int dap_cli_voting_compose(int a_argc, char **a_argv); -int dap_cli_srv_stake_order_create_staker_compose(int a_argc, char **a_argv); +typedef enum { + STAKE_ORDER_CREATE_STAKER_OK = 0, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -2, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -4, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -6, + STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -8, + STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -9, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -10, + STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -11, + STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -12 +} dap_cli_srv_stake_order_create_staker_error_t; +int dap_cli_srv_stake_order_create_staker_compose(json_object* a_json_obj_ret, const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port); + int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv); typedef enum { -- GitLab From bb94dc4d090fbfa3cadbc5978a576af90199c565 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Thu, 10 Apr 2025 18:30:20 +0700 Subject: [PATCH 44/53] [*] improve error handle --- modules/compose/dap_chain_tx_compose.c | 362 ++++++++++-------- .../compose/include/dap_chain_tx_compose.h | 26 +- 2 files changed, 216 insertions(+), 172 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index ed84d7b71b..7072f557ef 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -79,6 +79,33 @@ static dap_chain_net_id_t s_get_net_id(const char* name) { } +int dap_json_compose_error_add(json_object* a_json_obj_reply, int a_code_error, const char *msg, ...) +{ + va_list args; + va_start(args, msg); + char *l_msg = dap_strdup_vprintf(msg, args); + va_end(args); + + if (!a_json_obj_reply || !json_object_is_type(a_json_obj_reply, json_type_object)) { + return -1; + } + + json_object *l_json_arr_errors = NULL; + if (!json_object_object_get_ex(a_json_obj_reply, "errors", &l_json_arr_errors)) { + l_json_arr_errors = json_object_new_array(); + json_object_object_add(a_json_obj_reply, "errors", l_json_arr_errors); + } + + json_object* l_obj_error = json_object_new_object(); + json_object_object_add(l_obj_error, "code", json_object_new_int(a_code_error)); + json_object_object_add(l_obj_error, "message", json_object_new_string(l_msg)); + json_object_array_add(l_json_arr_errors, l_obj_error); + + DAP_DEL_Z(l_msg); + return 0; +} + + int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add) { json_object *items_array; if (!json_object_object_get_ex(json_tx, "items", &items_array)) { @@ -2994,9 +3021,10 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c -int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, +json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port) { + json_object* l_json_obj_ret = json_object_new_object(); dap_hash_fast_t l_tx_hash = {}; if (a_tx_hash_str) { dap_chain_hash_fast_from_str(a_tx_hash_str, &l_tx_hash); @@ -3005,13 +3033,16 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char if (a_cert_str) { dap_cert_t *l_cert = dap_cert_find_by_name(a_cert_str); if (!l_cert) { - return DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND, "Specified certificate not found"); + return l_json_obj_ret; } if (!l_cert->enc_key->priv_key_data || l_cert->enc_key->priv_key_data_size == 0) { - return DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING, "Private key missing in certificate"); + return l_json_obj_ret; } if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, s_get_net_id(a_net_str))) { - return DAP_CLI_STAKE_INVALIDATE_WRONG_CERT; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_WRONG_CERT, "Wrong certificate"); + return l_json_obj_ret; } } const char *l_addr_str = dap_chain_addr_to_str_static(&l_signing_addr); @@ -3021,7 +3052,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); if (!l_json_coins) { - return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger"); + return l_json_obj_ret; } int items_count = json_object_array_length(l_json_coins); @@ -3033,7 +3065,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash")); if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) { json_object_put(l_json_coins); - return DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format"); + return l_json_obj_ret; } found = true; break; @@ -3041,7 +3074,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char } json_object_put(l_json_coins); if (!found) { - return DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED, "Specified certificate/pkey hash is not delegated"); + return l_json_obj_ret; } } @@ -3050,9 +3084,10 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, a_net_str); - json_object *l_json_response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); + json_object *l_json_response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); if (!l_json_response) { - return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger"); + return l_json_obj_ret; } json_object *l_json_items = json_object_array_get_idx(l_json_response, 0); @@ -3075,7 +3110,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char if (!has_delegate_out) { json_object_put(l_json_response); - return DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT, "No delegate output found in transaction"); + return l_json_obj_ret; } json_object *l_json_spents = json_object_object_get(l_json_response, "Spent OUTs"); @@ -3087,7 +3123,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char if (spent_by_tx) { if (dap_chain_hash_fast_from_str(spent_by_tx, &l_tx_hash)) { json_object_put(l_json_response); - return DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format"); + return l_json_obj_ret; } l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash); snprintf(data, sizeof(data), @@ -3095,13 +3132,15 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char json_object *l_json_prev_tx = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); if (!l_json_prev_tx) { json_object_put(l_json_response); - return DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND, "Previous transaction not found"); + return l_json_obj_ret; } json_object_put(l_json_prev_tx); break; } } } + json_object_put(l_json_response); if (a_tx_hash_str) { char data[512]; @@ -3109,8 +3148,8 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", a_net_str); json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); if (!l_json_coins) { - json_object_put(l_json_response); - return DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger"); + return l_json_obj_ret; } bool tx_exists = false; @@ -3120,35 +3159,32 @@ int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char const char *tx_hash = json_object_get_string(json_object_object_get(tx_item, "tx_hash")); if (tx_hash && strcmp(tx_hash, l_tx_hash_str_tmp) == 0) { json_object_put(l_json_coins); - json_object_put(l_json_response); - return DAP_CLI_STAKE_INVALIDATE_TX_EXISTS; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_TX_EXISTS, "Transaction already exists"); + return l_json_obj_ret; } } json_object_put(l_json_coins); } - dap_chain_datum_tx_t *l_tx = NULL; + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path,NULL); if (!l_wallet) { - json_object_put(l_json_response); - return DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND; + dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND, "Specified wallet not found"); + return l_json_obj_ret; } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); - int l_ret = 0; - l_tx = dap_stake_tx_invalidate_compose(a_net_str, &l_tx_hash, a_fee, l_enc_key, a_url_str, a_port, &l_ret); - if (!l_tx) { - json_object_put(l_json_response); - return l_ret; + dap_chain_datum_tx_t *l_tx = dap_stake_tx_invalidate_compose(a_net_str, &l_tx_hash, a_fee, l_enc_key, a_url_str, a_port, l_json_obj_ret); + if (l_tx) { + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + DAP_DELETE(l_tx); } - dap_chain_net_tx_to_json(l_tx, a_json_obj_ret); dap_chain_wallet_close(l_wallet); dap_enc_key_delete(l_enc_key); - json_object_put(l_json_response); - return DAP_CLI_STAKE_INVALIDATE_OK; + return l_json_obj_ret; } -dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, int *l_ret) +dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, json_object *a_error_handler) { if(!a_net_str || !*a_net_str || !a_tx_hash || !a_key || !l_url_str || !*l_url_str || l_port == 0) return NULL; @@ -3159,14 +3195,14 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); if (!response) { - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR, "Failed to get ledger info"); return NULL; } json_object *l_items_array = json_object_array_get_idx(response, 0); l_items_array = json_object_object_get(l_items_array, "ITEMS"); if (!l_items_array) { json_object_put(response); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND, "Items not found in ledger response"); return NULL; } @@ -3175,7 +3211,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap const char *all_unspent = json_object_get_string(l_unspent_outs); if (all_unspent && strcmp(all_unspent, "yes") == 0) { json_object_put(response); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT, "All outputs are already spent"); return NULL; } } @@ -3198,7 +3234,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!l_tx_prev_hash) { json_object_put(response); DAP_DELETE(l_tx_out_cond); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND, "Previous transaction hash not found"); return NULL; } l_prev_cond_idx = json_object_get_int(json_object_object_get(l_item, "Tx_out_prev_idx")); @@ -3210,7 +3246,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!response_cond) { json_object_put(response); DAP_DELETE(l_tx_out_cond); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR, "Failed to get conditional transaction info"); return NULL; } json_object_put(response_cond); @@ -3220,7 +3256,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!l_tx_out_cond || !l_tx_prev_hash) { json_object_put(response); DAP_DELETE(l_tx_out_cond); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND, "Conditional transaction not found"); return NULL; } @@ -3237,7 +3273,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!l_sig_item) { json_object_put(response); DAP_DELETE(l_tx_out_cond); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND, "Signature item not found"); return NULL; } @@ -3245,7 +3281,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!l_sign_b64_str) { json_object_put(response); DAP_DELETE(l_tx_out_cond); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR, "Failed to decode signature"); return NULL; } @@ -3268,7 +3304,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER, "Wrong transaction owner"); return NULL; } @@ -3282,7 +3318,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND, "Token ticker not found"); return NULL; } } @@ -3293,7 +3329,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND, "Transaction outputs not found"); return NULL; } @@ -3314,7 +3350,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS, "Not enough funds to pay fees"); return NULL; } @@ -3333,7 +3369,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR, "Error adding input items"); return NULL; } @@ -3344,7 +3380,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR, "Error adding output items"); return NULL; } // add fee items @@ -3355,7 +3391,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR, "Error adding network fee"); return NULL; } } @@ -3366,7 +3402,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR, "Error adding fee"); return NULL; } } @@ -3380,7 +3416,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (l_ret) *l_ret = DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR; + if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR, "Error adding fee back"); return NULL; } } @@ -3526,13 +3562,14 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o -int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, +json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path) { + json_object* l_json_obj_ret = json_object_new_object(); dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallets_path, NULL); if (!l_wallet) { - printf("Specified wallet not found\n"); - return STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND; + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND, "Specified wallet not found"); + return l_json_obj_ret; } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); dap_chain_wallet_close(l_wallet); @@ -3542,9 +3579,9 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* if (a_value_str) { l_value = dap_chain_balance_scan(a_value_str); if (IS_ZERO_256(l_value)) { - printf("Unrecognized number in '-value' param\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-value' param"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE; + return l_json_obj_ret; } } dap_pkey_t *l_pkey = NULL; @@ -3552,39 +3589,39 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* if (a_cert_str) { dap_cert_t *l_signing_cert = dap_cert_find_by_name(a_cert_str); if (!l_signing_cert) { - printf("Specified certificate not found\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND, "Specified certificate not found"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND; + return l_json_obj_ret; } if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(a_net_str))) { - printf("Specified certificate is wrong\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG, "Specified certificate is wrong"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG; + return l_json_obj_ret; } l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key); } else if (a_pkey_full_str) { dap_sign_type_t l_type = dap_sign_type_from_str(a_sign_type_str); if (l_type.type == SIG_TYPE_NULL) { - printf("Wrong sign type\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE, "Wrong sign type"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE; + return l_json_obj_ret; } l_pkey = dap_pkey_get_from_str(a_pkey_full_str); if (!l_pkey) { - printf("Invalid pkey string format, can't get pkey_full\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey string format, can't get pkey_full"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY; + return l_json_obj_ret; } if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) { - printf("pkey and sign types is different\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "pkey and sign types is different"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY; + return l_json_obj_ret; } dap_chain_hash_fast_t l_hash_public_key = {0}; if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) { - printf("Invalid pkey hash format\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey hash format"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY; + return l_json_obj_ret; } dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(a_net_str)); } @@ -3592,9 +3629,9 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* dap_chain_node_addr_t l_node_addr = g_node_addr; if (a_node_addr_str) { if (dap_chain_node_addr_from_str(&l_node_addr, a_node_addr_str)) { - printf("Unrecognized node addr %s\n", a_node_addr_str); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Unrecognized node addr %s", a_node_addr_str); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR; + return l_json_obj_ret; } } if (a_order_hash_str) { @@ -3603,23 +3640,23 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* int l_prev_tx_count = 0; dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(a_net_str, a_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, a_url_str, a_port); if (!l_order) { - printf("Error: Failed to get order from remote node\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND, "Error: Failed to get order from remote node"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND; + return l_json_obj_ret; } l_sovereign_tax = l_tax; if (l_order->direction == SERV_DIR_BUY) { // Staker order if (!a_cert_str) { - printf("Command 'delegate' requires parameter -cert with this order type\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED, "Command 'delegate' requires parameter -cert with this order type"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED; + return l_json_obj_ret; } if (l_order->ext_size != 0) { - printf("Specified order has invalid size\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Specified order has invalid size"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE; + return l_json_obj_ret; } dap_chain_tx_out_cond_t *l_cond_tx = NULL; @@ -3630,14 +3667,14 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); if (!response) { - printf("Error: Failed to get response from remote node\n"); - return STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE; + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE, "Error: Failed to get response from remote node"); + return l_json_obj_ret; } json_object *items = json_object_object_get(response, "ITEMS"); if (!items) { - printf("Error: No items found in response\n"); - return STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS; + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS, "Error: No items found in response"); + return l_json_obj_ret; } int items_count = json_object_array_length(items); for (int i = 0; i < items_count; i++) { @@ -3654,8 +3691,8 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr"))); if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) { - printf("Error: Failed to parse signer node address\n"); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR; + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR, "Error: Failed to parse signer node address"); + return l_json_obj_ret; } l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); l_prev_tx_count++; @@ -3666,60 +3703,60 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* } } if (!l_cond_tx) { - printf("Error: No transaction output condition found\n"); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR; + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Error: No transaction output condition found"); + return l_json_obj_ret; } json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); const char *spent_outs_value = json_object_get_string(spent_outs); if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { - printf("Error: Transaction output item already used\n"); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE; + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Error: Transaction output item already used"); + return l_json_obj_ret; } char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(a_net_str)); const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker")); if (!l_token_ticker) { - printf("Error: Token ticker not found in response\n"); - return STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER; + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER, "Error: Token ticker not found in response"); + return l_json_obj_ret; } json_object_put(response); if (dap_strcmp(l_token_ticker, l_delegated_ticker)) { - printf("Requested conditional transaction have another ticker (not %s)\n", l_delegated_ticker); - return STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER; + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER, "Requested conditional transaction have another ticker (not %s)", l_delegated_ticker); + return l_json_obj_ret; } if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) { - printf("The order's conditional transaction has invalid format\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT, "The order's conditional transaction has invalid format"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT; + return l_json_obj_ret; } if (compare256(l_cond_tx->header.value, l_order->price)) { - printf("The order's conditional transaction has different value\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE, "The order's conditional transaction has different value"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE; + return l_json_obj_ret; } if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) || l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) { - printf("The order's conditional transaction gas not blank address or key\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR, "The order's conditional transaction gas not blank address or key"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR; + return l_json_obj_ret; } l_value = l_order->price; } else { if (!a_value_str) { - printf("Command 'delegate' requires parameter -value with this order type\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED, "Command 'delegate' requires parameter -value with this order type"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED; + return l_json_obj_ret; } if (a_sovereign_addr_str) { dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(a_sovereign_addr_str); if (!l_spec_addr) { - printf("Specified address is ivalid\n"); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR; + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR, "Specified address is invalid"); + return l_json_obj_ret; } l_sovereign_addr = *l_spec_addr; DAP_DELETE(l_spec_addr); @@ -3729,58 +3766,58 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* if (a_order_hash_str && compare256(l_value, l_order->price) == -1) { const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_order->price, &l_coin_min_str); - printf("Number in '-value' param %s is lower than order minimum allowed value %s(%s)\n", + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW, "Number in '-value' param %s is lower than order minimum allowed value %s(%s)", a_value_str, l_coin_min_str, l_value_min_str); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW; + return l_json_obj_ret; } if (a_order_hash_str && compare256(l_value, l_value_max) == 1) { const char *l_coin_max_str, *l_value_max_str = dap_uint256_to_char(l_value_max, &l_coin_max_str); - printf("Number in '-value' param %s is higher than order minimum allowed value %s(%s)\n", + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH, "Number in '-value' param %s is higher than order minimum allowed value %s(%s)", a_value_str, l_coin_max_str, l_value_max_str); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH; + return l_json_obj_ret; } size_t l_sign_size = 0; dap_sign_t *l_sign = dap_get_remote_srv_order_sign(a_net_str, a_order_hash_str, a_url_str, a_port); if (!l_sign) { - printf("Specified order is unsigned\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER, "Specified order is unsigned"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER; + return l_json_obj_ret; } dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, s_get_net_id(a_net_str)); l_pkey = dap_pkey_get_from_sign(l_sign); char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX]; dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, s_get_native_ticker(a_net_str)); if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) { - printf("Specified order is invalid\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER, "Specified order is invalid"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER; + return l_json_obj_ret; } l_node_addr = l_order->node_addr; } DAP_DELETE(l_order); if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 || compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) { - printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX; + return l_json_obj_ret; } DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); } if (!l_pkey) { - printf("pkey not defined\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED, "pkey not defined"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED; + return l_json_obj_ret; } // TODO: need to make sure that the key and node are required verification // int l_check_result = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr); // if (l_check_result) { - // printf("Key and node verification error\n"); + // dap_json_compose_error_add(a_json_obj_ret, l_check_result, "Key and node verification error"); // dap_enc_key_delete(l_enc_key); // return l_check_result; // } @@ -3789,44 +3826,42 @@ int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* uint256_t l_allowed_min = s_get_key_delegating_min_value(a_net_str, a_url_str, a_port); if (compare256(l_value, l_allowed_min) == -1) { const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str); - printf("Number in '-value' param %s is lower than minimum allowed value %s(%s)\n", + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN, "Number in '-value' param %s is lower than minimum allowed value %s(%s)", a_value_str, l_coin_min_str, l_value_min_str); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN; + return l_json_obj_ret; } uint256_t l_fee = dap_chain_balance_scan(a_fee_str); if (IS_ZERO_256(l_fee)) { - printf("Unrecognized number in '-fee' param\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-fee' param"); dap_enc_key_delete(l_enc_key); - return STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE; + return l_json_obj_ret; } - int l_ret = 0; dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(a_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr, - a_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, a_url_str, a_port, &l_ret); + a_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, a_url_str, a_port, l_json_obj_ret); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_pkey); - if (l_ret) { - return l_ret; + if (l_tx) { + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + DAP_DELETE(l_tx); } - dap_chain_net_tx_to_json(l_tx, a_json_obj_ret); - DAP_DELETE(l_tx); - return STAKE_DELEGATE_COMPOSE_OK; + return l_json_obj_ret; } - dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, - dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, int *l_ret) + dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, json_object *l_error_handle) { if (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS, "Invalid parameters for transaction creation"); return NULL; } const char *l_native_ticker = s_get_native_ticker(a_net_str); @@ -3844,16 +3879,17 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en dap_list_t *l_list_fee_out = NULL; - json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); if (!l_outs_native) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee"); return NULL; } json_object *l_outs_delegated = dap_get_remote_tx_outs(l_delegated_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); if (!l_outs_delegated) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value"); return NULL; } @@ -3866,7 +3902,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en if (!l_list_fee_out) { json_object_put(l_outs_native); json_object_put(l_outs_delegated); - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee"); return NULL; } @@ -3880,14 +3917,16 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en if (!l_list_used_out) { json_object_put(l_outs_native); json_object_put(l_outs_delegated); - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value"); return NULL; } // add 'in' items to pay for delegate uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); dap_list_free_full(l_list_used_out, NULL); if (!EQUAL_256(l_value_to_items, l_value_transfer)) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input"); goto tx_fail; } } else { @@ -3897,7 +3936,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); // add 'in' item to buy from conditional transaction if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_out_num, -1)) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input"); goto tx_fail; } } @@ -3905,7 +3945,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); dap_list_free_full(l_list_fee_out, NULL); if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input"); goto tx_fail; } @@ -3915,7 +3956,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en a_sovereign_addr, a_sovereign_tax, a_pkey); if (!l_tx_out) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR, "Error creating conditional transaction output"); goto tx_fail; } dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); @@ -3926,7 +3968,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back); if (!IS_ZERO_256(l_value_back)) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR, "Error creating transaction output"); goto tx_fail; } } @@ -3935,13 +3978,15 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en // add fee items if (l_net_fee_used) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR, "Error with network fee"); goto tx_fail; } } if (!IS_ZERO_256(a_fee)) { if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR, "Error with validator fee"); goto tx_fail; } } @@ -3950,7 +3995,8 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back); if (!IS_ZERO_256(l_fee_back)) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) { - if (l_ret) *l_ret = DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR; + if (l_error_handle) + dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR, "Error with fee back"); goto tx_fail; } } @@ -3965,38 +4011,38 @@ tx_fail: static dap_chain_datum_tx_t *dap_order_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, uint256_t a_sovereign_tax, dap_chain_addr_t *a_sovereign_addr, - const char *l_url_str, int l_port, int *l_ret) + const char *l_url_str, int l_port, json_object *l_error_handle) { dap_chain_node_addr_t l_node_addr = {}; return dap_stake_tx_create_compose(a_net_str, a_key, a_value, a_fee, (dap_chain_addr_t *)&c_dap_chain_addr_blank, &l_node_addr, - a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, l_ret); + a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, l_error_handle); } - -int dap_cli_srv_stake_order_create_staker_compose(json_object* a_json_obj_ret, const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) { +json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) { + json_object* l_json_obj_ret = json_object_new_object(); uint256_t l_value = dap_chain_balance_scan(l_value_str); - if (IS_ZERO_256(l_value)) { - printf("Format -value <256 bit integer>\n"); - return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE; + if (IS_ZERO_256(l_value)) { + dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE, "Format -value <256 bit integer>"); + return l_json_obj_ret; } uint256_t l_fee = dap_chain_balance_scan(l_fee_str); if (IS_ZERO_256(l_fee)) { - printf("Format -fee <256 bit integer>\n"); - return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE; + dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE, "Format -fee <256 bit integer>"); + return l_json_obj_ret; } uint256_t l_tax = dap_chain_coins_to_balance(l_tax_str); if (compare256(l_tax, dap_chain_coins_to_balance("100.0")) == 1 || compare256(l_tax, GET_256_FROM_64(100)) == -1) { - printf("Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%\n"); - return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX; + dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%"); + return l_json_obj_ret; } dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); if (!l_wallet) { - printf("Specified wallet not found\n"); - return STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND; + dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND, "Specified wallet not found"); + return l_json_obj_ret; } const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet); @@ -4004,35 +4050,33 @@ int dap_cli_srv_stake_order_create_staker_compose(json_object* a_json_obj_ret, c dap_chain_wallet_close(l_wallet); if (!l_enc_key) { - printf("Failed to retrieve encryption key\n"); - return STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND; + dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND, "Failed to retrieve encryption key"); + return l_json_obj_ret; } dap_chain_addr_t l_addr = {}; if (l_addr_str) { dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str); if (!l_spec_addr) { - printf("Specified address is invalid\n"); + dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR, "Specified address is invalid"); DAP_DELETE(l_enc_key); - return STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR; + return NULL; } l_addr = *l_spec_addr; DAP_DELETE(l_spec_addr); } else dap_chain_addr_fill_from_key(&l_addr, l_enc_key, s_get_net_id(l_net_str)); DIV_256(l_tax, GET_256_FROM_64(100), &l_tax); - int l_ret = 0; - dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, &l_addr, l_url_str, l_port, &l_ret); + dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, + &l_addr, l_url_str, l_port, l_json_obj_ret); DAP_DEL_Z(l_enc_key); - if (l_ret) { - return l_ret; + if (l_tx) { + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + DAP_DELETE(l_tx); } - dap_chain_net_tx_to_json(l_tx, a_json_obj_ret); - - DAP_DELETE(l_tx); - return STAKE_ORDER_CREATE_STAKER_OK; + return l_json_obj_ret; } int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) { diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index f06ba28a1d..92d8bc19c1 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -69,16 +69,16 @@ int dap_cli_take_compose(int a_argc, char **a_argv); int dap_cli_voting_compose(int a_argc, char **a_argv); typedef enum { STAKE_ORDER_CREATE_STAKER_OK = 0, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -2, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -4, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -6, - STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -8, - STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -9, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -10, - STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -11, - STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -12 + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -1, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -2, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -3, + STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -4, + STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -5, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -6, + STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -7, + STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -8 } dap_cli_srv_stake_order_create_staker_error_t; -int dap_cli_srv_stake_order_create_staker_compose(json_object* a_json_obj_ret, const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port); +json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port); int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv); @@ -121,7 +121,7 @@ typedef enum { DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -35, DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -36 } stake_delegate_error_t; -int dap_cli_srv_stake_delegate_compose(json_object* a_json_obj_ret, const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, +json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path); typedef enum { @@ -155,9 +155,9 @@ typedef enum { DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28 } dap_cli_stake_invalidate_error_t; -int dap_cli_srv_stake_invalidate_compose(json_object *a_json_obj_ret, const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, +json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port); -dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, int *l_ret); +dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, json_object *a_error_handler); json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port); int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); @@ -200,7 +200,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, - dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, int *l_ret); + dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, json_object *l_error_handle); dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port); -- GitLab From 2a042795aa8e11a58d1d7bda91a99a0b6284fcec Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Fri, 11 Apr 2025 14:53:23 +0700 Subject: [PATCH 45/53] [*] refactor error --- modules/compose/dap_chain_tx_compose.c | 5213 +++++++++-------- .../compose/include/dap_chain_tx_compose.h | 46 +- 2 files changed, 2651 insertions(+), 2608 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 7072f557ef..125c7259b3 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -41,6 +41,37 @@ #include <json-c/json.h> +static compose_config_t* s_compose_config_init(const char *a_net_name, const char *a_url_str, + uint16_t a_port) { + if (!a_net_name || !a_url_str || a_port == 0) { + return NULL; + } + compose_config_t *l_config = DAP_NEW_Z(compose_config_t); + if (!l_config) { + return NULL; + } + l_config->net_name = a_net_name; + l_config->url_str = a_url_str ? a_url_str : dap_compose_get_net_url(a_net_name); + l_config->port = a_port ? a_port : dap_compose_get_net_port(a_net_name); + l_config->response_handler = json_object_new_object(); + return l_config; +} + +static json_object* s_compose_config_return_response_handler(compose_config_t *a_config) { + if (!a_config || !a_config->response_handler) { + return NULL; + } + json_object* l_response_handler = a_config->response_handler; + DAP_DEL_Z(a_config); + return l_response_handler; +} + +static int s_compose_config_deinit(compose_config_t *a_config) { + json_object_put(a_config->response_handler); + DAP_DEL_Z(a_config); + return 0; +} + const char* dap_compose_get_net_url(const char* name) { for (int i = 0; i < NET_COUNT; i++) { if (strcmp(netinfo[i].name, name) == 0) { @@ -278,19 +309,20 @@ static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_ob return ret; } -static json_object* s_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) { + +static json_object* s_request_command_to_rpc(const char *request, compose_config_t *a_config) { json_object * l_response = NULL; size_t l_response_size = 0; struct cmd_request* l_cmd_request = s_cmd_request_init(); if (!l_cmd_request) { - printf("Error: Failed to initialize command request\n"); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_REQUEST_INIT_FAILED, "Failed to initialize command request"); return NULL; } dap_client_http_request(dap_worker_get_auto(), - a_url_str ? a_url_str : dap_compose_get_net_url(a_net_name), - a_port ? a_port : dap_compose_get_net_port(a_net_name), + a_config->url_str, + a_config->port, "POST", "application/json", NULL, request, strlen(request), NULL, s_cmd_response_handler, s_cmd_error_handler, @@ -300,25 +332,24 @@ static json_object* s_request_command_to_rpc(const char *request, const char * a if (!l_ret){ if (s_cmd_request_get_response(l_cmd_request, &l_response, &l_response_size)) { - printf( "Response error code: %d", l_cmd_request->error_code); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_REQUEST_FAILED, "Response error code: %d", l_cmd_request->error_code); } } else { - printf("Error: Command list wait failed with code %d\n", l_ret); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_REQUEST_TIMEOUT, "Request timed out"); } - s_cmd_request_free(l_cmd_request); return l_response; } -static json_object* s_request_command_parse(json_object *l_response) { +static json_object* s_request_command_parse(json_object *l_response, compose_config_t *a_config) { if (!l_response) { - printf("Error: Response is NULL\n"); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is NULL"); return NULL; } json_object * l_result = NULL; if (!json_object_object_get_ex(l_response, "result", &l_result)) { - printf("Error: Failed to get 'result' from response\n"); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESULT_NOT_FOUND, "Failed to get 'result' from response"); return NULL; } @@ -332,7 +363,7 @@ static json_object* s_request_command_parse(json_object *l_response) { json_object *error_code = NULL, *error_message = NULL; if (json_object_object_get_ex(error_obj, "code", &error_code) && json_object_object_get_ex(error_obj, "message", &error_message)) { - printf("Error %d: %s\n", json_object_get_int(error_code), json_object_get_string(error_message)); + dap_json_compose_error_add(a_config->response_handler, json_object_get_int(error_code), json_object_get_string(error_message)); } } l_result = NULL; @@ -342,23 +373,26 @@ static json_object* s_request_command_parse(json_object *l_response) { return l_result; } -json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port) { - json_object * l_response = s_request_command_to_rpc(request, a_net_name, a_url_str, a_port); +json_object* dap_request_command_to_rpc(const char *request, compose_config_t *a_config) { + json_object * l_response = s_request_command_to_rpc(request, a_config); if (!l_response) { - printf("Error: Failed to get response from RPC request\n"); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Failed to get response from RPC request"); return NULL; } - - json_object * l_result = s_request_command_parse(l_response); + json_object * l_result = s_request_command_parse(l_response, a_config); json_object_put(l_response); + if (!l_result) { + json_object_put(l_result); + return NULL; + } return l_result; } -bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, const char * a_url_str, uint16_t a_port) { +bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, compose_config_t *a_config) { char data[512]; - snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", l_net_name); - json_object *l_json_get_fee = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port); + snprintf(data, sizeof(data), "{\"method\": \"net\",\"params\": [\"net;get;fee;-net;%s\"],\"id\": \"1\"}", a_config->net_name); + json_object * l_json_get_fee = dap_request_command_to_rpc(data, a_config); if (!l_json_get_fee) { return false; } @@ -403,557 +437,557 @@ bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net return true; } -bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, - json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port) { - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", - dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name); - json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port); - if (!l_json_outs) { - return false; - } +// bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, +// json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port) { +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", +// dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name); +// json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port); +// if (!l_json_outs) { +// return false; +// } - if (!json_object_is_type(l_json_outs, json_type_array)) { - json_object_put(l_json_outs); - return false; - } +// if (!json_object_is_type(l_json_outs, json_type_array)) { +// json_object_put(l_json_outs); +// return false; +// } - if (json_object_array_length(l_json_outs) == 0) { - json_object_put(l_json_outs); - return false; - } +// if (json_object_array_length(l_json_outs) == 0) { +// json_object_put(l_json_outs); +// return false; +// } - json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0); - if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) { - json_object_put(l_json_outs); - return false; - } +// json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0); +// if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) { +// json_object_put(l_json_outs); +// return false; +// } - json_object *l_first_item = json_object_array_get_idx(l_first_array, 0); - if (!l_first_item) { - json_object_put(l_json_outs); - return false; - } +// json_object *l_first_item = json_object_array_get_idx(l_first_array, 0); +// if (!l_first_item) { +// json_object_put(l_json_outs); +// return false; +// } - if (!json_object_object_get_ex(l_first_item, "outs", l_outs) || - !json_object_is_type(*l_outs, json_type_array)) { - json_object_put(l_json_outs); - return false; - } +// if (!json_object_object_get_ex(l_first_item, "outs", l_outs) || +// !json_object_is_type(*l_outs, json_type_array)) { +// json_object_put(l_json_outs); +// return false; +// } - *l_outputs_count = json_object_array_length(*l_outs); - json_object_get(*l_outs); - json_object_put(l_json_outs); - return true; -} +// *l_outputs_count = json_object_array_length(*l_outs); +// json_object_get(*l_outs); +// json_object_put(l_json_outs); +// return true; +// } -int dap_tx_create_xchange_compose(int argc, char ** argv) { - int arg_index = 1; - const char *l_net_name = NULL; - const char *l_token_sell = NULL; - const char *l_token_buy = NULL; - const char *l_wallet_name = NULL; - const char *l_value_str = NULL; - const char *l_rate_str = NULL; - const char *l_fee_str = NULL; - const char *l_url_str = NULL; - const char *l_port_str = NULL; - uint16_t l_port = 0; - - const char *l_wallet_path = NULL; - dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); - if (!l_wallet_path) { - l_wallet_path = - #ifdef DAP_OS_WINDOWS - dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); - #elif defined DAP_OS_MAC - dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); - #elif defined DAP_OS_UNIX - dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); - #endif - } +// int dap_tx_create_xchange_compose(int argc, char ** argv) { +// int arg_index = 1; +// const char *l_net_name = NULL; +// const char *l_token_sell = NULL; +// const char *l_token_buy = NULL; +// const char *l_wallet_name = NULL; +// const char *l_value_str = NULL; +// const char *l_rate_str = NULL; +// const char *l_fee_str = NULL; +// const char *l_url_str = NULL; +// const char *l_port_str = NULL; +// uint16_t l_port = 0; + +// const char *l_wallet_path = NULL; +// dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); +// if (!l_wallet_path) { +// l_wallet_path = +// #ifdef DAP_OS_WINDOWS +// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); +// #elif defined DAP_OS_MAC +// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); +// #elif defined DAP_OS_UNIX +// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); +// #endif +// } - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_sell", &l_token_sell); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_buy", &l_token_buy); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-rate", &l_rate_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str); - - if (!l_net_name) { - printf("xchange_create requires parameter '-net'"); - return -1; - } +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_sell", &l_token_sell); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_buy", &l_token_buy); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-rate", &l_rate_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str); - if (!l_url_str) { - l_url_str = dap_compose_get_net_url(l_net_name); - } +// if (!l_net_name) { +// printf("xchange_create requires parameter '-net'"); +// return -1; +// } - if (!l_port_str) { - l_port = dap_compose_get_net_port(l_net_name); - } else { - l_port = atoi(l_port_str); - } +// if (!l_url_str) { +// l_url_str = dap_compose_get_net_url(l_net_name); +// } - if (!l_token_buy) { - printf("xchange_create requires parameter '-token_buy'"); - return -1; - } +// if (!l_port_str) { +// l_port = dap_compose_get_net_port(l_net_name); +// } else { +// l_port = atoi(l_port_str); +// } - if (!l_token_sell) { - printf("xchange_create requires parameter '-token_sell'"); - return -1; - } +// if (!l_token_buy) { +// printf("xchange_create requires parameter '-token_buy'"); +// return -1; +// } - if (!l_wallet_name) { - printf("xchange_create requires parameter '-w'"); - return -1; - } +// if (!l_token_sell) { +// printf("xchange_create requires parameter '-token_sell'"); +// return -1; +// } - if (!l_value_str) { - printf("xchange_create requires parameter '-value'"); - return -1; - } +// if (!l_wallet_name) { +// printf("xchange_create requires parameter '-w'"); +// return -1; +// } - if (!l_rate_str) { - printf("xchange_create requires parameter '-rate'"); - return -1; - } +// if (!l_value_str) { +// printf("xchange_create requires parameter '-value'"); +// return -1; +// } - if (!l_fee_str) { - printf("xchange_create requires parameter '-fee'"); - return -1; - } +// if (!l_rate_str) { +// printf("xchange_create requires parameter '-rate'"); +// return -1; +// } - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL); - if(!l_wallet) { - printf("wallet %s does not exist", l_wallet_name); - return -1; - } +// if (!l_fee_str) { +// printf("xchange_create requires parameter '-fee'"); +// return -1; +// } +// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL); +// if(!l_wallet) { +// printf("wallet %s does not exist", l_wallet_name); +// return -1; +// } - uint256_t l_value = dap_chain_balance_scan(l_value_str); - uint256_t l_rate = dap_chain_balance_scan(l_rate_str); - uint256_t l_fee = dap_chain_balance_scan(l_fee_str); - if (IS_ZERO_256(l_value) || IS_ZERO_256(l_rate) || IS_ZERO_256(l_fee)) { - printf("Invalid parameter value, rate or fee is 0, use required format 1.0e+18 ot in datoshi"); - return -1; - } - dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_net_name, l_token_buy, - l_token_sell, l_value, l_rate, l_fee, l_wallet, l_url_str, l_port); - json_object *l_ret = json_object_new_object(); - dap_chain_net_tx_to_json(l_tx, l_ret); - printf("%s", json_object_to_json_string(l_ret)); - json_object_put(l_ret); - dap_chain_datum_tx_delete(l_tx); - return 0; -} +// uint256_t l_value = dap_chain_balance_scan(l_value_str); +// uint256_t l_rate = dap_chain_balance_scan(l_rate_str); +// uint256_t l_fee = dap_chain_balance_scan(l_fee_str); +// if (IS_ZERO_256(l_value) || IS_ZERO_256(l_rate) || IS_ZERO_256(l_fee)) { +// printf("Invalid parameter value, rate or fee is 0, use required format 1.0e+18 ot in datoshi"); +// return -1; +// } + +// dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_net_name, l_token_buy, +// l_token_sell, l_value, l_rate, l_fee, l_wallet, l_url_str, l_port); +// json_object *l_ret = json_object_new_object(); +// dap_chain_net_tx_to_json(l_tx, l_ret); +// printf("%s", json_object_to_json_string(l_ret)); +// json_object_put(l_ret); +// dap_chain_datum_tx_delete(l_tx); +// return 0; +// } -int dap_tx_create_compose(int argc, char ** argv) { - int arg_index = 1; - const char *addr_base58_to = NULL; - const char *str_tmp = NULL; - const char * l_from_wallet_name = NULL; - const char * l_wallet_fee_name = NULL; - const char * l_token_ticker = NULL; - const char * l_net_name = NULL; - const char * l_chain_name = NULL; - const char * l_url_str = NULL; - uint16_t l_port = 0; - - const char * l_hash_out_type = NULL; - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type); - if(!l_hash_out_type) - l_hash_out_type = "hex"; - if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) { - printf("Invalid parameter -H, valid values: -H <hex | base58>"); - return -1; - } +// int dap_tx_create_compose(int argc, char ** argv) { +// int arg_index = 1; +// const char *addr_base58_to = NULL; +// const char *str_tmp = NULL; +// const char * l_from_wallet_name = NULL; +// const char * l_wallet_fee_name = NULL; +// const char * l_token_ticker = NULL; +// const char * l_net_name = NULL; +// const char * l_chain_name = NULL; +// const char * l_url_str = NULL; +// uint16_t l_port = 0; + +// const char * l_hash_out_type = NULL; +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type); +// if(!l_hash_out_type) +// l_hash_out_type = "hex"; +// if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) { +// printf("Invalid parameter -H, valid values: -H <hex | base58>"); +// return -1; +// } - const char *l_wallet_path = NULL; - dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); - if (!l_wallet_path) { - l_wallet_path = - #ifdef DAP_OS_WINDOWS - dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); - #elif defined DAP_OS_MAC - dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); - #elif defined DAP_OS_UNIX - dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); - #endif - } - - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); - if (!l_net_name) { - printf("tx_create requires parameter '-net'"); - return -1; - } +// const char *l_wallet_path = NULL; +// dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); +// if (!l_wallet_path) { +// l_wallet_path = +// #ifdef DAP_OS_WINDOWS +// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); +// #elif defined DAP_OS_MAC +// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); +// #elif defined DAP_OS_UNIX +// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); +// #endif +// } - if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str)) { - l_url_str = dap_compose_get_net_url(l_net_name); - } - const char *l_port_str = NULL; - if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str)) { - l_port = dap_compose_get_net_port(l_net_name); - } else { - l_port = atoi(l_port_str); - } +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); +// if (!l_net_name) { +// printf("tx_create requires parameter '-net'"); +// return -1; +// } - uint256_t *l_value = NULL; - uint256_t l_value_fee = {}; - dap_chain_addr_t **l_addr_to = NULL; - size_t l_addr_el_count = 0; - size_t l_value_el_count = 0; - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-wallet_fee", &l_wallet_fee_name); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name); +// if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str)) { +// l_url_str = dap_compose_get_net_url(l_net_name); +// } +// const char *l_port_str = NULL; +// if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str)) { +// l_port = dap_compose_get_net_port(l_net_name); +// } else { +// l_port = atoi(l_port_str); +// } - // Validator's fee - if (dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) { - if (!str_tmp) { - printf("tx_create requires parameter '-fee'"); - return -1; - } - l_value_fee = dap_chain_balance_scan(str_tmp); - } - if (IS_ZERO_256(l_value_fee) && (str_tmp && strcmp(str_tmp, "0"))) { - printf("tx_create requires parameter '-fee' to be valid uint256"); - return -2; - } +// uint256_t *l_value = NULL; +// uint256_t l_value_fee = {}; +// dap_chain_addr_t **l_addr_to = NULL; +// size_t l_addr_el_count = 0; +// size_t l_value_el_count = 0; +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-wallet_fee", &l_wallet_fee_name); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name); + +// // Validator's fee +// if (dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) { +// if (!str_tmp) { +// printf("tx_create requires parameter '-fee'"); +// return -1; +// } +// l_value_fee = dap_chain_balance_scan(str_tmp); +// } +// if (IS_ZERO_256(l_value_fee) && (str_tmp && strcmp(str_tmp, "0"))) { +// printf("tx_create requires parameter '-fee' to be valid uint256"); +// return -2; +// } - if (!l_from_wallet_name) { - printf("tx_create requires parameter '-from_wallet'"); - return -3; - } +// if (!l_from_wallet_name) { +// printf("tx_create requires parameter '-from_wallet'"); +// return -3; +// } - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker); - if (!l_token_ticker) { - printf("tx_create requires parameter '-token'"); - return -4; - } +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker); +// if (!l_token_ticker) { +// printf("tx_create requires parameter '-token'"); +// return -4; +// } - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp); - if (!str_tmp) { - printf("tx_create requires parameter '-value' to be valid uint256 value"); - return -6; - } - l_value_el_count = dap_str_symbol_count(str_tmp, ',') + 1; +// if (!str_tmp) { +// printf("tx_create requires parameter '-value' to be valid uint256 value"); +// return -6; +// } +// l_value_el_count = dap_str_symbol_count(str_tmp, ',') + 1; - if (addr_base58_to) - l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1; - else - l_addr_el_count = l_value_el_count; +// if (addr_base58_to) +// l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1; +// else +// l_addr_el_count = l_value_el_count; - if (addr_base58_to && l_addr_el_count != l_value_el_count) { - printf("num of '-to_addr' and '-value' should be equal"); - return -5; - } +// if (addr_base58_to && l_addr_el_count != l_value_el_count) { +// printf("num of '-to_addr' and '-value' should be equal"); +// return -5; +// } - l_value = DAP_NEW_Z_COUNT(uint256_t, l_value_el_count); - if (!l_value) { - printf("Can't allocate memory"); - return -6; - } - char **l_value_array = dap_strsplit(str_tmp, ",", l_value_el_count); - if (!l_value_array) { - DAP_DELETE(l_value); - printf("Can't read '-to_addr' arg"); - return -7; - } - for (size_t i = 0; i < l_value_el_count; ++i) { - l_value[i] = dap_chain_balance_scan(l_value_array[i]); - if(IS_ZERO_256(l_value[i])) { - DAP_DEL_MULTY(l_value_array, l_value); - printf("tx_create requires parameter '-value' to be valid uint256 value"); - return -8; - } - } - DAP_DELETE(l_value_array); +// l_value = DAP_NEW_Z_COUNT(uint256_t, l_value_el_count); +// if (!l_value) { +// printf("Can't allocate memory"); +// return -6; +// } +// char **l_value_array = dap_strsplit(str_tmp, ",", l_value_el_count); +// if (!l_value_array) { +// DAP_DELETE(l_value); +// printf("Can't read '-to_addr' arg"); +// return -7; +// } +// for (size_t i = 0; i < l_value_el_count; ++i) { +// l_value[i] = dap_chain_balance_scan(l_value_array[i]); +// if(IS_ZERO_256(l_value[i])) { +// DAP_DEL_MULTY(l_value_array, l_value); +// printf("tx_create requires parameter '-value' to be valid uint256 value"); +// return -8; +// } +// } +// DAP_DELETE(l_value_array); - if (addr_base58_to) { - l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count); - if (!l_addr_to) { - printf("Can't allocate memory"); - DAP_DELETE(l_value); - return -9; - } - char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count); - if (!l_addr_base58_to_array) { - DAP_DEL_MULTY(l_addr_to, l_value); - printf("Can't read '-to_addr' arg"); - return -10; - } - for (size_t i = 0; i < l_addr_el_count; ++i) { - l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]); - if(!l_addr_to[i]) { - for (size_t j = 0; j < i; ++j) { - DAP_DELETE(l_addr_to[j]); - } - DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value); - printf("destination address is invalid"); - return -11; - } - } - DAP_DELETE(l_addr_base58_to_array); - } +// if (addr_base58_to) { +// l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count); +// if (!l_addr_to) { +// printf("Can't allocate memory"); +// DAP_DELETE(l_value); +// return -9; +// } +// char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count); +// if (!l_addr_base58_to_array) { +// DAP_DEL_MULTY(l_addr_to, l_value); +// printf("Can't read '-to_addr' arg"); +// return -10; +// } +// for (size_t i = 0; i < l_addr_el_count; ++i) { +// l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]); +// if(!l_addr_to[i]) { +// for (size_t j = 0; j < i; ++j) { +// DAP_DELETE(l_addr_to[j]); +// } +// DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value); +// printf("destination address is invalid"); +// return -11; +// } +// } +// DAP_DELETE(l_addr_base58_to_array); +// } - dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, l_wallet_path, NULL); - if(!l_wallet) { - printf("Can't open wallet %s", l_from_wallet_name); - return -12; - } +// dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, l_wallet_path, NULL); +// if(!l_wallet) { +// printf("Can't open wallet %s", l_from_wallet_name); +// return -12; +// } - dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)); - for (size_t i = 0; l_addr_to && i < l_addr_el_count; ++i) { - if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) { - printf("The transaction cannot be directed to the same address as the source."); - for (size_t j = 0; j < l_addr_el_count; ++j) { - DAP_DELETE(l_addr_to[j]); - } - DAP_DEL_MULTY(l_addr_to, l_value); - return -13; - } - } +// dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)); +// for (size_t i = 0; l_addr_to && i < l_addr_el_count; ++i) { +// if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) { +// printf("The transaction cannot be directed to the same address as the source."); +// for (size_t j = 0; j < l_addr_el_count; ++j) { +// DAP_DELETE(l_addr_to[j]); +// } +// DAP_DEL_MULTY(l_addr_to, l_value); +// return -13; +// } +// } - dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count, l_url_str, l_port); +// dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count, l_url_str, l_port); - json_object * l_json_obj_ret = json_object_new_object(); - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); - printf("%s", json_object_to_json_string(l_json_obj_ret)); - json_object_put(l_json_obj_ret); - dap_chain_datum_tx_delete(l_tx); - DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from); - return 0; -} +// json_object * l_json_obj_ret = json_object_new_object(); +// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); +// printf("%s", json_object_to_json_string(l_json_obj_ret)); +// json_object_put(l_json_obj_ret); +// dap_chain_datum_tx_delete(l_tx); +// DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from); +// return 0; +// } -int dap_chain_datum_tx_add_out_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value) { - if (IS_ZERO_256(a_value)) - return -1; +// int dap_chain_datum_tx_add_out_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value) { +// if (IS_ZERO_256(a_value)) +// return -1; - dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t); - if (!l_item) - return -1; +// dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t); +// if (!l_item) +// return -1; - l_item->header.type = TX_ITEM_TYPE_OUT; - l_item->header.value = a_value; +// l_item->header.type = TX_ITEM_TYPE_OUT; +// l_item->header.value = a_value; - int res = dap_chain_datum_tx_add_item(a_tx, l_item); - DAP_DELETE(l_item); +// int res = dap_chain_datum_tx_add_item(a_tx, l_item); +// DAP_DELETE(l_item); - return res; -} +// return res; +// } -int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value, const char *a_token) -{ - if (!a_token || IS_ZERO_256(a_value)) - return -1; +// int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value, const char *a_token) +// { +// if (!a_token || IS_ZERO_256(a_value)) +// return -1; - dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t); - if (!l_item) - return -2; - l_item->header.type = TX_ITEM_TYPE_OUT_EXT; - l_item->header.value = a_value; - dap_strncpy((char*)l_item->token, a_token, sizeof(l_item->token) - 1); +// dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t); +// if (!l_item) +// return -2; +// l_item->header.type = TX_ITEM_TYPE_OUT_EXT; +// l_item->header.value = a_value; +// dap_strncpy((char*)l_item->token, a_token, sizeof(l_item->token) - 1); - int result = dap_chain_datum_tx_add_item(a_tx, l_item); - DAP_DELETE(l_item); - return result; -} +// int result = dap_chain_datum_tx_add_item(a_tx, l_item); +// DAP_DELETE(l_item); +// return result; +// } -dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, - const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port) -{ - if (!a_addr_from || !a_token_ticker || !a_value) { - return NULL; - } +// dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, +// const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port) +// { +// if (!a_addr_from || !a_token_ticker || !a_value) { +// return NULL; +// } - if (dap_chain_addr_check_sum(a_addr_from)) { - return NULL; - } +// if (dap_chain_addr_check_sum(a_addr_from)) { +// return NULL; +// } - for (size_t i = 0; i < a_tx_num; ++i) { - // if (!a_addr_to || !a_addr_to[i]) { - // return NULL; - // } - if (a_addr_to && dap_chain_addr_check_sum(a_addr_to[i])) { - return NULL; - } - if (IS_ZERO_256(a_value[i])) { - return NULL; - } - } - const char * l_native_ticker = s_get_native_ticker(l_net_name); - bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker); +// for (size_t i = 0; i < a_tx_num; ++i) { +// // if (!a_addr_to || !a_addr_to[i]) { +// // return NULL; +// // } +// if (a_addr_to && dap_chain_addr_check_sum(a_addr_to[i])) { +// return NULL; +// } +// if (IS_ZERO_256(a_value[i])) { +// return NULL; +// } +// } +// const char * l_native_ticker = s_get_native_ticker(l_net_name); +// bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker); - uint256_t l_value_transfer = {}; // how many coins to transfer - uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {}; - for (size_t i = 0; i < a_tx_num; ++i) { - SUM_256_256(l_value_total, a_value[i], &l_value_total); - } - uint256_t l_value_need = l_value_total; +// uint256_t l_value_transfer = {}; // how many coins to transfer +// uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {}; +// for (size_t i = 0; i < a_tx_num; ++i) { +// SUM_256_256(l_value_total, a_value[i], &l_value_total); +// } +// uint256_t l_value_need = l_value_total; - dap_list_t *l_list_fee_out = NULL; - uint256_t l_net_fee = {}; - dap_chain_addr_t *l_addr_fee = NULL; - if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port)) { - return NULL; - } +// dap_list_t *l_list_fee_out = NULL; +// uint256_t l_net_fee = {}; +// dap_chain_addr_t *l_addr_fee = NULL; +// if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port)) { +// return NULL; +// } - bool l_net_fee_used = !IS_ZERO_256(l_net_fee); - SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); - json_object *l_outs = NULL; - int l_outputs_count = 0; - if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) { - return NULL; - } +// bool l_net_fee_used = !IS_ZERO_256(l_net_fee); +// SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); +// json_object *l_outs = NULL; +// int l_outputs_count = 0; +// if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) { +// return NULL; +// } - if (l_single_channel) - SUM_256_256(l_value_need, l_total_fee, &l_value_need); - else if (!IS_ZERO_256(l_total_fee)) { - l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, - l_total_fee, - &l_fee_transfer); - if (!l_list_fee_out) { - printf("Not enough funds to pay fee"); - json_object_put(l_outs); - return NULL; - } - } - dap_list_t *l_list_used_out = NULL; - l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, - l_value_need, - &l_value_transfer); - json_object_put(l_outs); - if (!l_list_used_out) { - printf("Not enough funds to transfer"); - return NULL; - } - // create empty transaction - dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - // add 'in' items - { - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); - assert(EQUAL_256(l_value_to_items, l_value_transfer)); - dap_list_free_full(l_list_used_out, NULL); - if (l_list_fee_out) { - uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); - assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); - dap_list_free_full(l_list_fee_out, NULL); - } +// if (l_single_channel) +// SUM_256_256(l_value_need, l_total_fee, &l_value_need); +// else if (!IS_ZERO_256(l_total_fee)) { +// l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, +// l_total_fee, +// &l_fee_transfer); +// if (!l_list_fee_out) { +// printf("Not enough funds to pay fee"); +// json_object_put(l_outs); +// return NULL; +// } +// } +// dap_list_t *l_list_used_out = NULL; +// l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, +// l_value_need, +// &l_value_transfer); +// json_object_put(l_outs); +// if (!l_list_used_out) { +// printf("Not enough funds to transfer"); +// return NULL; +// } +// // create empty transaction +// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); +// // add 'in' items +// { +// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); +// assert(EQUAL_256(l_value_to_items, l_value_transfer)); +// dap_list_free_full(l_list_used_out, NULL); +// if (l_list_fee_out) { +// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); +// assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); +// dap_list_free_full(l_list_fee_out, NULL); +// } - } - if (a_tx_num > 1) { - uint32_t l_tx_num = a_tx_num; - dap_chain_tx_tsd_t *l_out_count = dap_chain_datum_tx_item_tsd_create(&l_tx_num, DAP_CHAIN_DATUM_TRANSFER_TSD_TYPE_OUT_COUNT, sizeof(uint32_t)); - dap_chain_datum_tx_add_item(&l_tx, l_out_count); - } +// } +// if (a_tx_num > 1) { +// uint32_t l_tx_num = a_tx_num; +// dap_chain_tx_tsd_t *l_out_count = dap_chain_datum_tx_item_tsd_create(&l_tx_num, DAP_CHAIN_DATUM_TRANSFER_TSD_TYPE_OUT_COUNT, sizeof(uint32_t)); +// dap_chain_datum_tx_add_item(&l_tx, l_out_count); +// } - if (l_single_channel) { // add 'out' items - uint256_t l_value_pack = {}; // how much datoshi add to 'out' items - for (size_t i = 0; i < a_tx_num; ++i) { - if (a_addr_to) { - if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } else { - if (dap_chain_datum_tx_add_out_without_addr(&l_tx, a_value[i]) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - SUM_256_256(l_value_pack, a_value[i], &l_value_pack); - } - // Network fee - if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) - SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); - else { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - // Validator's fee - if (!IS_ZERO_256(a_value_fee)) { - if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) - SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); - else { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - // coin back - uint256_t l_value_back; - SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); - if(!IS_ZERO_256(l_value_back)) { - if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - } else { // add 'out_ext' items - for (size_t i = 0; i < a_tx_num; ++i) { - if (a_addr_to) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } else { - if (dap_chain_datum_tx_add_out_ext_item_without_addr(&l_tx, a_value[i], a_token_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - } - // coin back - uint256_t l_value_back; - SUBTRACT_256_256(l_value_transfer, l_value_total, &l_value_back); - if(!IS_ZERO_256(l_value_back)) { - if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - // Network fee - if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - // Validator's fee - if (!IS_ZERO_256(a_value_fee)) { - if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - // fee coin back - SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back); - if(!IS_ZERO_256(l_value_back)) { - if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - } - DAP_DELETE(l_addr_fee); - return l_tx; -} +// if (l_single_channel) { // add 'out' items +// uint256_t l_value_pack = {}; // how much datoshi add to 'out' items +// for (size_t i = 0; i < a_tx_num; ++i) { +// if (a_addr_to) { +// if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } else { +// if (dap_chain_datum_tx_add_out_without_addr(&l_tx, a_value[i]) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// SUM_256_256(l_value_pack, a_value[i], &l_value_pack); +// } +// // Network fee +// if (l_net_fee_used) { +// if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) +// SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); +// else { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// // Validator's fee +// if (!IS_ZERO_256(a_value_fee)) { +// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) +// SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); +// else { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// // coin back +// uint256_t l_value_back; +// SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); +// if(!IS_ZERO_256(l_value_back)) { +// if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// } else { // add 'out_ext' items +// for (size_t i = 0; i < a_tx_num; ++i) { +// if (a_addr_to) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } else { +// if (dap_chain_datum_tx_add_out_ext_item_without_addr(&l_tx, a_value[i], a_token_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// } +// // coin back +// uint256_t l_value_back; +// SUBTRACT_256_256(l_value_transfer, l_value_total, &l_value_back); +// if(!IS_ZERO_256(l_value_back)) { +// if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// // Network fee +// if (l_net_fee_used) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// // Validator's fee +// if (!IS_ZERO_256(a_value_fee)) { +// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// // fee coin back +// SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back); +// if(!IS_ZERO_256(l_value_back)) { +// if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// } +// DAP_DELETE(l_addr_fee); +// return l_tx; +// } dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer) { @@ -1018,157 +1052,162 @@ dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, } } -uint256_t get_balance_from_json(json_object *l_json_outs, const char *a_token_sell) { - uint256_t l_value = {}; - if (l_json_outs && json_object_is_type(l_json_outs, json_type_array)) { - for (size_t i = 0; i < json_object_array_length(l_json_outs); i++) { - json_object *outer_array = json_object_array_get_idx(l_json_outs, i); - if (json_object_is_type(outer_array, json_type_array)) { - for (size_t j = 0; j < json_object_array_length(outer_array); j++) { - json_object *addr_obj = json_object_array_get_idx(outer_array, j); - if (json_object_is_type(addr_obj, json_type_object)) { - json_object *tokens = NULL; - if (json_object_object_get_ex(addr_obj, "tokens", &tokens) && json_object_is_type(tokens, json_type_array)) { - for (size_t k = 0; k < json_object_array_length(tokens); k++) { - json_object *token_obj = json_object_array_get_idx(tokens, k); - json_object *token = NULL; - if (json_object_object_get_ex(token_obj, "token", &token) && json_object_is_type(token, json_type_object)) { - json_object *ticker = NULL; - if (json_object_object_get_ex(token, "ticker", &ticker) && json_object_is_type(ticker, json_type_string)) { - const char *ticker_str = json_object_get_string(ticker); - if (strcmp(ticker_str, a_token_sell) == 0) { - json_object *datoshi = NULL; - if (json_object_object_get_ex(token_obj, "datoshi", &datoshi) && json_object_is_type(datoshi, json_type_string)) { - const char *datoshi_str = json_object_get_string(datoshi); - l_value = dap_uint256_scan_uninteger(datoshi_str); - break; - } - } - } - } - } - } - } - } - } - } - } - return l_value; -} +// uint256_t get_balance_from_json(json_object *l_json_outs, const char *a_token_sell) { +// uint256_t l_value = {}; +// if (l_json_outs && json_object_is_type(l_json_outs, json_type_array)) { +// for (size_t i = 0; i < json_object_array_length(l_json_outs); i++) { +// json_object *outer_array = json_object_array_get_idx(l_json_outs, i); +// if (json_object_is_type(outer_array, json_type_array)) { +// for (size_t j = 0; j < json_object_array_length(outer_array); j++) { +// json_object *addr_obj = json_object_array_get_idx(outer_array, j); +// if (json_object_is_type(addr_obj, json_type_object)) { +// json_object *tokens = NULL; +// if (json_object_object_get_ex(addr_obj, "tokens", &tokens) && json_object_is_type(tokens, json_type_array)) { +// for (size_t k = 0; k < json_object_array_length(tokens); k++) { +// json_object *token_obj = json_object_array_get_idx(tokens, k); +// json_object *token = NULL; +// if (json_object_object_get_ex(token_obj, "token", &token) && json_object_is_type(token, json_type_object)) { +// json_object *ticker = NULL; +// if (json_object_object_get_ex(token, "ticker", &ticker) && json_object_is_type(ticker, json_type_string)) { +// const char *ticker_str = json_object_get_string(ticker); +// if (strcmp(ticker_str, a_token_sell) == 0) { +// json_object *datoshi = NULL; +// if (json_object_object_get_ex(token_obj, "datoshi", &datoshi) && json_object_is_type(datoshi, json_type_string)) { +// const char *datoshi_str = json_object_get_string(datoshi); +// l_value = dap_uint256_scan_uninteger(datoshi_str); +// break; +// } +// } +// } +// } +// } +// } +// } +// } +// } +// } +// } +// return l_value; +// } -bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) { - if (json_object_is_type(l_json_coins, json_type_array)) { - for (size_t i = 0; i < json_object_array_length(l_json_coins); i++) { - json_object *token_array = json_object_array_get_idx(l_json_coins, i); - if (json_object_is_type(token_array, json_type_array)) { - for (size_t j = 0; j < json_object_array_length(token_array); j++) { - json_object *token_obj = json_object_array_get_idx(token_array, j); - json_object *token_name = NULL; - if (json_object_object_get_ex(token_obj, "-->Token name", &token_name) && json_object_is_type(token_name, json_type_string)) { - const char *token_name_str = json_object_get_string(token_name); - if (strcmp(token_name_str, a_token) == 0) { - return true; - } - } - } - } - } - } - return false; -} +// bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) { +// if (json_object_is_type(l_json_coins, json_type_array)) { +// for (size_t i = 0; i < json_object_array_length(l_json_coins); i++) { +// json_object *token_array = json_object_array_get_idx(l_json_coins, i); +// if (json_object_is_type(token_array, json_type_array)) { +// for (size_t j = 0; j < json_object_array_length(token_array); j++) { +// json_object *token_obj = json_object_array_get_idx(token_array, j); +// json_object *token_name = NULL; +// if (json_object_object_get_ex(token_obj, "-->Token name", &token_name) && json_object_is_type(token_name, json_type_string)) { +// const char *token_name_str = json_object_get_string(token_name); +// if (strcmp(token_name_str, a_token) == 0) { +// return true; +// } +// } +// } +// } +// } +// } +// return false; +// } -dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, - const char *a_token_sell, uint256_t a_datoshi_sell, - uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port){ - if (!a_net_name || !a_token_buy || !a_token_sell || !a_wallet) { - return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMEN - } - if (IS_ZERO_256(a_rate)) { - return NULL; // XCHANGE_CREATE_ERROR_RATE_IS_ZERO - } - if (IS_ZERO_256(a_fee)) { - return NULL; // XCHANGE_CREATE_ERROR_FEE_IS_ZERO - } - if (IS_ZERO_256(a_datoshi_sell)) { - return NULL; // XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO - } - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name); - json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port); - if (!l_json_coins) { - return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS - } - if (!check_token_in_ledger(l_json_coins, a_token_sell) || !check_token_in_ledger(l_json_coins, a_token_buy)) { - json_object_put(l_json_coins); - return NULL; // XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER - } - json_object_put(l_json_coins); - dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name)); - snprintf(data, sizeof(data), - "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", - dap_chain_addr_to_str(l_wallet_addr), a_net_name); - DAP_DEL_Z(l_wallet_addr); - json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port); - uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell); - - uint256_t l_value_sell = a_datoshi_sell; - if (!dap_strcmp(s_get_native_ticker(a_net_name), a_token_sell)) { - if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) { - return NULL; // XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE - } - } else { // sell non-native ticker - uint256_t l_fee_value = get_balance_from_json(l_json_outs, s_get_native_ticker(a_net_name)); - if (compare256(l_fee_value, a_fee) == -1) { - return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET - } - } - if (compare256(l_value, l_value_sell) == -1) { - return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET - } - // Create the price - dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); - if (!l_price) { - return NULL; // XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED - } - dap_stpcpy(l_price->token_sell, a_token_sell); - dap_stpcpy(l_price->token_buy, a_token_buy); - l_price->datoshi_sell = a_datoshi_sell; - l_price->rate = a_rate; - l_price->fee = a_fee; - dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name, a_url_str, a_port); - return l_tx; -} +// dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, +// const char *a_token_sell, uint256_t a_datoshi_sell, +// uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port){ +// if (!a_net_name || !a_token_buy || !a_token_sell || !a_wallet) { +// return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMEN +// } +// if (IS_ZERO_256(a_rate)) { +// return NULL; // XCHANGE_CREATE_ERROR_RATE_IS_ZERO +// } +// if (IS_ZERO_256(a_fee)) { +// return NULL; // XCHANGE_CREATE_ERROR_FEE_IS_ZERO +// } +// if (IS_ZERO_256(a_datoshi_sell)) { +// return NULL; // XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO +// } +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name); +// json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port); +// if (!l_json_coins) { +// return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS +// } +// if (!check_token_in_ledger(l_json_coins, a_token_sell) || !check_token_in_ledger(l_json_coins, a_token_buy)) { +// json_object_put(l_json_coins); +// return NULL; // XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER +// } +// json_object_put(l_json_coins); +// dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name)); +// snprintf(data, sizeof(data), +// "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", +// dap_chain_addr_to_str(l_wallet_addr), a_net_name); +// DAP_DEL_Z(l_wallet_addr); +// json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port); +// uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell); + +// uint256_t l_value_sell = a_datoshi_sell; +// if (!dap_strcmp(s_get_native_ticker(a_net_name), a_token_sell)) { +// if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) { +// return NULL; // XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE +// } +// } else { // sell non-native ticker +// uint256_t l_fee_value = get_balance_from_json(l_json_outs, s_get_native_ticker(a_net_name)); +// if (compare256(l_fee_value, a_fee) == -1) { +// return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET +// } +// } +// if (compare256(l_value, l_value_sell) == -1) { +// return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET +// } +// // Create the price +// dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); +// if (!l_price) { +// return NULL; // XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED +// } +// dap_stpcpy(l_price->token_sell, a_token_sell); +// dap_stpcpy(l_price->token_buy, a_token_buy); +// l_price->datoshi_sell = a_datoshi_sell; +// l_price->rate = a_rate; +// l_price->fee = a_fee; +// dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name, a_url_str, a_port); +// return l_tx; +// } -json_object *dap_get_remote_tx_outs(const char *a_token_ticker, const char *a_net_name, dap_chain_addr_t * a_addr, const char *a_url_str, uint16_t a_port) { +json_object *dap_get_remote_tx_outs(const char *a_token_ticker, dap_chain_addr_t * a_addr, compose_config_t *a_config) { char data[512]; snprintf(data, sizeof(data), "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", - dap_chain_addr_to_str(a_addr), a_token_ticker, a_net_name); - json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port); + dap_chain_addr_to_str(a_addr), a_token_ticker, a_config->net_name); + json_object *l_json_outs = dap_request_command_to_rpc(data, a_config); if (!l_json_outs) { + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Failed to get response from RPC request"); return NULL; } if (!json_object_is_type(l_json_outs, json_type_array)) { json_object_put(l_json_outs); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is not an array"); return NULL; } if (json_object_array_length(l_json_outs) == 0) { json_object_put(l_json_outs); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is empty"); return NULL; } json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0); if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) { json_object_put(l_json_outs); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is not an array"); return NULL; } json_object *l_first_item = json_object_array_get_idx(l_first_array, 0); if (!l_first_item) { json_object_put(l_json_outs); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is not an array"); return NULL; } @@ -1176,6 +1215,7 @@ json_object *dap_get_remote_tx_outs(const char *a_token_ticker, const char *a_ne if (!json_object_object_get_ex(l_first_item, "outs", &l_outs) || !json_object_is_type(l_outs, json_type_array)) { json_object_put(l_json_outs); + dap_json_compose_error_add(a_config->response_handler, DAP_COMPOSE_ERROR_RESPONSE_NULL, "Response is not an array"); return NULL; } json_object_get(l_outs); @@ -1184,1158 +1224,1158 @@ json_object *dap_get_remote_tx_outs(const char *a_token_ticker, const char *a_ne } -dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, - const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port) -{ - if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) { - return NULL; - } - const char *l_native_ticker = s_get_native_ticker(a_net_name); - bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker); - // find the transactions from which to take away coins - uint256_t l_value_transfer; // how many coins to transfer - uint256_t l_value_need = a_price->datoshi_sell, - l_net_fee, - l_total_fee = a_price->fee, - l_fee_transfer; - dap_chain_addr_t * l_addr_net_fee = NULL; - dap_list_t *l_list_fee_out = NULL; +// dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, +// const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port) +// { +// if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) { +// return NULL; +// } +// const char *l_native_ticker = s_get_native_ticker(a_net_name); +// bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker); +// // find the transactions from which to take away coins +// uint256_t l_value_transfer; // how many coins to transfer +// uint256_t l_value_need = a_price->datoshi_sell, +// l_net_fee, +// l_total_fee = a_price->fee, +// l_fee_transfer; +// dap_chain_addr_t * l_addr_net_fee = NULL; +// dap_list_t *l_list_fee_out = NULL; + +// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee, a_url_str, a_port); +// if (l_net_fee_used) +// SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); + +// dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name)); +// dap_chain_addr_t l_seller_addr = *l_wallet_addr; +// json_object *l_outs_native = dap_get_remote_tx_outs(a_native_ticker, a_net_name, l_wallet_addr, a_url_str, a_port); +// if (!l_outs_native) { +// return NULL; +// } - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee, a_url_str, a_port); - if (l_net_fee_used) - SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); +// json_object *l_outs = NULL; +// if (!dap_strcmp(a_price->token_sell, a_native_ticker)) { +// l_outs = l_outs_native; +// } else { +// l_outs = dap_get_remote_tx_outs(a_price->token_sell, a_net_name, l_wallet_addr, a_url_str, a_port); +// } +// DAP_DELETE(l_wallet_addr); +// int l_out_native_count = json_object_array_length(l_outs_native); +// int l_out_count = json_object_array_length(l_outs); + +// if (l_single_channel) +// SUM_256_256(l_value_need, l_total_fee, &l_value_need); +// else if (!IS_ZERO_256(l_total_fee)) { +// l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, +// l_total_fee, +// &l_fee_transfer); +// if (!l_list_fee_out) { +// printf("Not enough funds to pay fee"); +// json_object_put(l_outs_native); +// json_object_put(l_outs); +// return NULL; +// } +// } +// dap_list_t *l_list_used_out = NULL; +// l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_out_count, +// l_value_need, +// &l_value_transfer); +// if (!l_list_used_out) { +// printf("Not enough funds to transfer"); +// json_object_put(l_outs_native); +// json_object_put(l_outs); +// return NULL; +// } - dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name)); - dap_chain_addr_t l_seller_addr = *l_wallet_addr; - json_object *l_outs_native = dap_get_remote_tx_outs(a_native_ticker, a_net_name, l_wallet_addr, a_url_str, a_port); - if (!l_outs_native) { - return NULL; - } +// // create empty transaction +// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); +// // add 'in' items to sell +// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); +// dap_list_free_full(l_list_used_out, NULL); +// if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Can't compose the transaction input\n"); +// return NULL; +// } +// if (!l_single_channel) { +// // add 'in' items to fee +// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); +// if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Can't compose the transaction input\n"); +// return NULL; +// } +// } - json_object *l_outs = NULL; - if (!dap_strcmp(a_price->token_sell, a_native_ticker)) { - l_outs = l_outs_native; - } else { - l_outs = dap_get_remote_tx_outs(a_price->token_sell, a_net_name, l_wallet_addr, a_url_str, a_port); - } - DAP_DELETE(l_wallet_addr); - int l_out_native_count = json_object_array_length(l_outs_native); - int l_out_count = json_object_array_length(l_outs); - - if (l_single_channel) - SUM_256_256(l_value_need, l_total_fee, &l_value_need); - else if (!IS_ZERO_256(l_total_fee)) { - l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, - l_total_fee, - &l_fee_transfer); - if (!l_list_fee_out) { - printf("Not enough funds to pay fee"); - json_object_put(l_outs_native); - json_object_put(l_outs); - return NULL; - } - } - dap_list_t *l_list_used_out = NULL; - l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_out_count, - l_value_need, - &l_value_transfer); - if (!l_list_used_out) { - printf("Not enough funds to transfer"); - json_object_put(l_outs_native); - json_object_put(l_outs); - return NULL; - } +// // add 'out_cond' & 'out' items + +// { +// dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID }; +// dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(l_uid, s_get_net_id(a_net_name), a_price->datoshi_sell, +// s_get_net_id(a_net_name), a_price->token_buy, a_price->rate, +// &l_seller_addr, NULL, 0); +// if (!l_tx_out) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Can't compose the transaction conditional output\n"); +// return NULL; +// } +// dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); +// DAP_DELETE(l_tx_out); +// // Network fee +// if (l_net_fee_used) { +// if ((l_single_channel && +// dap_chain_datum_tx_add_out_item(&l_tx, l_addr_net_fee, l_net_fee) != 1) || +// (!l_single_channel && +// dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add network fee output\n"); +// return NULL; +// } +// } +// DAP_DELETE(l_addr_net_fee); +// // Validator's fee +// if (!IS_ZERO_256(a_price->fee)) { +// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add validator's fee output\n"); +// return NULL; +// } +// } +// // coin back +// uint256_t l_value_back = {}; +// SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back); +// if (!IS_ZERO_256(l_value_back)) { +// if ((l_single_channel && +// dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) || +// (!l_single_channel && +// dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_value_back, a_price->token_sell) != 1)) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add coin back output\n"); +// return NULL; +// } +// } +// // Fee coinback +// if (!l_single_channel) { +// uint256_t l_fee_coinback = {}; +// SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback); +// if (!IS_ZERO_256(l_fee_coinback)) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add fee back output\n"); +// return NULL; +// } +// } +// } +// } +// return l_tx; +// } - // create empty transaction - dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - // add 'in' items to sell - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); - dap_list_free_full(l_list_used_out, NULL); - if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) { - dap_chain_datum_tx_delete(l_tx); - printf("Can't compose the transaction input\n"); - return NULL; - } - if (!l_single_channel) { - // add 'in' items to fee - uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); - if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) { - dap_chain_datum_tx_delete(l_tx); - printf("Can't compose the transaction input\n"); - return NULL; - } - } +// // tx_cond_create -net <net_name> -token <token_ticker> -w <wallet_name> -cert <pub_cert_name> -value <value_datoshi> -fee <value> -unit {B | SEC} -srv_uid <numeric_uid> +// int dap_tx_cond_create_compose(int argc, char ** argv) +// { +// int arg_index = 1; +// const char * l_token_ticker = NULL; +// const char * l_wallet_str = NULL; +// const char * l_cert_str = NULL; +// const char * l_value_datoshi_str = NULL; +// const char * l_value_fee_str = NULL; +// const char * l_net_name = NULL; +// const char * l_unit_str = NULL; +// const char * l_srv_uid_str = NULL; +// uint256_t l_value_datoshi = {}; +// uint256_t l_value_fee = {}; +// const char * l_url_str = NULL; +// const char * l_port_str = NULL; +// uint16_t l_port = 0; + +// const char *l_wallet_path = NULL; +// dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); +// if (!l_wallet_path) { +// l_wallet_path = +// #ifdef DAP_OS_WINDOWS +// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); +// #elif defined DAP_OS_MAC +// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); +// #elif defined DAP_OS_UNIX +// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); +// #endif +// } + +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_datoshi_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_value_fee_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str); +// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str); - // add 'out_cond' & 'out' items +// if(!l_token_ticker) { +// printf("tx_cond_create requires parameter '-token'\n"); +// return -2; +// } +// if (!l_wallet_str) { +// printf("tx_cond_create requires parameter '-w'\n"); +// return -3; +// } +// if (!l_cert_str) { +// printf("tx_cond_create requires parameter '-cert'\n"); +// return -4; +// } +// if(!l_value_datoshi_str) { +// printf("tx_cond_create requires parameter '-value'\n"); +// return -5; +// } +// if(!l_value_fee_str){ +// printf("tx_cond_create requires parameter '-fee'\n"); +// return -6; +// } +// if(!l_net_name) { +// printf("tx_cond_create requires parameter '-net'\n"); +// return -7; +// } +// if(!l_url_str) { +// l_url_str = dap_compose_get_net_url(l_net_name); +// } +// if(!l_port_str) { +// l_port = dap_compose_get_net_port(l_net_name); +// } else { +// l_port = atoi(l_port_str); +// } +// if(!l_unit_str) { +// printf("tx_cond_create requires parameter '-unit'\n"); +// return -8; +// } - { - dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID }; - dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(l_uid, s_get_net_id(a_net_name), a_price->datoshi_sell, - s_get_net_id(a_net_name), a_price->token_buy, a_price->rate, - &l_seller_addr, NULL, 0); - if (!l_tx_out) { - dap_chain_datum_tx_delete(l_tx); - printf("Can't compose the transaction conditional output\n"); - return NULL; - } - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); - DAP_DELETE(l_tx_out); - // Network fee - if (l_net_fee_used) { - if ((l_single_channel && - dap_chain_datum_tx_add_out_item(&l_tx, l_addr_net_fee, l_net_fee) != 1) || - (!l_single_channel && - dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add network fee output\n"); - return NULL; - } - } - DAP_DELETE(l_addr_net_fee); - // Validator's fee - if (!IS_ZERO_256(a_price->fee)) { - if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add validator's fee output\n"); - return NULL; - } - } - // coin back - uint256_t l_value_back = {}; - SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back); - if (!IS_ZERO_256(l_value_back)) { - if ((l_single_channel && - dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) || - (!l_single_channel && - dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_value_back, a_price->token_sell) != 1)) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add coin back output\n"); - return NULL; - } - } - // Fee coinback - if (!l_single_channel) { - uint256_t l_fee_coinback = {}; - SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback); - if (!IS_ZERO_256(l_fee_coinback)) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add fee back output\n"); - return NULL; - } - } - } - } - return l_tx; -} +// if(!l_srv_uid_str) { +// printf("tx_cond_create requires parameter '-srv_uid'\n"); +// return -9; +// } +// dap_chain_net_srv_uid_t l_srv_uid = {}; +// l_srv_uid.uint64 = strtoll(l_srv_uid_str, NULL, 10); +// if (!l_srv_uid.uint64) { +// printf("Can't find service UID %s\n", l_srv_uid_str); +// return -10; +// } -// tx_cond_create -net <net_name> -token <token_ticker> -w <wallet_name> -cert <pub_cert_name> -value <value_datoshi> -fee <value> -unit {B | SEC} -srv_uid <numeric_uid> -int dap_tx_cond_create_compose(int argc, char ** argv) -{ - int arg_index = 1; - const char * l_token_ticker = NULL; - const char * l_wallet_str = NULL; - const char * l_cert_str = NULL; - const char * l_value_datoshi_str = NULL; - const char * l_value_fee_str = NULL; - const char * l_net_name = NULL; - const char * l_unit_str = NULL; - const char * l_srv_uid_str = NULL; - uint256_t l_value_datoshi = {}; - uint256_t l_value_fee = {}; - const char * l_url_str = NULL; - const char * l_port_str = NULL; - uint16_t l_port = 0; - - const char *l_wallet_path = NULL; - dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); - if (!l_wallet_path) { - l_wallet_path = - #ifdef DAP_OS_WINDOWS - dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); - #elif defined DAP_OS_MAC - dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); - #elif defined DAP_OS_UNIX - dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); - #endif - } - - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_datoshi_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_value_fee_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str); - dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str); - - if(!l_token_ticker) { - printf("tx_cond_create requires parameter '-token'\n"); - return -2; - } - if (!l_wallet_str) { - printf("tx_cond_create requires parameter '-w'\n"); - return -3; - } - if (!l_cert_str) { - printf("tx_cond_create requires parameter '-cert'\n"); - return -4; - } - if(!l_value_datoshi_str) { - printf("tx_cond_create requires parameter '-value'\n"); - return -5; - } - if(!l_value_fee_str){ - printf("tx_cond_create requires parameter '-fee'\n"); - return -6; - } - if(!l_net_name) { - printf("tx_cond_create requires parameter '-net'\n"); - return -7; - } - if(!l_url_str) { - l_url_str = dap_compose_get_net_url(l_net_name); - } - if(!l_port_str) { - l_port = dap_compose_get_net_port(l_net_name); - } else { - l_port = atoi(l_port_str); - } - if(!l_unit_str) { - printf("tx_cond_create requires parameter '-unit'\n"); - return -8; - } +// dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)l_unit_str)}; - if(!l_srv_uid_str) { - printf("tx_cond_create requires parameter '-srv_uid'\n"); - return -9; - } - dap_chain_net_srv_uid_t l_srv_uid = {}; - l_srv_uid.uint64 = strtoll(l_srv_uid_str, NULL, 10); - if (!l_srv_uid.uint64) { - printf("Can't find service UID %s\n", l_srv_uid_str); - return -10; - } +// if(l_price_unit.enm == SERV_UNIT_UNDEFINED) { +// printf("Can't recognize unit '%s'. Unit must look like { B | SEC }\n", l_unit_str); +// return -11; +// } - dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)l_unit_str)}; +// l_value_datoshi = dap_chain_balance_scan(l_value_datoshi_str); +// if(IS_ZERO_256(l_value_datoshi)) { +// printf("Can't recognize value '%s' as a number\n", l_value_datoshi_str); +// return -12; +// } - if(l_price_unit.enm == SERV_UNIT_UNDEFINED) { - printf("Can't recognize unit '%s'. Unit must look like { B | SEC }\n", l_unit_str); - return -11; - } +// l_value_fee = dap_chain_balance_scan(l_value_fee_str); +// if(IS_ZERO_256(l_value_fee)) { +// printf("Can't recognize value '%s' as a number\n", l_value_fee_str); +// return -13; +// } - l_value_datoshi = dap_chain_balance_scan(l_value_datoshi_str); - if(IS_ZERO_256(l_value_datoshi)) { - printf("Can't recognize value '%s' as a number\n", l_value_datoshi_str); - return -12; - } +// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); +// if(!l_wallet) { +// printf("Can't open wallet '%s'\n", l_wallet_str); +// return -15; +// } - l_value_fee = dap_chain_balance_scan(l_value_fee_str); - if(IS_ZERO_256(l_value_fee)) { - printf("Can't recognize value '%s' as a number\n", l_value_fee_str); - return -13; - } +// dap_cert_t *l_cert_cond = dap_cert_find_by_name(l_cert_str); +// if(!l_cert_cond) { +// dap_chain_wallet_close(l_wallet); +// printf("Can't find cert '%s'\n", l_cert_str); +// return -16; +// } - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); - if(!l_wallet) { - printf("Can't open wallet '%s'\n", l_wallet_str); - return -15; - } +// dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet, 0); +// dap_pkey_t *l_key_cond = dap_pkey_from_enc_key(l_cert_cond->enc_key); +// if (!l_key_cond) { +// dap_chain_wallet_close(l_wallet); +// dap_enc_key_delete(l_key_from); +// printf("Cert '%s' doesn't contain a valid public key\n", l_cert_str); +// return -17; +// } - dap_cert_t *l_cert_cond = dap_cert_find_by_name(l_cert_str); - if(!l_cert_cond) { - dap_chain_wallet_close(l_wallet); - printf("Can't find cert '%s'\n", l_cert_str); - return -16; - } +// uint256_t l_value_per_unit_max = {}; +// dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker, +// l_value_datoshi, l_value_per_unit_max, l_price_unit, +// l_srv_uid, l_value_fee, NULL, 0, l_url_str, l_port); + +// json_object * l_json_obj_ret = json_object_new_object(); +// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); +// printf("%s", json_object_to_json_string(l_json_obj_ret)); +// json_object_put(l_json_obj_ret); +// dap_chain_datum_tx_delete(l_tx); +// dap_chain_wallet_close(l_wallet); +// dap_enc_key_delete(l_key_from); +// DAP_DELETE(l_key_cond); +// return 0; +// } - dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet, 0); - dap_pkey_t *l_key_cond = dap_pkey_from_enc_key(l_cert_cond->enc_key); - if (!l_key_cond) { - dap_chain_wallet_close(l_wallet); - dap_enc_key_delete(l_key_from); - printf("Cert '%s' doesn't contain a valid public key\n", l_cert_str); - return -17; - } - uint256_t l_value_per_unit_max = {}; - dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker, - l_value_datoshi, l_value_per_unit_max, l_price_unit, - l_srv_uid, l_value_fee, NULL, 0, l_url_str, l_port); - - json_object * l_json_obj_ret = json_object_new_object(); - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); - printf("%s", json_object_to_json_string(l_json_obj_ret)); - json_object_put(l_json_obj_ret); - dap_chain_datum_tx_delete(l_tx); - dap_chain_wallet_close(l_wallet); - dap_enc_key_delete(l_key_from); - DAP_DELETE(l_key_cond); - return 0; -} +// dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name, +// dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, +// const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], +// uint256_t a_value, uint256_t a_value_per_unit_max, +// dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, +// uint256_t a_value_fee, const void *a_cond, +// size_t a_cond_size, const char *a_url_str, uint16_t a_port) +// { +// // check valid param +// if (!a_net_name || !*a_net_name || !a_key_from || !a_key_cond || +// !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value) || !a_url_str || !*a_url_str || a_port == 0) +// return NULL; + +// if (dap_strcmp(s_get_native_ticker(a_net_name), a_token_ticker)) { +// printf("Pay for service should be only in native token ticker\n"); +// return NULL; +// } +// uint256_t l_net_fee = {}; +// dap_chain_addr_t* l_addr_fee = NULL; +// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port); +// // find the transactions from which to take away coins +// uint256_t l_value_transfer = {}; // how many coins to transfer +// uint256_t l_value_need = {}; +// SUM_256_256(a_value, a_value_fee, &l_value_need); +// if (l_net_fee_used) { +// SUM_256_256(l_value_need, l_net_fee, &l_value_need); +// } +// // where to take coins for service +// dap_chain_addr_t l_addr_from; +// dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, s_get_net_id(a_net_name)); +// // list of transaction with 'out' items +// json_object *l_outs = NULL; +// int l_outputs_count = 0; +// if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) { +// return NULL; +// } +// dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, +// l_value_need, +// &l_value_transfer); +// json_object_put(l_outs); +// if(!l_list_used_out) { +// printf("Nothing to transfer (not enough funds)\n"); +// return NULL; +// } -dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name, - dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, - const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], - uint256_t a_value, uint256_t a_value_per_unit_max, - dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, - uint256_t a_value_fee, const void *a_cond, - size_t a_cond_size, const char *a_url_str, uint16_t a_port) -{ - // check valid param - if (!a_net_name || !*a_net_name || !a_key_from || !a_key_cond || - !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value) || !a_url_str || !*a_url_str || a_port == 0) - return NULL; +// // create empty transaction +// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); +// // add 'in' items +// { +// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); +// assert(EQUAL_256(l_value_to_items, l_value_transfer)); +// dap_list_free_full(l_list_used_out, NULL); +// } +// // add 'out_cond' and 'out' items +// { +// uint256_t l_value_pack = {}; // how much coin add to 'out' items +// if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond, +// a_cond_size) == 1) { +// SUM_256_256(l_value_pack, a_value, &l_value_pack); +// } else { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add conditional output\n"); +// return NULL; +// } +// // Network fee +// if (l_net_fee_used) { +// if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) +// SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); +// else { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// // Validator's fee +// if (!IS_ZERO_256(a_value_fee)) { +// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) +// SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); +// else { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// // coin back +// uint256_t l_value_back = {}; +// SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); +// if (!IS_ZERO_256(l_value_back)) { +// if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add coin back output\n"); +// return NULL; +// } +// } +// } - if (dap_strcmp(s_get_native_ticker(a_net_name), a_token_ticker)) { - printf("Pay for service should be only in native token ticker\n"); - return NULL; - } +// return l_tx; +// } - uint256_t l_net_fee = {}; - dap_chain_addr_t* l_addr_fee = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port); - // find the transactions from which to take away coins - uint256_t l_value_transfer = {}; // how many coins to transfer - uint256_t l_value_need = {}; - SUM_256_256(a_value, a_value_fee, &l_value_need); - if (l_net_fee_used) { - SUM_256_256(l_value_need, l_net_fee, &l_value_need); - } - // where to take coins for service - dap_chain_addr_t l_addr_from; - dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, s_get_net_id(a_net_name)); - // list of transaction with 'out' items - json_object *l_outs = NULL; - int l_outputs_count = 0; - if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) { - return NULL; - } - dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, - l_value_need, - &l_value_transfer); - json_object_put(l_outs); - if(!l_list_used_out) { - printf("Nothing to transfer (not enough funds)\n"); - return NULL; - } +// // stake_lock hold -net <net_name> -w <wallet_name> -time_staking <YYMMDD> -token <ticker> -value <value> -fee <value>[-chain <chain_name>] [-reinvest <percentage>] +// int dap_cli_hold_compose(int a_argc, char **a_argv) +// { +// int arg_index = 1; +// const char *l_net_name = NULL, *l_ticker_str = NULL, *l_coins_str = NULL, +// *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL, +// *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL; + +// char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; +// dap_time_t l_time_staking = 0; +// uint256_t l_reinvest_percent = {}; +// uint256_t l_value_delegated = {}; +// uint256_t l_value_fee = {}; +// uint256_t l_value; +// dap_enc_key_t *l_key_from; +// dap_chain_wallet_t *l_wallet; +// dap_chain_addr_t *l_addr_holder; +// const char *l_url_str = NULL; +// uint16_t l_port = 0; + +// const char *l_wallet_path = NULL; +// dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); +// if (!l_wallet_path) { +// l_wallet_path = +// #ifdef DAP_OS_WINDOWS +// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); +// #elif defined DAP_OS_MAC +// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); +// #elif defined DAP_OS_UNIX +// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); +// #endif +// } + + +// const char *l_hash_out_type = NULL; +// dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); +// if(!l_hash_out_type) +// l_hash_out_type = "hex"; +// if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type, "base58")) { +// printf("Error: Invalid hash type argument\n"); +// return -1; +// } - // create empty transaction - dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - // add 'in' items - { - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); - assert(EQUAL_256(l_value_to_items, l_value_transfer)); - dap_list_free_full(l_list_used_out, NULL); - } - // add 'out_cond' and 'out' items - { - uint256_t l_value_pack = {}; // how much coin add to 'out' items - if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond, - a_cond_size) == 1) { - SUM_256_256(l_value_pack, a_value, &l_value_pack); - } else { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add conditional output\n"); - return NULL; - } - // Network fee - if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) - SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); - else { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - // Validator's fee - if (!IS_ZERO_256(a_value_fee)) { - if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) - SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); - else { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - // coin back - uint256_t l_value_back = {}; - SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); - if (!IS_ZERO_256(l_value_back)) { - if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add coin back output\n"); - return NULL; - } - } - } - - return l_tx; -} - -// stake_lock hold -net <net_name> -w <wallet_name> -time_staking <YYMMDD> -token <ticker> -value <value> -fee <value>[-chain <chain_name>] [-reinvest <percentage>] -int dap_cli_hold_compose(int a_argc, char **a_argv) -{ - int arg_index = 1; - const char *l_net_name = NULL, *l_ticker_str = NULL, *l_coins_str = NULL, - *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL, - *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL; - - char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; - dap_time_t l_time_staking = 0; - uint256_t l_reinvest_percent = {}; - uint256_t l_value_delegated = {}; - uint256_t l_value_fee = {}; - uint256_t l_value; - dap_enc_key_t *l_key_from; - dap_chain_wallet_t *l_wallet; - dap_chain_addr_t *l_addr_holder; - const char *l_url_str = NULL; - uint16_t l_port = 0; - - const char *l_wallet_path = NULL; - dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); - if (!l_wallet_path) { - l_wallet_path = - #ifdef DAP_OS_WINDOWS - dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); - #elif defined DAP_OS_MAC - dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); - #elif defined DAP_OS_UNIX - dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); - #endif - } - - - const char *l_hash_out_type = NULL; - dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); - if(!l_hash_out_type) - l_hash_out_type = "hex"; - if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type, "base58")) { - printf("Error: Invalid hash type argument\n"); - return -1; - } - - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_name) || NULL == l_net_name) { - printf("Error: Missing or invalid network argument\n"); - return -2; - } - - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_ticker_str) || NULL == l_ticker_str || dap_strlen(l_ticker_str) > 8) { - printf("Error: Missing or invalid token argument\n"); - return -3; - } - - if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) { - l_url_str = dap_compose_get_net_url(l_net_name); - } - - const char *l_port_str = NULL; - if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) { - l_port = dap_compose_get_net_port(l_net_name); - } else { - l_port = atoi(l_port_str); - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_name) || NULL == l_net_name) { +// printf("Error: Missing or invalid network argument\n"); +// return -2; +// } - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name); - json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port); - if (!l_json_coins) { - return -4; - } - if (!check_token_in_ledger(l_json_coins, l_ticker_str)) { - printf("Error: Invalid token '%s'\n", l_ticker_str); - return -4; - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_ticker_str) || NULL == l_ticker_str || dap_strlen(l_ticker_str) > 8) { +// printf("Error: Missing or invalid token argument\n"); +// return -3; +// } - if ((!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-coins", &l_coins_str) || NULL == l_coins_str) && - (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-value", &l_coins_str) || NULL == l_coins_str)) { - printf("Error: Missing coins or value argument\n"); - return -5; - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) { +// l_url_str = dap_compose_get_net_url(l_net_name); +// } - if (IS_ZERO_256((l_value = dap_chain_balance_scan(l_coins_str)))) { - printf("Error: Invalid coins format\n"); - return -6; - } +// const char *l_port_str = NULL; +// if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) { +// l_port = dap_compose_get_net_port(l_net_name); +// } else { +// l_port = atoi(l_port_str); +// } - dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str); +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name); +// json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port); +// if (!l_json_coins) { +// return -4; +// } +// if (!check_token_in_ledger(l_json_coins, l_ticker_str)) { +// printf("Error: Invalid token '%s'\n", l_ticker_str); +// return -4; +// } - if (!check_token_in_ledger(l_json_coins, l_delegated_ticker_str)) { - printf("Error: No delegated token found\n"); - return -7; - } - json_object_put(l_json_coins); +// if ((!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-coins", &l_coins_str) || NULL == l_coins_str) && +// (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-value", &l_coins_str) || NULL == l_coins_str)) { +// printf("Error: Missing coins or value argument\n"); +// return -5; +// } - uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001"); // TODO 16126 - // uint256_t l_emission_rate = dap_ledger_token_get_emission_rate(l_ledger, l_delegated_ticker_str); - // if (IS_ZERO_256(l_emission_rate)) { - // printf("Error: Invalid token emission rate\n"); - // return -8; - // } +// if (IS_ZERO_256((l_value = dap_chain_balance_scan(l_coins_str)))) { +// printf("Error: Invalid coins format\n"); +// return -6; +// } - if (MULT_256_COIN(l_value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) { - printf("Error: Invalid coins format\n"); - return -9; - } +// dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str); - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str); - if (!l_chain_id_str) { - printf("Error: Missing or invalid chain_id argument\n"); - return -10; - } +// if (!check_token_in_ledger(l_json_coins, l_delegated_ticker_str)) { +// printf("Error: No delegated token found\n"); +// return -7; +// } +// json_object_put(l_json_coins); + +// uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001"); // TODO 16126 +// // uint256_t l_emission_rate = dap_ledger_token_get_emission_rate(l_ledger, l_delegated_ticker_str); +// // if (IS_ZERO_256(l_emission_rate)) { +// // printf("Error: Invalid token emission rate\n"); +// // return -8; +// // } + +// if (MULT_256_COIN(l_value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) { +// printf("Error: Invalid coins format\n"); +// return -9; +// } - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) { - printf("Error: Missing wallet argument\n"); - return -11; - } +// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str); +// if (!l_chain_id_str) { +// printf("Error: Missing or invalid chain_id argument\n"); +// return -10; +// } - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) { - printf("Error: Missing fee argument\n"); - return -12; - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) { +// printf("Error: Missing wallet argument\n"); +// return -11; +// } - if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) { - printf("Error: Invalid fee format\n"); - return -13; - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) { +// printf("Error: Missing fee argument\n"); +// return -12; +// } - // Read time staking - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-time_staking", &l_time_staking_str) || !l_time_staking_str) { - printf("Error: Missing time staking argument\n"); - return -14; - } +// if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) { +// printf("Error: Invalid fee format\n"); +// return -13; +// } - if (dap_strlen(l_time_staking_str) != 6) { - printf("Error: Invalid time staking format\n"); - return -15; - } +// // Read time staking +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-time_staking", &l_time_staking_str) || !l_time_staking_str) { +// printf("Error: Missing time staking argument\n"); +// return -14; +// } - char l_time_staking_month_str[3] = {l_time_staking_str[2], l_time_staking_str[3], 0}; - int l_time_staking_month = atoi(l_time_staking_month_str); - if (l_time_staking_month < 1 || l_time_staking_month > 12) { - printf("Error: Invalid time staking month\n"); - return -16; - } +// if (dap_strlen(l_time_staking_str) != 6) { +// printf("Error: Invalid time staking format\n"); +// return -15; +// } - char l_time_staking_day_str[3] = {l_time_staking_str[4], l_time_staking_str[5], 0}; - int l_time_staking_day = atoi(l_time_staking_day_str); - if (l_time_staking_day < 1 || l_time_staking_day > 31) { - printf("Error: Invalid time staking day\n"); - return -17; - } +// char l_time_staking_month_str[3] = {l_time_staking_str[2], l_time_staking_str[3], 0}; +// int l_time_staking_month = atoi(l_time_staking_month_str); +// if (l_time_staking_month < 1 || l_time_staking_month > 12) { +// printf("Error: Invalid time staking month\n"); +// return -16; +// } - l_time_staking = dap_time_from_str_simplified(l_time_staking_str); - if (0 == l_time_staking) { - printf("Error: Invalid time staking\n"); - return -18; - } - dap_time_t l_time_now = dap_time_now(); - if (l_time_staking < l_time_now) { - printf("Error: Time staking is in the past\n"); - return -19; - } - l_time_staking -= l_time_now; +// char l_time_staking_day_str[3] = {l_time_staking_str[4], l_time_staking_str[5], 0}; +// int l_time_staking_day = atoi(l_time_staking_day_str); +// if (l_time_staking_day < 1 || l_time_staking_day > 31) { +// printf("Error: Invalid time staking day\n"); +// return -17; +// } - if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-reinvest", &l_reinvest_percent_str) && NULL != l_reinvest_percent_str) { - l_reinvest_percent = dap_chain_coins_to_balance(l_reinvest_percent_str); - if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1) { - printf("Error: Invalid reinvest percentage\n"); - return -20; - } - if (IS_ZERO_256(l_reinvest_percent)) { - int l_reinvest_percent_int = atoi(l_reinvest_percent_str); - if (l_reinvest_percent_int < 0 || l_reinvest_percent_int > 100) { - printf("Error: Invalid reinvest percentage\n"); - return -21; - } - l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int); - MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent); - } - } +// l_time_staking = dap_time_from_str_simplified(l_time_staking_str); +// if (0 == l_time_staking) { +// printf("Error: Invalid time staking\n"); +// return -18; +// } +// dap_time_t l_time_now = dap_time_now(); +// if (l_time_staking < l_time_now) { +// printf("Error: Time staking is in the past\n"); +// return -19; +// } +// l_time_staking -= l_time_now; - if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) { - printf("Error: Unable to open wallet '%s'\n", l_wallet_str); - return -22; - } +// if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-reinvest", &l_reinvest_percent_str) && NULL != l_reinvest_percent_str) { +// l_reinvest_percent = dap_chain_coins_to_balance(l_reinvest_percent_str); +// if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1) { +// printf("Error: Invalid reinvest percentage\n"); +// return -20; +// } +// if (IS_ZERO_256(l_reinvest_percent)) { +// int l_reinvest_percent_int = atoi(l_reinvest_percent_str); +// if (l_reinvest_percent_int < 0 || l_reinvest_percent_int > 100) { +// printf("Error: Invalid reinvest percentage\n"); +// return -21; +// } +// l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int); +// MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent); +// } +// } +// if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) { +// printf("Error: Unable to open wallet '%s'\n", l_wallet_str); +// return -22; +// } - if (NULL == (l_addr_holder = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)))) { - dap_chain_wallet_close(l_wallet); - printf("Error: Unable to get wallet address for '%s'\n", l_wallet_str); - return -24; - } - snprintf(data, sizeof(data), - "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", - dap_chain_addr_to_str(l_addr_holder), l_net_name); - DAP_DEL_Z(l_addr_holder); +// if (NULL == (l_addr_holder = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)))) { +// dap_chain_wallet_close(l_wallet); +// printf("Error: Unable to get wallet address for '%s'\n", l_wallet_str); +// return -24; +// } - json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port); - uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str); - json_object_put(l_json_outs); - if (compare256(l_value_balance, l_value) == -1) { - dap_chain_wallet_close(l_wallet); - printf("Error: Insufficient funds in wallet\n"); - return -23; - } +// snprintf(data, sizeof(data), +// "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", +// dap_chain_addr_to_str(l_addr_holder), l_net_name); +// DAP_DEL_Z(l_addr_holder); + +// json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port); +// uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str); +// json_object_put(l_json_outs); +// if (compare256(l_value_balance, l_value) == -1) { +// dap_chain_wallet_close(l_wallet); +// printf("Error: Insufficient funds in wallet\n"); +// return -23; +// } - l_key_from = dap_chain_wallet_get_key(l_wallet, 0); +// l_key_from = dap_chain_wallet_get_key(l_wallet, 0); - // Make transfer transaction - dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_net_name, l_key_from, - l_ticker_str, l_value, l_value_fee, - l_time_staking, l_reinvest_percent, - l_delegated_ticker_str, l_value_delegated, l_chain_id_str, l_url_str, l_port); +// // Make transfer transaction +// dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_net_name, l_key_from, +// l_ticker_str, l_value, l_value_fee, +// l_time_staking, l_reinvest_percent, +// l_delegated_ticker_str, l_value_delegated, l_chain_id_str, l_url_str, l_port); - json_object * l_json_obj_ret = json_object_new_object(); - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); - printf("%s", json_object_to_json_string(l_json_obj_ret)); - json_object_put(l_json_obj_ret); - dap_chain_datum_tx_delete(l_tx); +// json_object * l_json_obj_ret = json_object_new_object(); +// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); +// printf("%s", json_object_to_json_string(l_json_obj_ret)); +// json_object_put(l_json_obj_ret); +// dap_chain_datum_tx_delete(l_tx); - dap_chain_wallet_close(l_wallet); - dap_enc_key_delete(l_key_from); +// dap_chain_wallet_close(l_wallet); +// dap_enc_key_delete(l_key_from); - return 0; -} - - -dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, - const char *a_main_ticker, - uint256_t a_value, uint256_t a_value_fee, - dap_time_t a_time_staking, uint256_t a_reinvest_percent, - const char *a_delegated_ticker_str, uint256_t a_delegated_value, - const char * l_chain_id_str, const char *l_url_str, uint16_t l_port) -{ - dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID }; - // check valid param - if (!a_net_name || !a_key_from || - !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value)) - return NULL; - - const char *l_native_ticker = s_get_native_ticker(a_net_name); - bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker); - // find the transactions from which to take away coins - uint256_t l_value_transfer = {}; // how many coins to transfer - uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {}; - dap_chain_addr_t * l_addr_fee = NULL; - dap_chain_addr_t l_addr = {}; - - dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name)); - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port); - SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); - - json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port); - if (!l_outs_native) { - return NULL; - } +// return 0; +// } - json_object *l_outs_main = NULL; - if (!dap_strcmp(a_main_ticker, l_native_ticker)) { - l_outs_main = l_outs_native; - } else { - l_outs_main = dap_get_remote_tx_outs(a_main_ticker, a_net_name, &l_addr, l_url_str, l_port); - } - int l_out_native_count = json_object_array_length(l_outs_native); - int l_out_main_count = json_object_array_length(l_outs_main); - dap_list_t *l_list_fee_out = NULL; - if (l_main_native) - SUM_256_256(l_value_need, l_total_fee, &l_value_need); - else if (!IS_ZERO_256(l_total_fee)) { - l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, - l_total_fee, - &l_fee_transfer); - if (!l_list_fee_out) { - printf("Not enough funds to pay fee"); - json_object_put(l_outs_native); - json_object_put(l_outs_main); - return NULL; - } - } - // list of transaction with 'out' items - dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_main, l_out_main_count, - l_value_need, - &l_value_transfer); - if (!l_list_used_out) { - printf("Not enough funds to transfer"); - json_object_put(l_outs_native); - json_object_put(l_outs_main); - return NULL; - } +// dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, +// const char *a_main_ticker, +// uint256_t a_value, uint256_t a_value_fee, +// dap_time_t a_time_staking, uint256_t a_reinvest_percent, +// const char *a_delegated_ticker_str, uint256_t a_delegated_value, +// const char * l_chain_id_str, const char *l_url_str, uint16_t l_port) +// { +// dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID }; +// // check valid param +// if (!a_net_name || !a_key_from || +// !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value)) +// return NULL; + +// const char *l_native_ticker = s_get_native_ticker(a_net_name); +// bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker); +// // find the transactions from which to take away coins +// uint256_t l_value_transfer = {}; // how many coins to transfer +// uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {}; +// dap_chain_addr_t * l_addr_fee = NULL; +// dap_chain_addr_t l_addr = {}; + +// dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name)); +// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port); +// SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); + +// json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port); +// if (!l_outs_native) { +// return NULL; +// } - // create empty transaction - dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); +// json_object *l_outs_main = NULL; +// if (!dap_strcmp(a_main_ticker, l_native_ticker)) { +// l_outs_main = l_outs_native; +// } else { +// l_outs_main = dap_get_remote_tx_outs(a_main_ticker, a_net_name, &l_addr, l_url_str, l_port); +// } +// int l_out_native_count = json_object_array_length(l_outs_native); +// int l_out_main_count = json_object_array_length(l_outs_main); + +// dap_list_t *l_list_fee_out = NULL; +// if (l_main_native) +// SUM_256_256(l_value_need, l_total_fee, &l_value_need); +// else if (!IS_ZERO_256(l_total_fee)) { +// l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, +// l_total_fee, +// &l_fee_transfer); +// if (!l_list_fee_out) { +// printf("Not enough funds to pay fee"); +// json_object_put(l_outs_native); +// json_object_put(l_outs_main); +// return NULL; +// } +// } +// // list of transaction with 'out' items +// dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_main, l_out_main_count, +// l_value_need, +// &l_value_transfer); +// if (!l_list_used_out) { +// printf("Not enough funds to transfer"); +// json_object_put(l_outs_native); +// json_object_put(l_outs_main); +// return NULL; +// } - // add 'in' items - { - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); - assert(EQUAL_256(l_value_to_items, l_value_transfer)); - dap_list_free_full(l_list_used_out, NULL); - if (l_list_fee_out) { - uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); - assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); - dap_list_free_full(l_list_fee_out, NULL); - } - } +// // create empty transaction +// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + +// // add 'in' items +// { +// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); +// assert(EQUAL_256(l_value_to_items, l_value_transfer)); +// dap_list_free_full(l_list_used_out, NULL); +// if (l_list_fee_out) { +// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); +// assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); +// dap_list_free_full(l_list_fee_out, NULL); +// } +// } - // add 'in_ems' item - { - dap_chain_id_t l_chain_id = { }; - dap_chain_id_parse(l_chain_id_str, &l_chain_id); - dap_hash_fast_t l_blank_hash = {}; - dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(l_chain_id, &l_blank_hash, a_delegated_ticker_str); - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems); - } +// // add 'in_ems' item +// { +// dap_chain_id_t l_chain_id = { }; +// dap_chain_id_parse(l_chain_id_str, &l_chain_id); +// dap_hash_fast_t l_blank_hash = {}; +// dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(l_chain_id, &l_blank_hash, a_delegated_ticker_str); +// dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems); +// } - // add 'out_cond' and 'out_ext' items - { - uint256_t l_value_pack = {}, l_native_pack = {}; // how much coin add to 'out_ext' items - dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock( - l_uid, a_value, a_time_staking, a_reinvest_percent); - if (l_tx_out_cond) { - SUM_256_256(l_value_pack, a_value, &l_value_pack); - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond); - DAP_DEL_Z(l_tx_out_cond); - } else { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Cant add conditional output\n"); - return NULL; - } +// // add 'out_cond' and 'out_ext' items +// { +// uint256_t l_value_pack = {}, l_native_pack = {}; // how much coin add to 'out_ext' items +// dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock( +// l_uid, a_value, a_time_staking, a_reinvest_percent); +// if (l_tx_out_cond) { +// SUM_256_256(l_value_pack, a_value, &l_value_pack); +// dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond); +// DAP_DEL_Z(l_tx_out_cond); +// } else { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Cant add conditional output\n"); +// return NULL; +// } - uint256_t l_value_back = {}; - // Network fee - if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Cant add network fee output\n"); - return NULL; - } - if (l_main_native) - SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); - else - SUM_256_256(l_native_pack, l_net_fee, &l_native_pack); - } - // Validator's fee - if (!IS_ZERO_256(a_value_fee)) { - if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Cant add validator's fee output\n"); - return NULL; - } - if (l_main_native) - SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); - else - SUM_256_256(l_native_pack, a_value_fee, &l_native_pack); - } - // coin back - SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); - if (!IS_ZERO_256(l_value_back)) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Cant add coin back output for main ticker\n"); - return NULL; - } - } - // fee coin back - if (!IS_ZERO_256(l_fee_transfer)) { - SUBTRACT_256_256(l_fee_transfer, l_native_pack, &l_value_back); - if (!IS_ZERO_256(l_value_back)) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Cant add coin back output for native ticker\n"); - return NULL; - } - } - } - } +// uint256_t l_value_back = {}; +// // Network fee +// if (l_net_fee_used) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Cant add network fee output\n"); +// return NULL; +// } +// if (l_main_native) +// SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); +// else +// SUM_256_256(l_native_pack, l_net_fee, &l_native_pack); +// } +// // Validator's fee +// if (!IS_ZERO_256(a_value_fee)) { +// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Cant add validator's fee output\n"); +// return NULL; +// } +// if (l_main_native) +// SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); +// else +// SUM_256_256(l_native_pack, a_value_fee, &l_native_pack); +// } +// // coin back +// SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); +// if (!IS_ZERO_256(l_value_back)) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Cant add coin back output for main ticker\n"); +// return NULL; +// } +// } +// // fee coin back +// if (!IS_ZERO_256(l_fee_transfer)) { +// SUBTRACT_256_256(l_fee_transfer, l_native_pack, &l_value_back); +// if (!IS_ZERO_256(l_value_back)) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Cant add coin back output for native ticker\n"); +// return NULL; +// } +// } +// } +// } - // add delegated token emission 'out_ext' - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_delegated_value, a_delegated_ticker_str) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Cant add delegated token emission output\n"); - return NULL; - } +// // add delegated token emission 'out_ext' +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_delegated_value, a_delegated_ticker_str) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Cant add delegated token emission output\n"); +// return NULL; +// } - return l_tx; -} +// return l_tx; +// } -int dap_cli_take_compose(int a_argc, char **a_argv) -{ - int arg_index = 1; - const char *l_net_str, *l_ticker_str, *l_wallet_str, *l_tx_str, *l_tx_burning_str, *l_chain_id_str, *l_value_fee_str; - l_net_str = l_ticker_str = l_wallet_str = l_tx_str = l_tx_burning_str = l_chain_id_str = l_value_fee_str = NULL; - char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; - int l_prev_cond_idx = 0; - uint256_t l_value_delegated = {}; - uint256_t l_value_fee = {}; - dap_chain_wallet_t *l_wallet; - dap_hash_fast_t l_tx_hash; - dap_chain_tx_out_cond_t *l_cond_tx = NULL; - dap_enc_key_t *l_owner_key; - const char *l_url_str = NULL; - uint16_t l_port = 0; - - - const char *l_wallet_path = NULL; - dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); - if (!l_wallet_path) { - l_wallet_path = - #ifdef DAP_OS_WINDOWS - dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); - #elif defined DAP_OS_MAC - dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); - #elif defined DAP_OS_UNIX - dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); - #endif - } - - - const char *l_hash_out_type = NULL; - dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); - if (!l_hash_out_type) - l_hash_out_type = "hex"; - if (dap_strcmp(l_hash_out_type, "hex") && dap_strcmp(l_hash_out_type, "base58")) { - printf("Error: Invalid hash type argument\n"); - return -1; - } +// int dap_cli_take_compose(int a_argc, char **a_argv) +// { +// int arg_index = 1; +// const char *l_net_str, *l_ticker_str, *l_wallet_str, *l_tx_str, *l_tx_burning_str, *l_chain_id_str, *l_value_fee_str; +// l_net_str = l_ticker_str = l_wallet_str = l_tx_str = l_tx_burning_str = l_chain_id_str = l_value_fee_str = NULL; +// char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; +// int l_prev_cond_idx = 0; +// uint256_t l_value_delegated = {}; +// uint256_t l_value_fee = {}; +// dap_chain_wallet_t *l_wallet; +// dap_hash_fast_t l_tx_hash; +// dap_chain_tx_out_cond_t *l_cond_tx = NULL; +// dap_enc_key_t *l_owner_key; +// const char *l_url_str = NULL; +// uint16_t l_port = 0; + + +// const char *l_wallet_path = NULL; +// dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); +// if (!l_wallet_path) { +// l_wallet_path = +// #ifdef DAP_OS_WINDOWS +// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); +// #elif defined DAP_OS_MAC +// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); +// #elif defined DAP_OS_UNIX +// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); +// #endif +// } + + +// const char *l_hash_out_type = NULL; +// dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); +// if (!l_hash_out_type) +// l_hash_out_type = "hex"; +// if (dap_strcmp(l_hash_out_type, "hex") && dap_strcmp(l_hash_out_type, "base58")) { +// printf("Error: Invalid hash type argument\n"); +// return -1; +// } - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str) || NULL == l_net_str) { - printf("Error: Missing or invalid network argument\n"); - return -2; - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str) || NULL == l_net_str) { +// printf("Error: Missing or invalid network argument\n"); +// return -2; +// } - if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) { - l_url_str = dap_compose_get_net_url(l_net_str); - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) { +// l_url_str = dap_compose_get_net_url(l_net_str); +// } - const char *l_port_str = NULL; - if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) { - l_port = dap_compose_get_net_port(l_net_str); - } else { - l_port = atoi(l_port_str); - } +// const char *l_port_str = NULL; +// if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) { +// l_port = dap_compose_get_net_port(l_net_str); +// } else { +// l_port = atoi(l_port_str); +// } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str); - if (!l_chain_id_str) { - printf("Error: Missing or invalid chain_id argument\n"); - return -10; - } +// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str); +// if (!l_chain_id_str) { +// printf("Error: Missing or invalid chain_id argument\n"); +// return -10; +// } - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_str) || NULL == l_tx_str) { - printf("Error: Missing or invalid transaction argument\n"); - return -5; - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_str) || NULL == l_tx_str) { +// printf("Error: Missing or invalid transaction argument\n"); +// return -5; +// } - if (dap_chain_hash_fast_from_str(l_tx_str, &l_tx_hash)) { - printf("Error: Invalid transaction hash\n"); - return -6; - } +// if (dap_chain_hash_fast_from_str(l_tx_str, &l_tx_hash)) { +// printf("Error: Invalid transaction hash\n"); +// return -6; +// } - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", - l_tx_str, l_net_str); +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", +// l_tx_str, l_net_str); - json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); - if (!response) { - printf("Error: Failed to get response from remote node\n"); - return -15; - } +// json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); +// if (!response) { +// printf("Error: Failed to get response from remote node\n"); +// return -15; +// } - json_object *items = NULL; - json_object *items_array = json_object_array_get_idx(response, 0); - if (items_array) { - items = json_object_object_get(items_array, "ITEMS"); - } - if (!items) { - printf("Error: No items found in response\n"); - return -16; - } - int items_count = json_object_array_length(items); - for (int i = 0; i < items_count; i++) { - json_object *item = json_object_array_get_idx(items, i); - const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); - if (dap_strcmp(item_type, "OUT COND") == 0) { - const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); - if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK")) { - l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); - l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; - l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); - l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK; - l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); - l_cond_tx->subtype.srv_stake_lock.time_unlock = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "time_unlock"))); - break; - } - } - } - if (!l_cond_tx) { - printf("Error: No transaction output condition found\n"); - return -7; - } +// json_object *items = NULL; +// json_object *items_array = json_object_array_get_idx(response, 0); +// if (items_array) { +// items = json_object_object_get(items_array, "ITEMS"); +// } +// if (!items) { +// printf("Error: No items found in response\n"); +// return -16; +// } +// int items_count = json_object_array_length(items); +// for (int i = 0; i < items_count; i++) { +// json_object *item = json_object_array_get_idx(items, i); +// const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); +// if (dap_strcmp(item_type, "OUT COND") == 0) { +// const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); +// if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK")) { +// l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); +// l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; +// l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); +// l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK; +// l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); +// l_cond_tx->subtype.srv_stake_lock.time_unlock = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "time_unlock"))); +// break; +// } +// } +// } +// if (!l_cond_tx) { +// printf("Error: No transaction output condition found\n"); +// return -7; +// } - json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); - const char *spent_outs_value = json_object_get_string(spent_outs); - if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { - printf("Error: Transaction output item already used\n"); - return -9; - } - - json_object *response_header_array = json_object_array_get_idx(response, 0); - if (!response_header_array) { - printf("Error: Failed to get items array from response\n"); - return -10; - } +// json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); +// const char *spent_outs_value = json_object_get_string(spent_outs); +// if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { +// printf("Error: Transaction output item already used\n"); +// return -9; +// } - json_object *token_ticker_obj = json_object_object_get(response_header_array, "token ticker"); - if (!token_ticker_obj) { - printf("Error: Token ticker not found in response\n"); - return -11; - } - l_ticker_str = json_object_get_string(token_ticker_obj); +// json_object *response_header_array = json_object_array_get_idx(response, 0); +// if (!response_header_array) { +// printf("Error: Failed to get items array from response\n"); +// return -10; +// } +// json_object *token_ticker_obj = json_object_object_get(response_header_array, "token ticker"); +// if (!token_ticker_obj) { +// printf("Error: Token ticker not found in response\n"); +// return -11; +// } +// l_ticker_str = json_object_get_string(token_ticker_obj); - dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str); - uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001"); +// dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str); - if (IS_ZERO_256(l_emission_rate) || - MULT_256_COIN(l_cond_tx->header.value, l_emission_rate, &l_value_delegated) || - IS_ZERO_256(l_value_delegated)) { - printf("Error: Invalid coins format\n"); - return -12; - } +// uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001"); +// if (IS_ZERO_256(l_emission_rate) || +// MULT_256_COIN(l_cond_tx->header.value, l_emission_rate, &l_value_delegated) || +// IS_ZERO_256(l_value_delegated)) { +// printf("Error: Invalid coins format\n"); +// return -12; +// } - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) { - printf("Error: Missing or invalid wallet argument\n"); - return -13; - } - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) { - printf("Error: Missing or invalid fee argument\n"); - return -14; - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) { +// printf("Error: Missing or invalid wallet argument\n"); +// return -13; +// } - if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) { - printf("Error: Invalid fee format\n"); - return -15; - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) { +// printf("Error: Missing or invalid fee argument\n"); +// return -14; +// } - if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) { - printf("Error: Unable to open wallet\n"); - return -16; - } +// if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) { +// printf("Error: Invalid fee format\n"); +// return -15; +// } - if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) { - dap_chain_wallet_close(l_wallet); - printf("Error: Owner key not found\n"); - return -17; - } +// if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) { +// printf("Error: Unable to open wallet\n"); +// return -16; +// } - if (l_cond_tx->subtype.srv_stake_lock.time_unlock > dap_time_now()) { - dap_chain_wallet_close(l_wallet); - dap_enc_key_delete(l_owner_key); - printf("Error: Not enough time has passed for unlocking\n"); - return -19; - } - dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_net_str, l_owner_key, &l_tx_hash, l_prev_cond_idx, - l_ticker_str, l_cond_tx->header.value, l_value_fee, - l_delegated_ticker_str, l_value_delegated, l_url_str, l_port); +// if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) { +// dap_chain_wallet_close(l_wallet); +// printf("Error: Owner key not found\n"); +// return -17; +// } - json_object * l_json_obj_ret = json_object_new_object(); - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); - printf("%s", json_object_to_json_string(l_json_obj_ret)); - json_object_put(l_json_obj_ret); +// if (l_cond_tx->subtype.srv_stake_lock.time_unlock > dap_time_now()) { +// dap_chain_wallet_close(l_wallet); +// dap_enc_key_delete(l_owner_key); +// printf("Error: Not enough time has passed for unlocking\n"); +// return -19; +// } +// dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_net_str, l_owner_key, &l_tx_hash, l_prev_cond_idx, +// l_ticker_str, l_cond_tx->header.value, l_value_fee, +// l_delegated_ticker_str, l_value_delegated, l_url_str, l_port); +// json_object * l_json_obj_ret = json_object_new_object(); +// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); +// printf("%s", json_object_to_json_string(l_json_obj_ret)); +// json_object_put(l_json_obj_ret); - dap_chain_datum_tx_delete(l_tx); - dap_enc_key_delete(l_owner_key); - return 0; -} +// dap_chain_datum_tx_delete(l_tx); +// dap_enc_key_delete(l_owner_key); -dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, - dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, - const char *a_main_ticker, uint256_t a_value, - uint256_t a_value_fee, - const char *a_delegated_ticker_str, uint256_t a_delegated_value, - const char *l_url_str, uint16_t l_port) -{ - // check valid param - if (!a_net_name | !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) { - printf("Error: Invalid parameters\n"); - return NULL; - } +// return 0; +// } - const char *l_native_ticker = s_get_native_ticker(a_net_name); - bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker); - // find the transactions from which to take away coins - uint256_t l_value_transfer = {}; // how many coins to transfer - uint256_t l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {}; - dap_chain_addr_t* l_addr_fee = NULL; - dap_chain_addr_t l_addr = {}; +// dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, +// dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, +// const char *a_main_ticker, uint256_t a_value, +// uint256_t a_value_fee, +// const char *a_delegated_ticker_str, uint256_t a_delegated_value, +// const char *l_url_str, uint16_t l_port) +// { +// // check valid param +// if (!a_net_name | !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) { +// printf("Error: Invalid parameters\n"); +// return NULL; +// } - dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name)); - dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL; +// const char *l_native_ticker = s_get_native_ticker(a_net_name); +// bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker); +// // find the transactions from which to take away coins +// uint256_t l_value_transfer = {}; // how many coins to transfer +// uint256_t l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {}; +// dap_chain_addr_t* l_addr_fee = NULL; +// dap_chain_addr_t l_addr = {}; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port); +// dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name)); +// dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL; - json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port); - if (!l_outs_native) { - return NULL; - } +// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port); - json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, a_net_name, &l_addr, l_url_str, l_port); - if (!l_outs_delegated) { - return NULL; - } +// json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port); +// if (!l_outs_native) { +// return NULL; +// } - int l_out_native_count = json_object_array_length(l_outs_native); - int l_out_delegated_count = json_object_array_length(l_outs_delegated); +// json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, a_net_name, &l_addr, l_url_str, l_port); +// if (!l_outs_delegated) { +// return NULL; +// } - SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); - if (!IS_ZERO_256(l_total_fee)) { - if (!l_main_native) { - l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, - l_total_fee, - &l_fee_transfer); - if (!l_list_fee_out) { - printf("Not enough funds to pay fee"); - json_object_put(l_outs_native); - json_object_put(l_outs_delegated); - return NULL; - } - } else if (compare256(a_value, l_total_fee) == -1) { - printf("Error: Total fee more than stake\n"); - return NULL; - } - } - if (!IS_ZERO_256(a_delegated_value)) { - l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count, - a_delegated_value, - &l_value_transfer); - if (!l_list_used_out) { - printf("Not enough funds to pay fee"); - json_object_put(l_outs_native); - json_object_put(l_outs_delegated); - return NULL; - } - } +// int l_out_native_count = json_object_array_length(l_outs_native); +// int l_out_delegated_count = json_object_array_length(l_outs_delegated); + +// SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); +// if (!IS_ZERO_256(l_total_fee)) { +// if (!l_main_native) { +// l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, +// l_total_fee, +// &l_fee_transfer); +// if (!l_list_fee_out) { +// printf("Not enough funds to pay fee"); +// json_object_put(l_outs_native); +// json_object_put(l_outs_delegated); +// return NULL; +// } +// } else if (compare256(a_value, l_total_fee) == -1) { +// printf("Error: Total fee more than stake\n"); +// return NULL; +// } +// } +// if (!IS_ZERO_256(a_delegated_value)) { +// l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count, +// a_delegated_value, +// &l_value_transfer); +// if (!l_list_used_out) { +// printf("Not enough funds to pay fee"); +// json_object_put(l_outs_native); +// json_object_put(l_outs_delegated); +// return NULL; +// } +// } - // create empty transaction - dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); +// // create empty transaction +// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - // add 'in_cond' & 'in' items - { - dap_chain_datum_tx_add_in_cond_item(&l_tx, a_stake_tx_hash, a_prev_cond_idx, 0); - if (l_list_used_out) { - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); - assert(EQUAL_256(l_value_to_items, l_value_transfer)); - dap_list_free_full(l_list_used_out, NULL); - } - if (l_list_fee_out) { - uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); - assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); - dap_list_free_full(l_list_fee_out, NULL); - } - } +// // add 'in_cond' & 'in' items +// { +// dap_chain_datum_tx_add_in_cond_item(&l_tx, a_stake_tx_hash, a_prev_cond_idx, 0); +// if (l_list_used_out) { +// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); +// assert(EQUAL_256(l_value_to_items, l_value_transfer)); +// dap_list_free_full(l_list_used_out, NULL); +// } +// if (l_list_fee_out) { +// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); +// assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); +// dap_list_free_full(l_list_fee_out, NULL); +// } +// } - // add 'out_ext' items - uint256_t l_value_back; - { - uint256_t l_value_pack = {}; // how much datoshi add to 'out' items - // Network fee - if(l_net_fee_used){ - if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker)){ - dap_chain_datum_tx_delete(l_tx); - printf("Error: Can't add network fee output\n"); - return NULL; - } - SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); - } - // Validator's fee - if (!IS_ZERO_256(a_value_fee)) { - if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) - { - SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); - } - else { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Can't add validator's fee output\n"); - return NULL; - } - } - // coin back - //SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back); - if(l_main_native){ - if (SUBTRACT_256_256(a_value, l_value_pack, &l_value_back)) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Can't subtract value pack from value\n"); - return NULL; - } - if(!IS_ZERO_256(l_value_back)) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker)!=1) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Can't add coin back output for main ticker\n"); - return NULL; - } - } - } else { - SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back); - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_value, a_main_ticker)!=1) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Can't add coin back output for main ticker\n"); - return NULL; - } - else - { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker)!=1) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Can't add coin back output for native ticker\n"); - return NULL; - } - } - } - } +// // add 'out_ext' items +// uint256_t l_value_back; +// { +// uint256_t l_value_pack = {}; // how much datoshi add to 'out' items +// // Network fee +// if(l_net_fee_used){ +// if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker)){ +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Can't add network fee output\n"); +// return NULL; +// } +// SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); +// } +// // Validator's fee +// if (!IS_ZERO_256(a_value_fee)) { +// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) +// { +// SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); +// } +// else { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Can't add validator's fee output\n"); +// return NULL; +// } +// } +// // coin back +// //SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back); +// if(l_main_native){ +// if (SUBTRACT_256_256(a_value, l_value_pack, &l_value_back)) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Can't subtract value pack from value\n"); +// return NULL; +// } +// if(!IS_ZERO_256(l_value_back)) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker)!=1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Can't add coin back output for main ticker\n"); +// return NULL; +// } +// } +// } else { +// SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back); +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_value, a_main_ticker)!=1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Can't add coin back output for main ticker\n"); +// return NULL; +// } +// else +// { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker)!=1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Can't add coin back output for native ticker\n"); +// return NULL; +// } +// } +// } +// } - // add burning 'out_ext' - if (!IS_ZERO_256(a_delegated_value)) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &c_dap_chain_addr_blank, - a_delegated_value, a_delegated_ticker_str) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Can't add burning output for delegated value\n"); - return NULL; - } - // delegated token coin back - SUBTRACT_256_256(l_value_transfer, a_delegated_value, &l_value_back); - if (!IS_ZERO_256(l_value_back)) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_delegated_ticker_str) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Error: Can't add coin back output for delegated ticker\n"); - return NULL; - } - } - } +// // add burning 'out_ext' +// if (!IS_ZERO_256(a_delegated_value)) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &c_dap_chain_addr_blank, +// a_delegated_value, a_delegated_ticker_str) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Can't add burning output for delegated value\n"); +// return NULL; +// } +// // delegated token coin back +// SUBTRACT_256_256(l_value_transfer, a_delegated_value, &l_value_back); +// if (!IS_ZERO_256(l_value_back)) { +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_delegated_ticker_str) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Error: Can't add coin back output for delegated ticker\n"); +// return NULL; +// } +// } +// } - return l_tx; -} +// return l_tx; +// } -uint256_t s_get_key_delegating_min_value(const char *a_net_str, const char *l_url_str, uint16_t l_port){ +uint256_t s_get_key_delegating_min_value(compose_config_t *a_config){ uint256_t l_key_delegating_min_value = uint256_0; char data[512]; snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", - a_net_str); + a_config->net_name); - json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + json_object *response = dap_request_command_to_rpc(data, a_config); if (!response) { printf("Error: Failed to get response from remote node\n"); return l_key_delegating_min_value; @@ -2375,320 +2415,320 @@ uint256_t s_get_key_delegating_min_value(const char *a_net_str, const char *l_ur } -int dap_cli_voting_compose(int a_argc, char **a_argv) -{ - int arg_index = 1; - const char* l_question_str = NULL; - const char* l_options_list_str = NULL; - const char* l_voting_expire_str = NULL; - const char* l_max_votes_count_str = NULL; - const char* l_fee_str = NULL; - const char* l_wallet_str = NULL; - const char* l_net_str = NULL; - const char* l_token_str = NULL; - const char* l_url_str = NULL; - uint16_t l_port = 0; - const char *l_wallet_path = NULL; - dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); - if (!l_wallet_path) { - l_wallet_path = - #ifdef DAP_OS_WINDOWS - dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); - #elif defined DAP_OS_MAC - dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); - #elif defined DAP_OS_UNIX - dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); - #endif - } +// int dap_cli_voting_compose(int a_argc, char **a_argv) +// { +// int arg_index = 1; +// const char* l_question_str = NULL; +// const char* l_options_list_str = NULL; +// const char* l_voting_expire_str = NULL; +// const char* l_max_votes_count_str = NULL; +// const char* l_fee_str = NULL; +// const char* l_wallet_str = NULL; +// const char* l_net_str = NULL; +// const char* l_token_str = NULL; +// const char* l_url_str = NULL; +// uint16_t l_port = 0; +// const char *l_wallet_path = NULL; +// dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); +// if (!l_wallet_path) { +// l_wallet_path = +// #ifdef DAP_OS_WINDOWS +// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); +// #elif defined DAP_OS_MAC +// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); +// #elif defined DAP_OS_UNIX +// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); +// #endif +// } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); - // Select chain network - if(!l_net_str) { - printf("Voting requires parameter '-net' to be valid.\n"); - return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING; - } +// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); +// // Select chain network +// if(!l_net_str) { +// printf("Voting requires parameter '-net' to be valid.\n"); +// return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING; +// } - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-url", &l_url_str)) { - l_url_str = dap_compose_get_net_url(l_net_str); - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-url", &l_url_str)) { +// l_url_str = dap_compose_get_net_url(l_net_str); +// } - const char *l_port_str = NULL; - if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str)) { - l_port = dap_compose_get_net_port(l_net_str); - } else { - l_port = atoi(l_port_str); - } +// const char *l_port_str = NULL; +// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str)) { +// l_port = dap_compose_get_net_port(l_net_str); +// } else { +// l_port = atoi(l_port_str); +// } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str); - if (!l_question_str){ - printf("Voting requires a question parameter to be valid.\n"); - return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_PARAM_MISSING; - } +// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str); +// if (!l_question_str){ +// printf("Voting requires a question parameter to be valid.\n"); +// return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_PARAM_MISSING; +// } - if (strlen(l_question_str) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ - printf("The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH); - return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_CONTAIN_MAX_CHARACTERS; - } +// if (strlen(l_question_str) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ +// printf("The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH); +// return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_CONTAIN_MAX_CHARACTERS; +// } - dap_list_t *l_options_list = NULL; - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-options", &l_options_list_str); - if (!l_options_list_str){ - printf("Voting requires a question parameter to be valid.\n"); - return -DAP_CHAIN_NET_VOTE_CREATE_OPTION_PARAM_MISSING; - } - // Parse options list - l_options_list = dap_get_options_list_from_str(l_options_list_str); - if(!l_options_list || dap_list_length(l_options_list) < 2){ - printf("Number of options must be 2 or greater.\n"); - return -DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR; - } +// dap_list_t *l_options_list = NULL; +// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-options", &l_options_list_str); +// if (!l_options_list_str){ +// printf("Voting requires a question parameter to be valid.\n"); +// return -DAP_CHAIN_NET_VOTE_CREATE_OPTION_PARAM_MISSING; +// } +// // Parse options list +// l_options_list = dap_get_options_list_from_str(l_options_list_str); +// if(!l_options_list || dap_list_length(l_options_list) < 2){ +// printf("Number of options must be 2 or greater.\n"); +// return -DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR; +// } - if(dap_list_length(l_options_list)>DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){ - printf("The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT); - return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS; - } +// if(dap_list_length(l_options_list)>DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){ +// printf("The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT); +// return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS; +// } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str); - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str); - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str); - if (!l_fee_str){ - printf("Voting requires parameter -fee to be valid.\n"); - return -DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID; - } - uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str); +// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str); +// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str); +// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str); +// if (!l_fee_str){ +// printf("Voting requires parameter -fee to be valid.\n"); +// return -DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID; +// } +// uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str); - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str); - if (!l_wallet_str){ - printf("Voting requires parameter -w to be valid.\n"); - return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID; - } +// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str); +// if (!l_wallet_str){ +// printf("Voting requires parameter -w to be valid.\n"); +// return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID; +// } - dap_time_t l_time_expire = 0; - if (l_voting_expire_str) - l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str); - if (l_voting_expire_str && !l_time_expire){ - printf("Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"\n"); - return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT; - } - uint64_t l_max_count = 0; - if (l_max_votes_count_str) - l_max_count = strtoul(l_max_votes_count_str, NULL, 10); - - bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false; - bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false; - dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); - if (!l_wallet_fee) { - printf("Wallet %s does not exist\n", l_wallet_str); - return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; - } +// dap_time_t l_time_expire = 0; +// if (l_voting_expire_str) +// l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str); +// if (l_voting_expire_str && !l_time_expire){ +// printf("Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"\n"); +// return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT; +// } +// uint64_t l_max_count = 0; +// if (l_max_votes_count_str) +// l_max_count = strtoul(l_max_votes_count_str, NULL, 10); + +// bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false; +// bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false; +// dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); +// if (!l_wallet_fee) { +// printf("Wallet %s does not exist\n", l_wallet_str); +// return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; +// } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str); - if (!l_token_str) { - printf("Command required -token argument"); - return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; - } +// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str); +// if (!l_token_str) { +// printf("Command required -token argument"); +// return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; +// } - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str); - json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); - if (!l_json_coins) { - printf("Error: Can't get ledger coins list\n"); - return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; - } - if (!check_token_in_ledger(l_json_coins, l_token_str)) { - json_object_put(l_json_coins); - printf("Token %s does not exist\n", l_token_str); - return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN; - } - json_object_put(l_json_coins); - - dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, - l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, - l_wallet_fee, l_net_str, l_token_str, l_url_str, l_port); - dap_list_free(l_options_list); - dap_chain_wallet_close(l_wallet_fee); - json_object * l_json_obj_ret = json_object_new_object(); - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); - printf("%s", json_object_to_json_string(l_json_obj_ret)); - json_object_put(l_json_obj_ret); - return 0; -} +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str); +// json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); +// if (!l_json_coins) { +// printf("Error: Can't get ledger coins list\n"); +// return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; +// } +// if (!check_token_in_ledger(l_json_coins, l_token_str)) { +// json_object_put(l_json_coins); +// printf("Token %s does not exist\n", l_token_str); +// return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN; +// } +// json_object_put(l_json_coins); + +// dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, +// l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, +// l_wallet_fee, l_net_str, l_token_str, l_url_str, l_port); +// dap_list_free(l_options_list); +// dap_chain_wallet_close(l_wallet_fee); +// json_object * l_json_obj_ret = json_object_new_object(); +// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); +// printf("%s", json_object_to_json_string(l_json_obj_ret)); +// json_object_put(l_json_obj_ret); +// return 0; +// } -dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, - uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, - bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, - const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port) { +// dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, +// uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, +// bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, +// const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port) { - if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ - return NULL; - } +// if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ +// return NULL; +// } - // Parse options list +// // Parse options list - if(dap_list_length(a_options) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){ - return NULL; - } +// if(dap_list_length(a_options) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){ +// return NULL; +// } - if (IS_ZERO_256(a_fee)) { - return NULL; - } +// if (IS_ZERO_256(a_fee)) { +// return NULL; +// } - dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str)); +// dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str)); - if(!l_addr_from) { - return NULL; - } +// if(!l_addr_from) { +// return NULL; +// } - const char *l_native_ticker = s_get_native_ticker(a_net_str); - uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer; - dap_chain_addr_t *l_addr_fee = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port); - SUM_256_256(l_net_fee, a_fee, &l_total_fee); +// const char *l_native_ticker = s_get_native_ticker(a_net_str); +// uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer; +// dap_chain_addr_t *l_addr_fee = NULL; +// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port); +// SUM_256_256(l_net_fee, a_fee, &l_total_fee); - json_object *l_outs = NULL; - int l_outputs_count = 0; - if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count, l_url_str, l_port)) { - return NULL; - } +// json_object *l_outs = NULL; +// int l_outputs_count = 0; +// if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count, l_url_str, l_port)) { +// return NULL; +// } - dap_list_t *l_list_used_out = NULL; - l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, - l_total_fee, - &l_value_transfer); +// dap_list_t *l_list_used_out = NULL; +// l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, +// l_total_fee, +// &l_value_transfer); - json_object_put(l_outs); - if (!l_list_used_out) { - printf("Not enough funds to transfer"); - return NULL; - } +// json_object_put(l_outs); +// if (!l_list_used_out) { +// printf("Not enough funds to transfer"); +// return NULL; +// } - // create empty transaction - dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); +// // create empty transaction +// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - // Add Voting item - dap_chain_tx_voting_t* l_voting_item = dap_chain_datum_tx_item_voting_create(); +// // Add Voting item +// dap_chain_tx_voting_t* l_voting_item = dap_chain_datum_tx_item_voting_create(); - dap_chain_datum_tx_add_item(&l_tx, l_voting_item); - DAP_DELETE(l_voting_item); +// dap_chain_datum_tx_add_item(&l_tx, l_voting_item); +// DAP_DELETE(l_voting_item); - // Add question to tsd data - dap_chain_tx_tsd_t* l_question_tsd = dap_chain_datum_voting_question_tsd_create(a_question, strlen(a_question)); - dap_chain_datum_tx_add_item(&l_tx, l_question_tsd); +// // Add question to tsd data +// dap_chain_tx_tsd_t* l_question_tsd = dap_chain_datum_voting_question_tsd_create(a_question, strlen(a_question)); +// dap_chain_datum_tx_add_item(&l_tx, l_question_tsd); - // Add options to tsd - dap_list_t *l_temp = a_options; - while(l_temp){ - if(strlen((char*)l_temp->data) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH){ - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - dap_chain_tx_tsd_t* l_option = dap_chain_datum_voting_answer_tsd_create((char*)l_temp->data, strlen((char*)l_temp->data)); - if(!l_option){ - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - dap_chain_datum_tx_add_item(&l_tx, l_option); - DAP_DEL_Z(l_option); +// // Add options to tsd +// dap_list_t *l_temp = a_options; +// while(l_temp){ +// if(strlen((char*)l_temp->data) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH){ +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// dap_chain_tx_tsd_t* l_option = dap_chain_datum_voting_answer_tsd_create((char*)l_temp->data, strlen((char*)l_temp->data)); +// if(!l_option){ +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// dap_chain_datum_tx_add_item(&l_tx, l_option); +// DAP_DEL_Z(l_option); - l_temp = l_temp->next; - } +// l_temp = l_temp->next; +// } - // add voting expire time if needed - if(a_expire_vote != 0){ - dap_time_t l_expired_vote = a_expire_vote; - if (l_expired_vote < dap_time_now()){ - dap_chain_datum_tx_delete(l_tx); - return NULL; - } +// // add voting expire time if needed +// if(a_expire_vote != 0){ +// dap_time_t l_expired_vote = a_expire_vote; +// if (l_expired_vote < dap_time_now()){ +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } - dap_chain_tx_tsd_t* l_expired_item = dap_chain_datum_voting_expire_tsd_create(l_expired_vote); - if(!l_expired_item){ - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - dap_chain_datum_tx_add_item(&l_tx, l_expired_item); - DAP_DEL_Z(l_expired_item); - } +// dap_chain_tx_tsd_t* l_expired_item = dap_chain_datum_voting_expire_tsd_create(l_expired_vote); +// if(!l_expired_item){ +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// dap_chain_datum_tx_add_item(&l_tx, l_expired_item); +// DAP_DEL_Z(l_expired_item); +// } - // Add vote max count if needed - if (a_max_vote != 0) { - dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote); - if(!l_max_votes_item){ - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - dap_chain_datum_tx_add_item(&l_tx, l_max_votes_item); - DAP_DEL_Z(l_max_votes_item); - } +// // Add vote max count if needed +// if (a_max_vote != 0) { +// dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote); +// if(!l_max_votes_item){ +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// dap_chain_datum_tx_add_item(&l_tx, l_max_votes_item); +// DAP_DEL_Z(l_max_votes_item); +// } - if (a_delegated_key_required) { - dap_chain_tx_tsd_t* l_delegated_key_req_item = dap_chain_datum_voting_delegated_key_required_tsd_create(true); - if(!l_delegated_key_req_item){ - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - dap_chain_datum_tx_add_item(&l_tx, l_delegated_key_req_item); - DAP_DEL_Z(l_delegated_key_req_item); - } +// if (a_delegated_key_required) { +// dap_chain_tx_tsd_t* l_delegated_key_req_item = dap_chain_datum_voting_delegated_key_required_tsd_create(true); +// if(!l_delegated_key_req_item){ +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// dap_chain_datum_tx_add_item(&l_tx, l_delegated_key_req_item); +// DAP_DEL_Z(l_delegated_key_req_item); +// } - if(a_vote_changing_allowed){ - dap_chain_tx_tsd_t* l_vote_changing_item = dap_chain_datum_voting_vote_changing_allowed_tsd_create(true); - if(!l_vote_changing_item){ - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item); - DAP_DEL_Z(l_vote_changing_item); - } - if (a_token_ticker) { - dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker); - if (!l_voting_token_item) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item); - DAP_DEL_Z(l_voting_token_item); - } +// if(a_vote_changing_allowed){ +// dap_chain_tx_tsd_t* l_vote_changing_item = dap_chain_datum_voting_vote_changing_allowed_tsd_create(true); +// if(!l_vote_changing_item){ +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item); +// DAP_DEL_Z(l_vote_changing_item); +// } +// if (a_token_ticker) { +// dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker); +// if (!l_voting_token_item) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item); +// DAP_DEL_Z(l_voting_token_item); +// } - // add 'in' items - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); - assert(EQUAL_256(l_value_to_items, l_value_transfer)); - dap_list_free_full(l_list_used_out, NULL); - uint256_t l_value_pack = {}; - // Network fee - if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) - SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); - else { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - // Validator's fee - if (!IS_ZERO_256(a_fee)) { - if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1) - SUM_256_256(l_value_pack, a_fee, &l_value_pack); - else { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } - // coin back - uint256_t l_value_back; - SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); - if(!IS_ZERO_256(l_value_back)) { - if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) { - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } +// // add 'in' items +// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); +// assert(EQUAL_256(l_value_to_items, l_value_transfer)); +// dap_list_free_full(l_list_used_out, NULL); +// uint256_t l_value_pack = {}; +// // Network fee +// if (l_net_fee_used) { +// if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) +// SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); +// else { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// // Validator's fee +// if (!IS_ZERO_256(a_fee)) { +// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1) +// SUM_256_256(l_value_pack, a_fee, &l_value_pack); +// else { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } +// // coin back +// uint256_t l_value_back; +// SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); +// if(!IS_ZERO_256(l_value_back)) { +// if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return NULL; +// } +// } - return l_tx; -} +// return l_tx; +// } /** int dap_cli_vote_compose(int a_argc, char **a_argv){ @@ -3024,7 +3064,7 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port) { - json_object* l_json_obj_ret = json_object_new_object(); + compose_config_t* l_config = s_compose_config_init(a_net_str, a_url_str, a_port); dap_hash_fast_t l_tx_hash = {}; if (a_tx_hash_str) { dap_chain_hash_fast_from_str(a_tx_hash_str, &l_tx_hash); @@ -3033,27 +3073,26 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c if (a_cert_str) { dap_cert_t *l_cert = dap_cert_find_by_name(a_cert_str); if (!l_cert) { - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND, "Specified certificate not found"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND, "Specified certificate not found"); + return s_compose_config_return_response_handler(l_config); } if (!l_cert->enc_key->priv_key_data || l_cert->enc_key->priv_key_data_size == 0) { - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING, "Private key missing in certificate"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING, "Private key missing in certificate"); + return s_compose_config_return_response_handler(l_config); } if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, s_get_net_id(a_net_str))) { - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_WRONG_CERT, "Wrong certificate"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_WRONG_CERT, "Wrong certificate"); + return s_compose_config_return_response_handler(l_config); } } const char *l_addr_str = dap_chain_addr_to_str_static(&l_signing_addr); char data[512]; snprintf(data, sizeof(data), - "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); - json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); + "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", l_config->net_name); + json_object *l_json_coins = dap_request_command_to_rpc(data, l_config); if (!l_json_coins) { - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger"); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } int items_count = json_object_array_length(l_json_coins); @@ -3065,8 +3104,8 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash")); if (dap_chain_hash_fast_from_str(tx_hash_str, &l_tx_hash)) { json_object_put(l_json_coins); - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format"); + return s_compose_config_return_response_handler(l_config); } found = true; break; @@ -3074,8 +3113,8 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c } json_object_put(l_json_coins); if (!found) { - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED, "Specified certificate/pkey hash is not delegated"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED, "Specified certificate/pkey hash is not delegated"); + return s_compose_config_return_response_handler(l_config); } } @@ -3083,11 +3122,10 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c char data[512]; snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, a_net_str); - json_object *l_json_response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_config->net_name); + json_object *l_json_response = dap_request_command_to_rpc(data, l_config); if (!l_json_response) { - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger"); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } json_object *l_json_items = json_object_array_get_idx(l_json_response, 0); @@ -3110,8 +3148,8 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c if (!has_delegate_out) { json_object_put(l_json_response); - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT, "No delegate output found in transaction"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT, "No delegate output found in transaction"); + return s_compose_config_return_response_handler(l_config); } json_object *l_json_spents = json_object_object_get(l_json_response, "Spent OUTs"); @@ -3123,17 +3161,17 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c if (spent_by_tx) { if (dap_chain_hash_fast_from_str(spent_by_tx, &l_tx_hash)) { json_object_put(l_json_response); - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH, "Invalid transaction hash format"); + return s_compose_config_return_response_handler(l_config); } l_tx_hash_str_tmp = dap_hash_fast_to_str_static(&l_tx_hash); snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, a_net_str); - json_object *l_json_prev_tx = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); + "{\"method\": \"ledger\",\"params\": [\"ledger;tx;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", l_tx_hash_str_tmp, l_config->net_name); + json_object *l_json_prev_tx = dap_request_command_to_rpc(data, l_config); if (!l_json_prev_tx) { json_object_put(l_json_response); - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND, "Previous transaction not found"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND, "Previous transaction not found"); + return s_compose_config_return_response_handler(l_config); } json_object_put(l_json_prev_tx); break; @@ -3145,11 +3183,10 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c if (a_tx_hash_str) { char data[512]; snprintf(data, sizeof(data), - "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", a_net_str); - json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); + "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;tx;-net;%s\"],\"id\": \"1\"}", l_config->net_name); + json_object *l_json_coins = dap_request_command_to_rpc(data, l_config); if (!l_json_coins) { - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR, "Failed to retrieve coins from ledger"); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } bool tx_exists = false; @@ -3159,8 +3196,8 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c const char *tx_hash = json_object_get_string(json_object_object_get(tx_item, "tx_hash")); if (tx_hash && strcmp(tx_hash, l_tx_hash_str_tmp) == 0) { json_object_put(l_json_coins); - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_TX_EXISTS, "Transaction already exists"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_TX_EXISTS, "Transaction already exists"); + return s_compose_config_return_response_handler(l_config); } } json_object_put(l_json_coins); @@ -3169,40 +3206,40 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path,NULL); if (!l_wallet) { - dap_json_compose_error_add(l_json_obj_ret, DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND, "Specified wallet not found"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND, "Specified wallet not found"); + return s_compose_config_return_response_handler(l_config); } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); - dap_chain_datum_tx_t *l_tx = dap_stake_tx_invalidate_compose(a_net_str, &l_tx_hash, a_fee, l_enc_key, a_url_str, a_port, l_json_obj_ret); + dap_chain_datum_tx_t *l_tx = dap_stake_tx_invalidate_compose(&l_tx_hash, a_fee, l_enc_key, l_config); if (l_tx) { - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + dap_chain_net_tx_to_json(l_tx, l_config->response_handler); DAP_DELETE(l_tx); } dap_chain_wallet_close(l_wallet); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } -dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, json_object *a_error_handler) +dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, compose_config_t *a_config) { - if(!a_net_str || !*a_net_str || !a_tx_hash || !a_key || !l_url_str || !*l_url_str || l_port == 0) + if(!a_config || !a_config->net_name || !*a_config->net_name || !a_tx_hash || !a_key || !a_config->url_str || !*a_config->url_str || a_config->port == 0) return NULL; char data[512]; snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;info;-need_sign;-hash;%s;-net;%s\"],\"id\": \"1\"}", - dap_hash_fast_to_str_static(a_tx_hash), a_net_str); + dap_hash_fast_to_str_static(a_tx_hash), a_config->net_name); - json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + json_object *response = dap_request_command_to_rpc(data, a_config); if (!response) { - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR, "Failed to get ledger info"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR, "Failed to get ledger info"); return NULL; } json_object *l_items_array = json_object_array_get_idx(response, 0); l_items_array = json_object_object_get(l_items_array, "ITEMS"); if (!l_items_array) { json_object_put(response); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND, "Items not found in ledger response"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND, "Items not found in ledger response"); return NULL; } @@ -3211,7 +3248,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap const char *all_unspent = json_object_get_string(l_unspent_outs); if (all_unspent && strcmp(all_unspent, "yes") == 0) { json_object_put(response); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT, "All outputs are already spent"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT, "All outputs are already spent"); return NULL; } } @@ -3234,19 +3271,19 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!l_tx_prev_hash) { json_object_put(response); DAP_DELETE(l_tx_out_cond); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND, "Previous transaction hash not found"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND, "Previous transaction hash not found"); return NULL; } l_prev_cond_idx = json_object_get_int(json_object_object_get(l_item, "Tx_out_prev_idx")); snprintf(data, sizeof(data), "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", - l_tx_prev_hash, a_net_str); + l_tx_prev_hash, a_config->net_name); - json_object *response_cond = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); + json_object *response_cond = dap_request_command_to_rpc(data, a_config); if (!response_cond) { json_object_put(response); DAP_DELETE(l_tx_out_cond); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR, "Failed to get conditional transaction info"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR, "Failed to get conditional transaction info"); return NULL; } json_object_put(response_cond); @@ -3256,7 +3293,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!l_tx_out_cond || !l_tx_prev_hash) { json_object_put(response); DAP_DELETE(l_tx_out_cond); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND, "Conditional transaction not found"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND, "Conditional transaction not found"); return NULL; } @@ -3273,7 +3310,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!l_sig_item) { json_object_put(response); DAP_DELETE(l_tx_out_cond); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND, "Signature item not found"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND, "Signature item not found"); return NULL; } @@ -3281,7 +3318,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap if (!l_sign_b64_str) { json_object_put(response); DAP_DELETE(l_tx_out_cond); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR, "Failed to decode signature"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR, "Failed to decode signature"); return NULL; } @@ -3297,18 +3334,18 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); dap_chain_addr_t l_owner_addr; - dap_chain_addr_fill_from_sign(&l_owner_addr, l_sign, s_get_net_id(a_net_str)); + dap_chain_addr_fill_from_sign(&l_owner_addr, l_sign, s_get_net_id(a_config->net_name)); dap_chain_addr_t l_wallet_addr; - dap_chain_addr_fill_from_key(&l_wallet_addr, a_key, s_get_net_id(a_net_str)); + dap_chain_addr_fill_from_key(&l_wallet_addr, a_key, s_get_net_id(a_config->net_name)); if (!dap_chain_addr_compare(&l_owner_addr, &l_wallet_addr)) { json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER, "Wrong transaction owner"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER, "Wrong transaction owner"); return NULL; } - const char *l_native_ticker = s_get_native_ticker(a_net_str); + const char *l_native_ticker = s_get_native_ticker(a_config->net_name); json_object *l_json_tiker = json_object_array_get_idx(response, 0); json_object *token_ticker_obj = json_object_object_get(l_json_tiker, "Token_ticker"); @@ -3318,18 +3355,18 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND, "Token ticker not found"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND, "Token ticker not found"); return NULL; } } const char *l_delegated_ticker = json_object_get_string(token_ticker_obj); - json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); + json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, &l_owner_addr, a_config); if (!l_outs_native) { json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND, "Transaction outputs not found"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND, "Transaction outputs not found"); return NULL; } @@ -3338,7 +3375,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap // list of transaction with 'out' items to sell uint256_t l_net_fee, l_fee_total = a_fee; dap_chain_addr_t*l_net_fee_addr = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_net_fee_addr, l_url_str, l_port); + bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_net_fee_addr, a_config); if (l_net_fee_used) SUM_256_256(l_fee_total, l_net_fee, &l_fee_total); dap_list_t *l_list_fee_out = NULL; @@ -3350,7 +3387,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS, "Not enough funds to pay fees"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS, "Not enough funds to pay fees"); return NULL; } @@ -3369,7 +3406,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR, "Error adding input items"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR, "Error adding input items"); return NULL; } @@ -3380,7 +3417,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR, "Error adding output items"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR, "Error adding output items"); return NULL; } // add fee items @@ -3391,7 +3428,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR, "Error adding network fee"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR, "Error adding network fee"); return NULL; } } @@ -3402,7 +3439,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR, "Error adding fee"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR, "Error adding fee"); return NULL; } } @@ -3416,7 +3453,7 @@ dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap json_object_put(response); DAP_DELETE(l_tx_out_cond); DAP_DELETE(l_tx_sig); - if (a_error_handler) dap_json_compose_error_add(a_error_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR, "Error adding fee back"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR, "Error adding fee back"); return NULL; } } @@ -3486,44 +3523,43 @@ dap_chain_net_srv_order_t* dap_check_remote_srv_order(const char* l_net_str, con return l_order; } -dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_net_str, const char* l_order_hash_str, uint256_t* a_tax, +dap_chain_net_srv_order_t* dap_get_remote_srv_order(const char* l_order_hash_str, uint256_t* a_tax, uint256_t* a_value_max, dap_chain_addr_t* a_sovereign_addr, uint256_t* a_sovereign_tax, - const char* l_url_str, uint16_t l_port){ + compose_config_t *a_config){ char data[512]; snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;staker;-net;%s\"],\"id\": \"1\"}", - l_net_str); - json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + a_config->net_name); + json_object *response = dap_request_command_to_rpc(data, a_config); if (!response) { printf("Error: Failed to get response from remote node\n"); return NULL; } - dap_chain_net_srv_order_t *l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response); + dap_chain_net_srv_order_t *l_order = dap_check_remote_srv_order(a_config->net_name, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response); json_object_put(response); if (!l_order) { snprintf(data, sizeof(data), "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;order;list;validator;-net;%s\"],\"id\": \"1\"}", - l_net_str); - response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + a_config->net_name); + response = dap_request_command_to_rpc(data, a_config); if (!response) { printf("Error: Failed to get response from remote node\n"); return NULL; } - l_order = dap_check_remote_srv_order(l_net_str, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response); + l_order = dap_check_remote_srv_order(a_config->net_name, l_order_hash_str, a_tax, a_value_max, a_sovereign_addr, a_sovereign_tax, response); json_object_put(response); } return l_order; } -dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_order_hash_str, - const char* l_url_str, uint16_t l_port){ +dap_sign_t* dap_get_remote_srv_order_sign(const char* l_order_hash_str, compose_config_t *a_config){ char data[512]; snprintf(data, sizeof(data), "{\"method\": \"net_srv\",\"params\": [\"net_srv;-net;%s;order;dump;-hash;%s;-need_sign\"],\"id\": \"1\"}", - l_net_str, l_order_hash_str); - json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); + a_config->net_name, l_order_hash_str); + json_object *response = dap_request_command_to_rpc(data, a_config); if (!response) { printf("Error: Failed to get response from remote node\n"); return NULL; @@ -3565,11 +3601,11 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_net_str, const char* l_o json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path) { - json_object* l_json_obj_ret = json_object_new_object(); + compose_config_t *l_config = s_compose_config_init(a_net_str, a_url_str, a_port); dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallets_path, NULL); if (!l_wallet) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND, "Specified wallet not found"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND, "Specified wallet not found"); + return l_config->response_handler; } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); dap_chain_wallet_close(l_wallet); @@ -3579,9 +3615,9 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha if (a_value_str) { l_value = dap_chain_balance_scan(a_value_str); if (IS_ZERO_256(l_value)) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-value' param"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-value' param"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } } dap_pkey_t *l_pkey = NULL; @@ -3589,39 +3625,39 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha if (a_cert_str) { dap_cert_t *l_signing_cert = dap_cert_find_by_name(a_cert_str); if (!l_signing_cert) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND, "Specified certificate not found"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND, "Specified certificate not found"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, s_get_net_id(a_net_str))) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG, "Specified certificate is wrong"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG, "Specified certificate is wrong"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } l_pkey = dap_pkey_from_enc_key(l_signing_cert->enc_key); } else if (a_pkey_full_str) { dap_sign_type_t l_type = dap_sign_type_from_str(a_sign_type_str); if (l_type.type == SIG_TYPE_NULL) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE, "Wrong sign type"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE, "Wrong sign type"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } l_pkey = dap_pkey_get_from_str(a_pkey_full_str); if (!l_pkey) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey string format, can't get pkey_full"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey string format, can't get pkey_full"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } if (l_pkey->header.type.type != dap_pkey_type_from_sign_type(l_type).type) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "pkey and sign types is different"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "pkey and sign types is different"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } dap_chain_hash_fast_t l_hash_public_key = {0}; if (!dap_pkey_get_hash(l_pkey, &l_hash_public_key)) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey hash format"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY, "Invalid pkey hash format"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } dap_chain_addr_fill(&l_signing_addr, l_type, &l_hash_public_key, s_get_net_id(a_net_str)); } @@ -3629,34 +3665,34 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha dap_chain_node_addr_t l_node_addr = g_node_addr; if (a_node_addr_str) { if (dap_chain_node_addr_from_str(&l_node_addr, a_node_addr_str)) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Unrecognized node addr %s", a_node_addr_str); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Unrecognized node addr %s", a_node_addr_str); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } } if (a_order_hash_str) { uint256_t l_tax; uint256_t l_value_max; int l_prev_tx_count = 0; - dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(a_net_str, a_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, a_url_str, a_port); + dap_chain_net_srv_order_t* l_order = dap_get_remote_srv_order(a_order_hash_str, &l_tax, &l_value_max, &l_sovereign_addr, &l_sovereign_tax, l_config); if (!l_order) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND, "Error: Failed to get order from remote node"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND, "Error: Failed to get order from remote node"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } l_sovereign_tax = l_tax; if (l_order->direction == SERV_DIR_BUY) { // Staker order if (!a_cert_str) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED, "Command 'delegate' requires parameter -cert with this order type"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED, "Command 'delegate' requires parameter -cert with this order type"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } if (l_order->ext_size != 0) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Specified order has invalid size"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Specified order has invalid size"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } dap_chain_tx_out_cond_t *l_cond_tx = NULL; @@ -3665,16 +3701,16 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", dap_chain_hash_fast_to_str_static(&l_order->tx_cond_hash), a_net_str); - json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); + json_object *response = dap_request_command_to_rpc(data, l_config); if (!response) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE, "Error: Failed to get response from remote node"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE, "Error: Failed to get response from remote node"); + return s_compose_config_return_response_handler(l_config); } json_object *items = json_object_object_get(response, "ITEMS"); if (!items) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS, "Error: No items found in response"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS, "Error: No items found in response"); + return s_compose_config_return_response_handler(l_config); } int items_count = json_object_array_length(items); for (int i = 0; i < items_count; i++) { @@ -3691,8 +3727,8 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr = *dap_chain_addr_from_str(json_object_get_string(json_object_object_get(item, "signing_addr"))); if (dap_chain_node_addr_from_str(&l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr, json_object_get_string(json_object_object_get(item, "signer_node_addr"))) != 0) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR, "Error: Failed to parse signer node address"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR, "Error: Failed to parse signer node address"); + return s_compose_config_return_response_handler(l_config); } l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); l_prev_tx_count++; @@ -3703,60 +3739,60 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha } } if (!l_cond_tx) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Error: No transaction output condition found"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR, "Error: No transaction output condition found"); + return s_compose_config_return_response_handler(l_config); } json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); const char *spent_outs_value = json_object_get_string(spent_outs); if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Error: Transaction output item already used"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE, "Error: Transaction output item already used"); + return s_compose_config_return_response_handler(l_config); } char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, s_get_native_ticker(a_net_str)); const char *l_token_ticker = json_object_get_string(json_object_object_get(response, "token_ticker")); if (!l_token_ticker) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER, "Error: Token ticker not found in response"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER, "Error: Token ticker not found in response"); + return s_compose_config_return_response_handler(l_config); } json_object_put(response); if (dap_strcmp(l_token_ticker, l_delegated_ticker)) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER, "Requested conditional transaction have another ticker (not %s)", l_delegated_ticker); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER, "Requested conditional transaction have another ticker (not %s)", l_delegated_ticker); + return s_compose_config_return_response_handler(l_config); } if (l_cond_tx->tsd_size != dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, 0)) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT, "The order's conditional transaction has invalid format"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT, "The order's conditional transaction has invalid format"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } if (compare256(l_cond_tx->header.value, l_order->price)) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE, "The order's conditional transaction has different value"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE, "The order's conditional transaction has different value"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } if (!dap_chain_addr_is_blank(&l_cond_tx->subtype.srv_stake_pos_delegate.signing_addr) || l_cond_tx->subtype.srv_stake_pos_delegate.signer_node_addr.uint64) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR, "The order's conditional transaction gas not blank address or key"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR, "The order's conditional transaction gas not blank address or key"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } l_value = l_order->price; } else { if (!a_value_str) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED, "Command 'delegate' requires parameter -value with this order type"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED, "Command 'delegate' requires parameter -value with this order type"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } if (a_sovereign_addr_str) { dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(a_sovereign_addr_str); if (!l_spec_addr) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR, "Specified address is invalid"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR, "Specified address is invalid"); + return s_compose_config_return_response_handler(l_config); } l_sovereign_addr = *l_spec_addr; DAP_DELETE(l_spec_addr); @@ -3766,52 +3802,52 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha if (a_order_hash_str && compare256(l_value, l_order->price) == -1) { const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_order->price, &l_coin_min_str); - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW, "Number in '-value' param %s is lower than order minimum allowed value %s(%s)", + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW, "Number in '-value' param %s is lower than order minimum allowed value %s(%s)", a_value_str, l_coin_min_str, l_value_min_str); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } if (a_order_hash_str && compare256(l_value, l_value_max) == 1) { const char *l_coin_max_str, *l_value_max_str = dap_uint256_to_char(l_value_max, &l_coin_max_str); - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH, "Number in '-value' param %s is higher than order minimum allowed value %s(%s)", + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH, "Number in '-value' param %s is higher than order minimum allowed value %s(%s)", a_value_str, l_coin_max_str, l_value_max_str); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } size_t l_sign_size = 0; - dap_sign_t *l_sign = dap_get_remote_srv_order_sign(a_net_str, a_order_hash_str, a_url_str, a_port); + dap_sign_t *l_sign = dap_get_remote_srv_order_sign(a_order_hash_str, l_config); if (!l_sign) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER, "Specified order is unsigned"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER, "Specified order is unsigned"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, s_get_net_id(a_net_str)); l_pkey = dap_pkey_get_from_sign(l_sign); char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX]; dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, s_get_native_ticker(a_net_str)); if (dap_strcmp(l_order->price_ticker, l_delegated_ticker_str)) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER, "Specified order is invalid"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER, "Specified order is invalid"); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_order); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } l_node_addr = l_order->node_addr; } DAP_DELETE(l_order); if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 || compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); } if (!l_pkey) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED, "pkey not defined"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED, "pkey not defined"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } // TODO: need to make sure that the key and node are required verification @@ -3823,73 +3859,70 @@ json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const cha // } - uint256_t l_allowed_min = s_get_key_delegating_min_value(a_net_str, a_url_str, a_port); + uint256_t l_allowed_min = s_get_key_delegating_min_value(l_config); if (compare256(l_value, l_allowed_min) == -1) { const char *l_coin_min_str, *l_value_min_str = dap_uint256_to_char(l_allowed_min, &l_coin_min_str); - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN, "Number in '-value' param %s is lower than minimum allowed value %s(%s)", + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN, "Number in '-value' param %s is lower than minimum allowed value %s(%s)", a_value_str, l_coin_min_str, l_value_min_str); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } uint256_t l_fee = dap_chain_balance_scan(a_fee_str); if (IS_ZERO_256(l_fee)) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-fee' param"); + dap_json_compose_error_add(l_config->response_handler, STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE, "Unrecognized number in '-fee' param"); dap_enc_key_delete(l_enc_key); - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } - dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(a_net_str, l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr, - a_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, a_url_str, a_port, l_json_obj_ret); + dap_chain_datum_tx_t *l_tx = dap_stake_tx_create_compose(l_enc_key, l_value, l_fee, &l_signing_addr, &l_node_addr, + a_order_hash_str ? &l_sovereign_addr : NULL, l_sovereign_tax, l_prev_tx, l_pkey, l_config); dap_enc_key_delete(l_enc_key); DAP_DELETE(l_pkey); if (l_tx) { - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + dap_chain_net_tx_to_json(l_tx, l_config->response_handler); DAP_DELETE(l_tx); - } + } - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } -dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, +dap_chain_datum_tx_t *dap_stake_tx_create_compose(dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, - dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, json_object *l_error_handle) + dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, compose_config_t *a_config) { - if (!a_net_str || !a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS, "Invalid parameters for transaction creation"); + if (!a_key || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) { + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS, "Invalid parameters for transaction creation"); return NULL; } - const char *l_native_ticker = s_get_native_ticker(a_net_str); + const char *l_native_ticker = s_get_native_ticker(a_config->net_name); char l_delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker, l_native_ticker); uint256_t l_value_transfer = {}, l_fee_transfer = {}; // list of transaction with 'out' items to sell dap_chain_addr_t l_owner_addr; - dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_net_str)); + dap_chain_addr_fill_from_key(&l_owner_addr, a_key, s_get_net_id(a_config->net_name)); uint256_t l_net_fee, l_fee_total = a_fee; dap_chain_addr_t * l_net_fee_addr = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_net_fee_addr, l_url_str, l_port); + bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_net_fee_addr, a_config); if (l_net_fee_used) SUM_256_256(l_fee_total, l_net_fee, &l_fee_total); dap_list_t *l_list_fee_out = NULL; - json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); + json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, &l_owner_addr, a_config); if (!l_outs_native) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee"); return NULL; } - json_object *l_outs_delegated = dap_get_remote_tx_outs(l_delegated_ticker, a_net_str, &l_owner_addr, l_url_str, l_port); + json_object *l_outs_delegated = dap_get_remote_tx_outs(l_delegated_ticker, &l_owner_addr, a_config); if (!l_outs_delegated) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value"); return NULL; } @@ -3902,8 +3935,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en if (!l_list_fee_out) { json_object_put(l_outs_native); json_object_put(l_outs_delegated); - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE, "Not enough funds to pay fee"); return NULL; } @@ -3917,16 +3949,14 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en if (!l_list_used_out) { json_object_put(l_outs_native); json_object_put(l_outs_delegated); - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE, "Not enough funds for value"); return NULL; } // add 'in' items to pay for delegate uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); dap_list_free_full(l_list_used_out, NULL); if (!EQUAL_256(l_value_to_items, l_value_transfer)) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input"); goto tx_fail; } } else { @@ -3936,8 +3966,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en dap_chain_datum_tx_out_cond_get(a_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_out_num); // add 'in' item to buy from conditional transaction if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &l_prev_tx_hash, l_out_num, -1)) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input"); goto tx_fail; } } @@ -3945,8 +3974,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); dap_list_free_full(l_list_fee_out, NULL); if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR, "Error creating transaction input"); goto tx_fail; } @@ -3956,8 +3984,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en a_sovereign_addr, a_sovereign_tax, a_pkey); if (!l_tx_out) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR, "Error creating conditional transaction output"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR, "Error creating conditional transaction output"); goto tx_fail; } dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); @@ -3968,8 +3995,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back); if (!IS_ZERO_256(l_value_back)) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_value_back, l_delegated_ticker) != 1) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR, "Error creating transaction output"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR, "Error creating transaction output"); goto tx_fail; } } @@ -3978,15 +4004,13 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en // add fee items if (l_net_fee_used) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) != 1) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR, "Error with network fee"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR, "Error with network fee"); goto tx_fail; } } if (!IS_ZERO_256(a_fee)) { if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR, "Error with validator fee"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR, "Error with validator fee"); goto tx_fail; } } @@ -3995,8 +4019,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_en SUBTRACT_256_256(l_fee_transfer, l_fee_total, &l_fee_back); if (!IS_ZERO_256(l_fee_back)) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_owner_addr, l_fee_back, l_native_ticker) != 1) { - if (l_error_handle) - dap_json_compose_error_add(l_error_handle, DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR, "Error with fee back"); + dap_json_compose_error_add(a_config->response_handler, DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR, "Error with fee back"); goto tx_fail; } } @@ -4008,41 +4031,46 @@ tx_fail: return NULL; } -static dap_chain_datum_tx_t *dap_order_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, +static dap_chain_datum_tx_t *dap_order_tx_create_compose(dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, uint256_t a_sovereign_tax, dap_chain_addr_t *a_sovereign_addr, - const char *l_url_str, int l_port, json_object *l_error_handle) + compose_config_t *a_config) { dap_chain_node_addr_t l_node_addr = {}; - return dap_stake_tx_create_compose(a_net_str, a_key, a_value, a_fee, + return dap_stake_tx_create_compose(a_key, a_value, a_fee, (dap_chain_addr_t *)&c_dap_chain_addr_blank, &l_node_addr, - a_sovereign_addr, a_sovereign_tax, NULL, NULL, l_url_str, l_port, l_error_handle); + a_sovereign_addr, a_sovereign_tax, NULL, NULL, a_config); } json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) { - json_object* l_json_obj_ret = json_object_new_object(); + compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port); + if (!l_config) { + json_object *l_json_obj_ret = json_object_new_object(); + dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_PARAMS, "Invalid arguments"); + return l_json_obj_ret; + } uint256_t l_value = dap_chain_balance_scan(l_value_str); if (IS_ZERO_256(l_value)) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE, "Format -value <256 bit integer>"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE, "Format -value <256 bit integer>"); + return s_compose_config_return_response_handler(l_config); } uint256_t l_fee = dap_chain_balance_scan(l_fee_str); if (IS_ZERO_256(l_fee)) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE, "Format -fee <256 bit integer>"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE, "Format -fee <256 bit integer>"); + return s_compose_config_return_response_handler(l_config); } uint256_t l_tax = dap_chain_coins_to_balance(l_tax_str); if (compare256(l_tax, dap_chain_coins_to_balance("100.0")) == 1 || compare256(l_tax, GET_256_FROM_64(100)) == -1) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX, "Tax must be lower or equal than 100%% and higher or equal than 1.0e-16%%"); + return s_compose_config_return_response_handler(l_config); } dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); if (!l_wallet) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND, "Specified wallet not found"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND, "Specified wallet not found"); + return s_compose_config_return_response_handler(l_config); } const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet); @@ -4050,505 +4078,504 @@ json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str dap_chain_wallet_close(l_wallet); if (!l_enc_key) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND, "Failed to retrieve encryption key"); - return l_json_obj_ret; + dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND, "Failed to retrieve encryption key"); + return s_compose_config_return_response_handler(l_config); } dap_chain_addr_t l_addr = {}; if (l_addr_str) { dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str); if (!l_spec_addr) { - dap_json_compose_error_add(l_json_obj_ret, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR, "Specified address is invalid"); + dap_json_compose_error_add(l_config->response_handler, STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR, "Specified address is invalid"); DAP_DELETE(l_enc_key); - return NULL; + return s_compose_config_return_response_handler(l_config); } l_addr = *l_spec_addr; DAP_DELETE(l_spec_addr); } else dap_chain_addr_fill_from_key(&l_addr, l_enc_key, s_get_net_id(l_net_str)); DIV_256(l_tax, GET_256_FROM_64(100), &l_tax); - dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_net_str, l_enc_key, l_value, l_fee, l_tax, - &l_addr, l_url_str, l_port, l_json_obj_ret); + dap_chain_datum_tx_t *l_tx = dap_order_tx_create_compose(l_enc_key, l_value, l_fee, l_tax, &l_addr, l_config); DAP_DEL_Z(l_enc_key); if (l_tx) { - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + dap_chain_net_tx_to_json(l_tx, l_config->response_handler); DAP_DELETE(l_tx); } - return l_json_obj_ret; + return s_compose_config_return_response_handler(l_config); } -int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) { - int l_arg_index = 1; - const char * l_order_hash_str = NULL; - const char * l_fee_str = NULL; - const char * l_net_str = NULL; - const char * l_wallet_str = NULL; - const char * l_url_str = NULL; - const char * l_port_str = NULL; - int l_port = 0; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); - if (!l_net_str) { - printf("Command 'order remove' requires parameter -net\n"); - return -1; - } +// int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) { +// int l_arg_index = 1; +// const char * l_order_hash_str = NULL; +// const char * l_fee_str = NULL; +// const char * l_net_str = NULL; +// const char * l_wallet_str = NULL; +// const char * l_url_str = NULL; +// const char * l_port_str = NULL; +// int l_port = 0; +// dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); +// if (!l_net_str) { +// printf("Command 'order remove' requires parameter -net\n"); +// return -1; +// } - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { - l_url_str = dap_compose_get_net_url(l_net_str); - } - if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { - l_port = dap_compose_get_net_port(l_net_str); - } else { - l_port = atoi(l_port_str); - } +// if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { +// l_url_str = dap_compose_get_net_url(l_net_str); +// } +// if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { +// l_port = dap_compose_get_net_port(l_net_str); +// } else { +// l_port = atoi(l_port_str); +// } - const char *l_wallet_path = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); - if (!l_wallet_path) { - l_wallet_path = - #ifdef DAP_OS_WINDOWS - dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); - #elif defined DAP_OS_MAC - dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); - #elif defined DAP_OS_UNIX - dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); - #endif - } - - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); - if (!l_wallet_str) { - printf("Command 'order remove' requires parameter -w\n"); - return -3; - } - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); - if (!l_wallet) { - printf("Specified wallet not found\n"); - return -4; - } - const char* l_sign_str = dap_chain_wallet_check_sign(l_wallet); - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str); - if (!l_order_hash_str) { - printf("Command 'order remove' requires parameter -order\n"); - return -5; - } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); - if (!l_fee_str) { - printf("Command 'order remove' requires parameter -fee\n"); - return -6; - } - uint256_t l_fee = dap_chain_balance_scan(l_fee_str); - dap_hash_fast_t l_tx_hash = {}; - dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash); - char *l_tx_hash_ret = NULL; - dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_remove_compose(l_net_str, &l_tx_hash, l_fee, l_wallet, l_url_str, l_port); - dap_chain_wallet_close(l_wallet); +// const char *l_wallet_path = NULL; +// dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); +// if (!l_wallet_path) { +// l_wallet_path = +// #ifdef DAP_OS_WINDOWS +// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); +// #elif defined DAP_OS_MAC +// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); +// #elif defined DAP_OS_UNIX +// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); +// #endif +// } + +// dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); +// if (!l_wallet_str) { +// printf("Command 'order remove' requires parameter -w\n"); +// return -3; +// } +// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); +// if (!l_wallet) { +// printf("Specified wallet not found\n"); +// return -4; +// } +// const char* l_sign_str = dap_chain_wallet_check_sign(l_wallet); +// dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str); +// if (!l_order_hash_str) { +// printf("Command 'order remove' requires parameter -order\n"); +// return -5; +// } +// dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); +// if (!l_fee_str) { +// printf("Command 'order remove' requires parameter -fee\n"); +// return -6; +// } +// uint256_t l_fee = dap_chain_balance_scan(l_fee_str); +// dap_hash_fast_t l_tx_hash = {}; +// dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash); +// char *l_tx_hash_ret = NULL; +// dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_remove_compose(l_net_str, &l_tx_hash, l_fee, l_wallet, l_url_str, l_port); +// dap_chain_wallet_close(l_wallet); - return 0; -} +// return 0; +// } -bool process_ledger_response(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, - dap_chain_hash_fast_t *a_tx_hash, const char *a_url_str, int a_port, dap_chain_hash_fast_t *a_out_hash) { - *a_out_hash = *a_tx_hash; - int l_prev_tx_count = 0; - dap_chain_hash_fast_t l_hash = {}; - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", - dap_chain_hash_fast_to_str_static(a_tx_hash), a_net_str); +// bool process_ledger_response(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, +// dap_chain_hash_fast_t *a_tx_hash, const char *a_url_str, int a_port, dap_chain_hash_fast_t *a_out_hash) { +// *a_out_hash = *a_tx_hash; +// int l_prev_tx_count = 0; +// dap_chain_hash_fast_t l_hash = {}; +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", +// dap_chain_hash_fast_to_str_static(a_tx_hash), a_net_str); - json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); - if (!response) { - printf("Error: Failed to get response from remote node\n"); - return false; - } +// json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); +// if (!response) { +// printf("Error: Failed to get response from remote node\n"); +// return false; +// } - json_object *l_response_array = json_object_array_get_idx(response, 0); - if (!l_response_array) { - printf("Error: Can't get the first element from the response array\n"); - json_object_put(response); - return false; - } +// json_object *l_response_array = json_object_array_get_idx(response, 0); +// if (!l_response_array) { +// printf("Error: Can't get the first element from the response array\n"); +// json_object_put(response); +// return false; +// } - json_object *items = json_object_object_get(l_response_array, "ITEMS"); - if (!items) { - printf("Error: No items found in response\n"); - return false; - } - bool l_found = false; - int items_count = json_object_array_length(items); - for (int i = 0; i < items_count; i++) { - json_object *item = json_object_array_get_idx(items, i); - const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); - if (dap_strcmp(item_type, "OUT COND") == 0) { - const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); - if (!dap_strcmp(subtype, dap_chain_tx_out_cond_subtype_to_str(a_cond_type))) { - dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(item, "hash")), &l_hash); - l_prev_tx_count++; - l_found = true; - break; - } - } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) { - l_prev_tx_count++; - } - } - if (!l_found) { - return false; - } - bool l_another_tx = false; - json_object *spent_outs = json_object_object_get(l_response_array, "Spent OUTs"); - if (spent_outs) { - int spent_outs_count = json_object_array_length(spent_outs); - for (int i = 0; i < spent_outs_count; i++) { - json_object *spent_out = json_object_array_get_idx(spent_outs, i); - int out_index = json_object_get_int(json_object_object_get(spent_out, "OUT - ")); - if (out_index == l_prev_tx_count) { - dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(spent_out, "is spent by tx")), &l_hash); - l_another_tx = true; - break; - } - } - } - if (l_another_tx) { - *a_out_hash = l_hash; - return true; - } - return false; -} +// json_object *items = json_object_object_get(l_response_array, "ITEMS"); +// if (!items) { +// printf("Error: No items found in response\n"); +// return false; +// } +// bool l_found = false; +// int items_count = json_object_array_length(items); +// for (int i = 0; i < items_count; i++) { +// json_object *item = json_object_array_get_idx(items, i); +// const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); +// if (dap_strcmp(item_type, "OUT COND") == 0) { +// const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); +// if (!dap_strcmp(subtype, dap_chain_tx_out_cond_subtype_to_str(a_cond_type))) { +// dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(item, "hash")), &l_hash); +// l_prev_tx_count++; +// l_found = true; +// break; +// } +// } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) { +// l_prev_tx_count++; +// } +// } +// if (!l_found) { +// return false; +// } +// bool l_another_tx = false; +// json_object *spent_outs = json_object_object_get(l_response_array, "Spent OUTs"); +// if (spent_outs) { +// int spent_outs_count = json_object_array_length(spent_outs); +// for (int i = 0; i < spent_outs_count; i++) { +// json_object *spent_out = json_object_array_get_idx(spent_outs, i); +// int out_index = json_object_get_int(json_object_object_get(spent_out, "OUT - ")); +// if (out_index == l_prev_tx_count) { +// dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(spent_out, "is spent by tx")), &l_hash); +// l_another_tx = true; +// break; +// } +// } +// } +// if (l_another_tx) { +// *a_out_hash = l_hash; +// return true; +// } +// return false; +// } -dap_chain_hash_fast_t dap_ledger_get_final_chain_tx_hash_compose(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash, bool a_unspent_only, const char *a_url_str, int a_port) -{ - dap_chain_hash_fast_t l_hash = { }; - if(!a_net_str || !a_tx_hash || dap_hash_fast_is_blank(a_tx_hash)) - return l_hash; - l_hash = *a_tx_hash; +// dap_chain_hash_fast_t dap_ledger_get_final_chain_tx_hash_compose(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash, bool a_unspent_only, const char *a_url_str, int a_port) +// { +// dap_chain_hash_fast_t l_hash = { }; +// if(!a_net_str || !a_tx_hash || dap_hash_fast_is_blank(a_tx_hash)) +// return l_hash; +// l_hash = *a_tx_hash; - while(process_ledger_response(a_net_str, a_cond_type, a_tx_hash, a_url_str, a_port, &l_hash)); +// while(process_ledger_response(a_net_str, a_cond_type, a_tx_hash, a_url_str, a_port, &l_hash)); - return l_hash; -} +// return l_hash; +// } -dap_chain_net_srv_xchange_price_t *dap_chain_net_srv_xchange_price_from_order_compose(const char *a_net_str, dap_chain_tx_out_cond_t *a_cond_tx, - dap_time_t a_ts_created, const char *a_token_ticker, dap_hash_fast_t *a_order_hash, - uint256_t *a_fee, bool a_ret_is_invalid, const char *a_url_str, int a_port) -{ - if (!a_net_str || !*a_net_str || !a_cond_tx || !a_token_ticker || !a_order_hash || !a_url_str || !*a_url_str || a_port == 0) - return NULL; - dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); - if (!l_price) - return NULL; - l_price->creation_date = a_ts_created; - dap_strncpy(l_price->token_buy, a_cond_tx->subtype.srv_xchange.buy_token, sizeof(l_price->token_buy) - 1); - - l_price->order_hash = *a_order_hash; - strncpy(l_price->token_sell, a_token_ticker, sizeof(l_price->token_sell) - 1); - - if (a_fee) - l_price->fee = *a_fee; - - l_price->datoshi_sell = a_cond_tx->header.value; - l_price->creator_addr = a_cond_tx->subtype.srv_xchange.seller_addr; - l_price->rate = a_cond_tx->subtype.srv_xchange.rate; - dap_chain_hash_fast_t l_final_hash = dap_ledger_get_final_chain_tx_hash_compose(a_net_str, - DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->order_hash, false, a_url_str, a_port); - if ( !dap_hash_fast_is_blank(&l_final_hash) ) { - l_price->tx_hash = l_final_hash; - return l_price; - } else { - printf( "This order have no active conditional transaction"); - if (a_ret_is_invalid) { - dap_hash_fast_t l_tx_hash_zero = {0}; - l_price->tx_hash = l_tx_hash_zero; - return l_price; - } - } +// dap_chain_net_srv_xchange_price_t *dap_chain_net_srv_xchange_price_from_order_compose(const char *a_net_str, dap_chain_tx_out_cond_t *a_cond_tx, +// dap_time_t a_ts_created, const char *a_token_ticker, dap_hash_fast_t *a_order_hash, +// uint256_t *a_fee, bool a_ret_is_invalid, const char *a_url_str, int a_port) +// { +// if (!a_net_str || !*a_net_str || !a_cond_tx || !a_token_ticker || !a_order_hash || !a_url_str || !*a_url_str || a_port == 0) +// return NULL; +// dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); +// if (!l_price) +// return NULL; +// l_price->creation_date = a_ts_created; +// dap_strncpy(l_price->token_buy, a_cond_tx->subtype.srv_xchange.buy_token, sizeof(l_price->token_buy) - 1); + +// l_price->order_hash = *a_order_hash; +// strncpy(l_price->token_sell, a_token_ticker, sizeof(l_price->token_sell) - 1); + +// if (a_fee) +// l_price->fee = *a_fee; + +// l_price->datoshi_sell = a_cond_tx->header.value; +// l_price->creator_addr = a_cond_tx->subtype.srv_xchange.seller_addr; +// l_price->rate = a_cond_tx->subtype.srv_xchange.rate; +// dap_chain_hash_fast_t l_final_hash = dap_ledger_get_final_chain_tx_hash_compose(a_net_str, +// DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->order_hash, false, a_url_str, a_port); +// if ( !dap_hash_fast_is_blank(&l_final_hash) ) { +// l_price->tx_hash = l_final_hash; +// return l_price; +// } else { +// printf( "This order have no active conditional transaction"); +// if (a_ret_is_invalid) { +// dap_hash_fast_t l_tx_hash_zero = {0}; +// l_price->tx_hash = l_tx_hash_zero; +// return l_price; +// } +// } - return NULL; -} +// return NULL; +// } -dap_chain_datum_tx_t* dap_xchange_tx_invalidate_compose(const char *a_net_str, dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) -{ - char * l_ret = NULL; +// dap_chain_datum_tx_t* dap_xchange_tx_invalidate_compose(const char *a_net_str, dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) +// { +// char * l_ret = NULL; - if (!a_price) { - printf("An a_price NULL argument was passed to the s_xchange_tx_invalidate() function."); - return NULL; - } - if (!a_wallet) { - printf("An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function."); - return NULL; - } - const char *l_native_ticker = s_get_native_ticker(a_net_str); +// if (!a_price) { +// printf("An a_price NULL argument was passed to the s_xchange_tx_invalidate() function."); +// return NULL; +// } +// if (!a_wallet) { +// printf("An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function."); +// return NULL; +// } +// const char *l_native_ticker = s_get_native_ticker(a_net_str); - dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str)); - dap_chain_addr_t l_seller_addr = *l_wallet_addr; - DAP_DELETE(l_wallet_addr); +// dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str)); +// dap_chain_addr_t l_seller_addr = *l_wallet_addr; +// DAP_DELETE(l_wallet_addr); - dap_chain_tx_out_cond_t *l_cond_tx = NULL; - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", - dap_chain_hash_fast_to_str_static(&a_price->tx_hash), a_net_str); +// dap_chain_tx_out_cond_t *l_cond_tx = NULL; +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", +// dap_chain_hash_fast_to_str_static(&a_price->tx_hash), a_net_str); - json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); - if (!response) { - printf("Error: Failed to get response from remote node\n"); - return NULL; - } +// json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); +// if (!response) { +// printf("Error: Failed to get response from remote node\n"); +// return NULL; +// } - json_object *l_response_array = json_object_array_get_idx(response, 0); - if (!l_response_array) { - printf("Error: Can't get the first element from the response array\n"); - json_object_put(response); - return NULL; - } - - json_object *items = json_object_object_get(l_response_array, "ITEMS"); - if (!items) { - printf("Error: No items found in response\n"); - return NULL; - } - int l_prev_cond_idx = 0; - int items_count = json_object_array_length(items); - for (int i = 0; i < items_count; i++) { - json_object *item = json_object_array_get_idx(items, i); - const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); - if (dap_strcmp(item_type, "OUT COND") == 0) { - const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); - if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { - l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); - l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; - l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); - l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; - l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); - l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); - strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); - l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; - l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); - l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); - break; - } else if (dap_strcmp(subtype, "OUT") == 0 || dap_strcmp(subtype, "OUT COND") == 0 || dap_strcmp(subtype, "OUT OLD") == 0) { - l_prev_cond_idx++; - } - } - } - if (!l_cond_tx) { - printf("Error: No transaction output condition found\n"); - return NULL; - } - - const char *l_tx_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); - if (!l_tx_ticker) { - printf("Error: Token_ticker not found in response\n"); - return NULL; - } +// json_object *l_response_array = json_object_array_get_idx(response, 0); +// if (!l_response_array) { +// printf("Error: Can't get the first element from the response array\n"); +// json_object_put(response); +// return NULL; +// } - bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker); +// json_object *items = json_object_object_get(l_response_array, "ITEMS"); +// if (!items) { +// printf("Error: No items found in response\n"); +// return NULL; +// } +// int l_prev_cond_idx = 0; +// int items_count = json_object_array_length(items); +// for (int i = 0; i < items_count; i++) { +// json_object *item = json_object_array_get_idx(items, i); +// const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); +// if (dap_strcmp(item_type, "OUT COND") == 0) { +// const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); +// if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { +// l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); +// l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; +// l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); +// l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; +// l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); +// l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); +// strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); +// l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; +// l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); +// l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); +// break; +// } else if (dap_strcmp(subtype, "OUT") == 0 || dap_strcmp(subtype, "OUT COND") == 0 || dap_strcmp(subtype, "OUT OLD") == 0) { +// l_prev_cond_idx++; +// } +// } +// } +// if (!l_cond_tx) { +// printf("Error: No transaction output condition found\n"); +// return NULL; +// } - json_object *spent_outs = json_object_object_get(l_response_array, "all OUTs yet unspent"); - const char *spent_outs_value = json_object_get_string(spent_outs); - if (spent_outs_value && !dap_strcmp(spent_outs_value, "yes")) { - printf("Error: Transaction output item already used\n"); - return NULL; - } +// const char *l_tx_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); +// if (!l_tx_ticker) { +// printf("Error: Token_ticker not found in response\n"); +// return NULL; +// } - if (!dap_chain_addr_compare(&l_seller_addr, &l_cond_tx->subtype.srv_xchange.seller_addr)) { - printf("Only owner can invalidate exchange transaction"); - return NULL; - } +// bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker); - // create empty transaction - dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - // add 'in' item to buy from conditional transaction - dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0); - uint256_t l_net_fee = {}; - dap_chain_addr_t* l_addr_fee = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port); - uint256_t l_total_fee = a_price->fee; - if (l_net_fee_used) - SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); +// json_object *spent_outs = json_object_object_get(l_response_array, "all OUTs yet unspent"); +// const char *spent_outs_value = json_object_get_string(spent_outs); +// if (spent_outs_value && !dap_strcmp(spent_outs_value, "yes")) { +// printf("Error: Transaction output item already used\n"); +// return NULL; +// } - if (!l_single_channel) { - json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_seller_addr, l_url_str, l_port); - if (!l_outs_native) { - return NULL; - } - int l_out_native_count = json_object_array_length(l_outs_native); - uint256_t l_transfer_fee = {}, l_fee_back = {}; - // list of transaction with 'out' items to get net fee - dap_list_t *l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, - l_total_fee, - &l_transfer_fee); - if (!l_list_fee_out) { - printf("Not enough funds to pay fee"); - json_object_put(l_outs_native); - return NULL; - } +// if (!dap_chain_addr_compare(&l_seller_addr, &l_cond_tx->subtype.srv_xchange.seller_addr)) { +// printf("Only owner can invalidate exchange transaction"); +// return NULL; +// } +// // create empty transaction +// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); +// // add 'in' item to buy from conditional transaction +// dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0); +// uint256_t l_net_fee = {}; +// dap_chain_addr_t* l_addr_fee = NULL; +// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port); +// uint256_t l_total_fee = a_price->fee; +// if (l_net_fee_used) +// SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); + +// if (!l_single_channel) { +// json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_seller_addr, l_url_str, l_port); +// if (!l_outs_native) { +// return NULL; +// } +// int l_out_native_count = json_object_array_length(l_outs_native); +// uint256_t l_transfer_fee = {}, l_fee_back = {}; +// // list of transaction with 'out' items to get net fee +// dap_list_t *l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, +// l_total_fee, +// &l_transfer_fee); +// if (!l_list_fee_out) { +// printf("Not enough funds to pay fee"); +// json_object_put(l_outs_native); +// return NULL; +// } - // add 'in' items to net fee - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); - dap_list_free_full(l_list_fee_out, NULL); - if (!EQUAL_256(l_value_to_items, l_transfer_fee)) { - dap_chain_datum_tx_delete(l_tx); - printf("Can't compose the transaction input"); - return NULL; - } - // return coins to owner - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_cond_tx->header.value, l_tx_ticker) == -1) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add returning coins output"); - return NULL; - } - // Network fee - if (l_net_fee_used && - dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add network fee output"); - return NULL; - } - // put fee coinback - SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back); - if (!IS_ZERO_256(l_fee_back) && - dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add fee cachback output"); - return NULL; - } - } else { - uint256_t l_coin_back = {}; - if (compare256(l_total_fee, l_cond_tx->header.value) >= 0) { - dap_chain_datum_tx_delete(l_tx); - printf("Total fee is greater or equal than order liquidity"); - return NULL; - } - SUBTRACT_256_256(l_cond_tx->header.value, l_total_fee, &l_coin_back); - // return coins to owner - if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add returning coins output"); - return NULL; - } - // Network fee - if (l_net_fee_used && - dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) != 1) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add network fee output"); - return NULL; - } - } - // Validator's fee - if (!IS_ZERO_256(a_price->fee)) { - if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) { - dap_chain_datum_tx_delete(l_tx); - printf("Cant add validator's fee output"); - return NULL; - } - } - // // add 'sign' items - // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); - // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) { - // dap_chain_datum_tx_delete(l_tx); - // dap_enc_key_delete(l_seller_key); - // log_it( L_ERROR, "Can't add sign output"); - // return false; - // } - // dap_enc_key_delete(l_seller_key); - // l_ret = s_xchange_tx_put(l_tx, a_price->net); - return l_tx; -} +// // add 'in' items to net fee +// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); +// dap_list_free_full(l_list_fee_out, NULL); +// if (!EQUAL_256(l_value_to_items, l_transfer_fee)) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Can't compose the transaction input"); +// return NULL; +// } +// // return coins to owner +// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_cond_tx->header.value, l_tx_ticker) == -1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add returning coins output"); +// return NULL; +// } +// // Network fee +// if (l_net_fee_used && +// dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add network fee output"); +// return NULL; +// } +// // put fee coinback +// SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back); +// if (!IS_ZERO_256(l_fee_back) && +// dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add fee cachback output"); +// return NULL; +// } +// } else { +// uint256_t l_coin_back = {}; +// if (compare256(l_total_fee, l_cond_tx->header.value) >= 0) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Total fee is greater or equal than order liquidity"); +// return NULL; +// } +// SUBTRACT_256_256(l_cond_tx->header.value, l_total_fee, &l_coin_back); +// // return coins to owner +// if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add returning coins output"); +// return NULL; +// } +// // Network fee +// if (l_net_fee_used && +// dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add network fee output"); +// return NULL; +// } +// } +// // Validator's fee +// if (!IS_ZERO_256(a_price->fee)) { +// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) { +// dap_chain_datum_tx_delete(l_tx); +// printf("Cant add validator's fee output"); +// return NULL; +// } +// } +// // // add 'sign' items +// // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); +// // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) { +// // dap_chain_datum_tx_delete(l_tx); +// // dap_enc_key_delete(l_seller_key); +// // log_it( L_ERROR, "Can't add sign output"); +// // return false; +// // } +// // dap_enc_key_delete(l_seller_key); +// // l_ret = s_xchange_tx_put(l_tx, a_price->net); + +// return l_tx; +// } -dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, - dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) { - if (!a_net_str || !a_hash_tx || !a_wallet) { - return NULL; - } - if(IS_ZERO_256(a_fee)){ - return NULL; - } +// dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, +// dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) { +// if (!a_net_str || !a_hash_tx || !a_wallet) { +// return NULL; +// } +// if(IS_ZERO_256(a_fee)){ +// return NULL; +// } - dap_time_t ts_created = 0; +// dap_time_t ts_created = 0; - dap_chain_tx_out_cond_t *l_cond_tx = NULL; - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", - dap_chain_hash_fast_to_str_static(a_hash_tx), a_net_str); +// dap_chain_tx_out_cond_t *l_cond_tx = NULL; +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", +// dap_chain_hash_fast_to_str_static(a_hash_tx), a_net_str); - json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); - if (!response) { - printf("Error: Failed to get response from remote node\n"); - return NULL; - } +// json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); +// if (!response) { +// printf("Error: Failed to get response from remote node\n"); +// return NULL; +// } - const char *items_str = json_object_get_string(response); - json_object *l_response_array = json_object_array_get_idx(response, 0); - if (!l_response_array) { - printf("Error: Can't get the first element from the response array\n"); - json_object_put(response); - return NULL; - } - json_object *items = json_object_object_get(l_response_array, "ITEMS"); - if (!items) { - printf("Error: No items found in response\n"); - return NULL; - } - int items_count = json_object_array_length(items); - for (int i = 0; i < items_count; i++) { - json_object *item = json_object_array_get_idx(items, i); - const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); - if (dap_strcmp(item_type, "OUT COND") == 0) { - const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); - if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { - l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); - l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; - l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); - l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; - l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); - l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); - strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); - l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; - l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); - l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); - break; - } - } - } - if (!l_cond_tx) { - printf("Error: No transaction output condition found\n"); - return NULL; - } - - const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); - if (!token_ticker) { - printf("Error: Token_ticker not found in response\n"); - return NULL; - } - const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created")); - if (ts_created_str) { - ts_created = dap_time_from_str_rfc822(ts_created_str); - } else { - printf("Error: TS_Created not found in response\n"); - return NULL; - } +// const char *items_str = json_object_get_string(response); +// json_object *l_response_array = json_object_array_get_idx(response, 0); +// if (!l_response_array) { +// printf("Error: Can't get the first element from the response array\n"); +// json_object_put(response); +// return NULL; +// } +// json_object *items = json_object_object_get(l_response_array, "ITEMS"); +// if (!items) { +// printf("Error: No items found in response\n"); +// return NULL; +// } +// int items_count = json_object_array_length(items); +// for (int i = 0; i < items_count; i++) { +// json_object *item = json_object_array_get_idx(items, i); +// const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); +// if (dap_strcmp(item_type, "OUT COND") == 0) { +// const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); +// if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { +// l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); +// l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; +// l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); +// l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; +// l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); +// l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); +// strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); +// l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; +// l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); +// l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); +// break; +// } +// } +// } +// if (!l_cond_tx) { +// printf("Error: No transaction output condition found\n"); +// return NULL; +// } - dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(a_net_str, l_cond_tx, ts_created, token_ticker, a_hash_tx, &a_fee, false, l_url_str, l_port); - if (!l_price) { - return NULL; - } - dap_chain_datum_tx_t *l_tx = dap_xchange_tx_invalidate_compose(a_net_str, l_price, a_wallet, l_url_str, l_port); - json_object * l_json_obj_ret = json_object_new_object(); - dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); - printf("%s", json_object_to_json_string(l_json_obj_ret)); - json_object_put(l_json_obj_ret); +// const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); +// if (!token_ticker) { +// printf("Error: Token_ticker not found in response\n"); +// return NULL; +// } +// const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created")); +// if (ts_created_str) { +// ts_created = dap_time_from_str_rfc822(ts_created_str); +// } else { +// printf("Error: TS_Created not found in response\n"); +// return NULL; +// } - DAP_DELETE(l_price); - return l_tx; -} +// dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(a_net_str, l_cond_tx, ts_created, token_ticker, a_hash_tx, &a_fee, false, l_url_str, l_port); +// if (!l_price) { +// return NULL; +// } +// dap_chain_datum_tx_t *l_tx = dap_xchange_tx_invalidate_compose(a_net_str, l_price, a_wallet, l_url_str, l_port); +// json_object * l_json_obj_ret = json_object_new_object(); +// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); +// printf("%s", json_object_to_json_string(l_json_obj_ret)); +// json_object_put(l_json_obj_ret); + +// DAP_DELETE(l_price); +// return l_tx; +// } // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value> diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 92d8bc19c1..8eca82a87f 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -43,6 +43,13 @@ typedef struct { uint16_t port; } NetInfo; +typedef struct { + const char *net_name; + const char *url_str; + uint16_t port; + json_object *response_handler; +} compose_config_t; + static NetInfo netinfo[NET_COUNT] = { {"riemann", "tKEL", {.uint64 = 0x000000000000dddd}, "45.76.140.191", 8081}, {"raiden", "tCELL", {.uint64 = 0x000000000000bbbb}, "http://rpc.cellframe.net", 8081}, @@ -53,13 +60,13 @@ static NetInfo netinfo[NET_COUNT] = { }; -const char* dap_compose_get_net_url(const char* name); -uint16_t dap_compose_get_net_port(const char* name); #ifdef __cplusplus extern "C" { #endif +const char* dap_compose_get_net_url(const char* name); +uint16_t dap_compose_get_net_port(const char* name); int dap_tx_create_compose(int argc, char ** argv); int dap_tx_create_xchange_compose(int argc, char ** argv); @@ -69,14 +76,15 @@ int dap_cli_take_compose(int a_argc, char **a_argv); int dap_cli_voting_compose(int a_argc, char **a_argv); typedef enum { STAKE_ORDER_CREATE_STAKER_OK = 0, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -1, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -2, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -3, - STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -4, - STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -5, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -6, - STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -7, - STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -8 + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_PARAMS = -1, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -2, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -3, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -4, + STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -5, + STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -6, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -7, + STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -8, + STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -9 } dap_cli_srv_stake_order_create_staker_error_t; json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port); @@ -155,11 +163,19 @@ typedef enum { DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28 } dap_cli_stake_invalidate_error_t; +dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, compose_config_t *a_config); json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port); -dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(const char *a_net_str, dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, const char *l_url_str, uint16_t l_port, json_object *a_error_handler); -json_object* dap_request_command_to_rpc(const char *request, const char * a_net_name, const char * a_url_str, uint16_t a_port); +typedef enum { + DAP_COMPOSE_ERROR_NONE = 0, + DAP_COMPOSE_ERROR_RESPONSE_NULL = -1, + DAP_COMPOSE_ERROR_RESULT_NOT_FOUND = -2, + DAP_COMPOSE_ERROR_REQUEST_INIT_FAILED = -3, + DAP_COMPOSE_ERROR_REQUEST_TIMEOUT = -4, + DAP_COMPOSE_ERROR_REQUEST_FAILED = -5 +} dap_compose_error_t; +json_object* dap_request_command_to_rpc(const char *request, compose_config_t *a_config); int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer); @@ -176,7 +192,7 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, uint256_t a_value_fee, const void *a_cond, size_t a_cond_size, const char *a_url_str, uint16_t a_port); -bool dap_get_remote_net_fee_and_address(const char *l_net_name, uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, const char * a_url_str, uint16_t a_port); +bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, compose_config_t *a_config); bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port); dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, @@ -196,11 +212,11 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port); -dap_chain_datum_tx_t *dap_stake_tx_create_compose(const char * a_net_str, dap_enc_key_t *a_key, +dap_chain_datum_tx_t *dap_stake_tx_create_compose(dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, - dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, const char *l_url_str, int l_port, json_object *l_error_handle); + dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, compose_config_t *a_config); dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port); -- GitLab From 9fd0eb9364220af5ab80e2f69f24c0275a475764 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Fri, 11 Apr 2025 15:42:48 +0700 Subject: [PATCH 46/53] [*] refactor order remove --- modules/compose/dap_chain_tx_compose.c | 837 +++++++++--------- .../compose/include/dap_chain_tx_compose.h | 41 +- modules/net/dap_chain_net_tx.c | 3 +- 3 files changed, 446 insertions(+), 435 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 125c7259b3..023f896b69 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -4106,476 +4106,451 @@ json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str return s_compose_config_return_response_handler(l_config); } -// int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv) { -// int l_arg_index = 1; -// const char * l_order_hash_str = NULL; -// const char * l_fee_str = NULL; -// const char * l_net_str = NULL; -// const char * l_wallet_str = NULL; -// const char * l_url_str = NULL; -// const char * l_port_str = NULL; -// int l_port = 0; -// dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); -// if (!l_net_str) { -// printf("Command 'order remove' requires parameter -net\n"); -// return -1; -// } +json_object * dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) { -// if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-url", &l_url_str)) { -// l_url_str = dap_compose_get_net_url(l_net_str); -// } -// if (!dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-port", &l_port_str)) { -// l_port = dap_compose_get_net_port(l_net_str); -// } else { -// l_port = atoi(l_port_str); -// } - -// const char *l_wallet_path = NULL; -// dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet_path", &l_wallet_path); -// if (!l_wallet_path) { -// l_wallet_path = -// #ifdef DAP_OS_WINDOWS -// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); -// #elif defined DAP_OS_MAC -// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); -// #elif defined DAP_OS_UNIX -// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); -// #endif -// } + compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port); + if (!l_config) { + json_object *l_json_obj_ret = json_object_new_object(); + dap_json_compose_error_add(l_json_obj_ret, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS, "Invalid arguments"); + return l_json_obj_ret; + } -// dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); -// if (!l_wallet_str) { -// printf("Command 'order remove' requires parameter -w\n"); -// return -3; -// } -// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); -// if (!l_wallet) { -// printf("Specified wallet not found\n"); -// return -4; -// } -// const char* l_sign_str = dap_chain_wallet_check_sign(l_wallet); -// dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str); -// if (!l_order_hash_str) { -// printf("Command 'order remove' requires parameter -order\n"); -// return -5; -// } -// dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); -// if (!l_fee_str) { -// printf("Command 'order remove' requires parameter -fee\n"); -// return -6; -// } -// uint256_t l_fee = dap_chain_balance_scan(l_fee_str); -// dap_hash_fast_t l_tx_hash = {}; -// dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash); -// char *l_tx_hash_ret = NULL; -// dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_remove_compose(l_net_str, &l_tx_hash, l_fee, l_wallet, l_url_str, l_port); -// dap_chain_wallet_close(l_wallet); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); + if (!l_wallet) { + dap_json_compose_error_add(l_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_WALLET_NOT_FOUND, "Specified wallet not found"); + return s_compose_config_return_response_handler(l_config); + } + const char* l_sign_str = dap_chain_wallet_check_sign(l_wallet); + if (!l_sign_str) { + dap_json_compose_error_add(l_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_KEY_NOT_FOUND, "Failed to retrieve encryption key"); + return s_compose_config_return_response_handler(l_config); + } + uint256_t l_fee = dap_chain_balance_scan(l_fee_str); + if (IS_ZERO_256(l_fee)) { + dap_json_compose_error_add(l_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, "Format -fee <256 bit integer>"); + return s_compose_config_return_response_handler(l_config); + } + dap_hash_fast_t l_tx_hash = {}; + dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash); + if (dap_hash_fast_is_blank(&l_tx_hash)) { + dap_json_compose_error_add(l_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ORDER_HASH, "Invalid order hash"); + return s_compose_config_return_response_handler(l_config); + } + char *l_tx_hash_ret = NULL; + dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_remove_compose(&l_tx_hash, l_fee, l_wallet, l_config); + dap_chain_wallet_close(l_wallet); + if (l_tx) { + dap_chain_net_tx_to_json(l_tx, l_config->response_handler); + DAP_DELETE(l_tx); + } -// return 0; -// } + return s_compose_config_return_response_handler(l_config); +} -// bool process_ledger_response(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, -// dap_chain_hash_fast_t *a_tx_hash, const char *a_url_str, int a_port, dap_chain_hash_fast_t *a_out_hash) { -// *a_out_hash = *a_tx_hash; -// int l_prev_tx_count = 0; -// dap_chain_hash_fast_t l_hash = {}; -// char data[512]; -// snprintf(data, sizeof(data), -// "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", -// dap_chain_hash_fast_to_str_static(a_tx_hash), a_net_str); +static bool s_process_ledger_response(dap_chain_tx_out_cond_subtype_t a_cond_type, + dap_chain_hash_fast_t *a_tx_hash, dap_chain_hash_fast_t *a_out_hash, compose_config_t *a_config) { + *a_out_hash = *a_tx_hash; + int l_prev_tx_count = 0; + dap_chain_hash_fast_t l_hash = {}; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_hash_fast_to_str_static(a_tx_hash), a_config->net_name); -// json_object *response = dap_request_command_to_rpc(data, a_net_str, a_url_str, a_port); -// if (!response) { -// printf("Error: Failed to get response from remote node\n"); -// return false; -// } + json_object *response = dap_request_command_to_rpc(data, a_config); + if (!response) { + printf("Error: Failed to get response from remote node\n"); + return false; + } -// json_object *l_response_array = json_object_array_get_idx(response, 0); -// if (!l_response_array) { -// printf("Error: Can't get the first element from the response array\n"); -// json_object_put(response); -// return false; -// } + json_object *l_response_array = json_object_array_get_idx(response, 0); + if (!l_response_array) { + printf("Error: Can't get the first element from the response array\n"); + json_object_put(response); + return false; + } -// json_object *items = json_object_object_get(l_response_array, "ITEMS"); -// if (!items) { -// printf("Error: No items found in response\n"); -// return false; -// } -// bool l_found = false; -// int items_count = json_object_array_length(items); -// for (int i = 0; i < items_count; i++) { -// json_object *item = json_object_array_get_idx(items, i); -// const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); -// if (dap_strcmp(item_type, "OUT COND") == 0) { -// const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); -// if (!dap_strcmp(subtype, dap_chain_tx_out_cond_subtype_to_str(a_cond_type))) { -// dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(item, "hash")), &l_hash); -// l_prev_tx_count++; -// l_found = true; -// break; -// } -// } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) { -// l_prev_tx_count++; -// } -// } -// if (!l_found) { -// return false; -// } -// bool l_another_tx = false; -// json_object *spent_outs = json_object_object_get(l_response_array, "Spent OUTs"); -// if (spent_outs) { -// int spent_outs_count = json_object_array_length(spent_outs); -// for (int i = 0; i < spent_outs_count; i++) { -// json_object *spent_out = json_object_array_get_idx(spent_outs, i); -// int out_index = json_object_get_int(json_object_object_get(spent_out, "OUT - ")); -// if (out_index == l_prev_tx_count) { -// dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(spent_out, "is spent by tx")), &l_hash); -// l_another_tx = true; -// break; -// } -// } -// } -// if (l_another_tx) { -// *a_out_hash = l_hash; -// return true; -// } -// return false; -// } + json_object *items = json_object_object_get(l_response_array, "ITEMS"); + if (!items) { + printf("Error: No items found in response\n"); + return false; + } + bool l_found = false; + int items_count = json_object_array_length(items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (dap_strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (!dap_strcmp(subtype, dap_chain_tx_out_cond_subtype_to_str(a_cond_type))) { + dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(item, "hash")), &l_hash); + l_prev_tx_count++; + l_found = true; + break; + } + } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT COND") == 0 || dap_strcmp(item_type, "OUT OLD") == 0) { + l_prev_tx_count++; + } + } + if (!l_found) { + return false; + } + bool l_another_tx = false; + json_object *spent_outs = json_object_object_get(l_response_array, "Spent OUTs"); + if (spent_outs) { + int spent_outs_count = json_object_array_length(spent_outs); + for (int i = 0; i < spent_outs_count; i++) { + json_object *spent_out = json_object_array_get_idx(spent_outs, i); + int out_index = json_object_get_int(json_object_object_get(spent_out, "OUT - ")); + if (out_index == l_prev_tx_count) { + dap_chain_hash_fast_from_str(json_object_get_string(json_object_object_get(spent_out, "is spent by tx")), &l_hash); + l_another_tx = true; + break; + } + } + } + if (l_another_tx) { + *a_out_hash = l_hash; + return true; + } + return false; +} -// dap_chain_hash_fast_t dap_ledger_get_final_chain_tx_hash_compose(const char *a_net_str, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash, bool a_unspent_only, const char *a_url_str, int a_port) -// { -// dap_chain_hash_fast_t l_hash = { }; -// if(!a_net_str || !a_tx_hash || dap_hash_fast_is_blank(a_tx_hash)) -// return l_hash; -// l_hash = *a_tx_hash; +dap_chain_hash_fast_t dap_ledger_get_final_chain_tx_hash_compose(dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash, bool a_unspent_only, compose_config_t *a_config) +{ + dap_chain_hash_fast_t l_hash = { }; + if(!a_tx_hash || dap_hash_fast_is_blank(a_tx_hash)) + return l_hash; + l_hash = *a_tx_hash; -// while(process_ledger_response(a_net_str, a_cond_type, a_tx_hash, a_url_str, a_port, &l_hash)); + while(s_process_ledger_response( a_cond_type, a_tx_hash, &l_hash, a_config)); -// return l_hash; -// } + return l_hash; +} -// dap_chain_net_srv_xchange_price_t *dap_chain_net_srv_xchange_price_from_order_compose(const char *a_net_str, dap_chain_tx_out_cond_t *a_cond_tx, -// dap_time_t a_ts_created, const char *a_token_ticker, dap_hash_fast_t *a_order_hash, -// uint256_t *a_fee, bool a_ret_is_invalid, const char *a_url_str, int a_port) -// { -// if (!a_net_str || !*a_net_str || !a_cond_tx || !a_token_ticker || !a_order_hash || !a_url_str || !*a_url_str || a_port == 0) -// return NULL; -// dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); -// if (!l_price) -// return NULL; -// l_price->creation_date = a_ts_created; -// dap_strncpy(l_price->token_buy, a_cond_tx->subtype.srv_xchange.buy_token, sizeof(l_price->token_buy) - 1); - -// l_price->order_hash = *a_order_hash; -// strncpy(l_price->token_sell, a_token_ticker, sizeof(l_price->token_sell) - 1); - -// if (a_fee) -// l_price->fee = *a_fee; - -// l_price->datoshi_sell = a_cond_tx->header.value; -// l_price->creator_addr = a_cond_tx->subtype.srv_xchange.seller_addr; -// l_price->rate = a_cond_tx->subtype.srv_xchange.rate; -// dap_chain_hash_fast_t l_final_hash = dap_ledger_get_final_chain_tx_hash_compose(a_net_str, -// DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->order_hash, false, a_url_str, a_port); -// if ( !dap_hash_fast_is_blank(&l_final_hash) ) { -// l_price->tx_hash = l_final_hash; -// return l_price; -// } else { -// printf( "This order have no active conditional transaction"); -// if (a_ret_is_invalid) { -// dap_hash_fast_t l_tx_hash_zero = {0}; -// l_price->tx_hash = l_tx_hash_zero; -// return l_price; -// } -// } +dap_chain_net_srv_xchange_price_t *dap_chain_net_srv_xchange_price_from_order_compose(dap_chain_tx_out_cond_t *a_cond_tx, + dap_time_t a_ts_created, const char *a_token_ticker, dap_hash_fast_t *a_order_hash, + uint256_t *a_fee, bool a_ret_is_invalid, compose_config_t *a_config) +{ + if (!a_cond_tx || !a_token_ticker || !a_order_hash || !a_config) + return NULL; + dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); + if (!l_price) + return NULL; + l_price->creation_date = a_ts_created; + dap_strncpy(l_price->token_buy, a_cond_tx->subtype.srv_xchange.buy_token, sizeof(l_price->token_buy) - 1); + + l_price->order_hash = *a_order_hash; + strncpy(l_price->token_sell, a_token_ticker, sizeof(l_price->token_sell) - 1); + + if (a_fee) + l_price->fee = *a_fee; + + l_price->datoshi_sell = a_cond_tx->header.value; + l_price->creator_addr = a_cond_tx->subtype.srv_xchange.seller_addr; + l_price->rate = a_cond_tx->subtype.srv_xchange.rate; + dap_chain_hash_fast_t l_final_hash = dap_ledger_get_final_chain_tx_hash_compose(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->order_hash, false, a_config); + if ( !dap_hash_fast_is_blank(&l_final_hash) ) { + l_price->tx_hash = l_final_hash; + return l_price; + } else { + printf( "This order have no active conditional transaction"); + if (a_ret_is_invalid) { + dap_hash_fast_t l_tx_hash_zero = {0}; + l_price->tx_hash = l_tx_hash_zero; + return l_price; + } + } -// return NULL; -// } + return NULL; +} -// dap_chain_datum_tx_t* dap_xchange_tx_invalidate_compose(const char *a_net_str, dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) -// { -// char * l_ret = NULL; +dap_chain_datum_tx_t* dap_xchange_tx_invalidate_compose( dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, compose_config_t *a_config) +{ + if (!a_config) { + return NULL; + } -// if (!a_price) { -// printf("An a_price NULL argument was passed to the s_xchange_tx_invalidate() function."); -// return NULL; -// } -// if (!a_wallet) { -// printf("An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function."); -// return NULL; -// } -// const char *l_native_ticker = s_get_native_ticker(a_net_str); + if (!a_price) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS, "An a_price NULL argument was passed to the s_xchange_tx_invalidate() function."); + return NULL; + } + if (!a_wallet) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS, "An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function."); + return NULL; + } + const char *l_native_ticker = s_get_native_ticker(a_config->net_name); -// dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str)); -// dap_chain_addr_t l_seller_addr = *l_wallet_addr; -// DAP_DELETE(l_wallet_addr); + dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_config->net_name)); + dap_chain_addr_t l_seller_addr = *l_wallet_addr; + DAP_DELETE(l_wallet_addr); -// dap_chain_tx_out_cond_t *l_cond_tx = NULL; -// char data[512]; -// snprintf(data, sizeof(data), -// "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", -// dap_chain_hash_fast_to_str_static(&a_price->tx_hash), a_net_str); + dap_chain_tx_out_cond_t *l_cond_tx = NULL; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_hash_fast_to_str_static(&a_price->tx_hash), a_config->net_name); -// json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); -// if (!response) { -// printf("Error: Failed to get response from remote node\n"); -// return NULL; -// } + json_object *response = dap_request_command_to_rpc(data, a_config); + if (!response) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE, "Failed to get response from remote node"); + return NULL; + } -// json_object *l_response_array = json_object_array_get_idx(response, 0); -// if (!l_response_array) { -// printf("Error: Can't get the first element from the response array\n"); -// json_object_put(response); -// return NULL; -// } + json_object *l_response_array = json_object_array_get_idx(response, 0); + if (!l_response_array) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT, "Can't get the first element from the response array"); + json_object_put(response); + return NULL; + } -// json_object *items = json_object_object_get(l_response_array, "ITEMS"); -// if (!items) { -// printf("Error: No items found in response\n"); -// return NULL; -// } -// int l_prev_cond_idx = 0; -// int items_count = json_object_array_length(items); -// for (int i = 0; i < items_count; i++) { -// json_object *item = json_object_array_get_idx(items, i); -// const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); -// if (dap_strcmp(item_type, "OUT COND") == 0) { -// const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); -// if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { -// l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); -// l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; -// l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); -// l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; -// l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); -// l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); -// strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); -// l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; -// l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); -// l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); -// break; -// } else if (dap_strcmp(subtype, "OUT") == 0 || dap_strcmp(subtype, "OUT COND") == 0 || dap_strcmp(subtype, "OUT OLD") == 0) { -// l_prev_cond_idx++; -// } -// } -// } -// if (!l_cond_tx) { -// printf("Error: No transaction output condition found\n"); -// return NULL; -// } + json_object *items = json_object_object_get(l_response_array, "ITEMS"); + if (!items) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_ITEMS_FOUND, "No items found in response"); + return NULL; + } + int l_prev_cond_idx = 0; + int items_count = json_object_array_length(items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (dap_strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { + l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); + l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; + l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); + l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; + l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); + l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); + strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); + l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; + l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); + l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); + break; + } else if (dap_strcmp(subtype, "OUT") == 0 || dap_strcmp(subtype, "OUT COND") == 0 || dap_strcmp(subtype, "OUT OLD") == 0) { + l_prev_cond_idx++; + } + } + } + if (!l_cond_tx) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_COND_TX, "No transaction output condition found"); + return NULL; + } -// const char *l_tx_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); -// if (!l_tx_ticker) { -// printf("Error: Token_ticker not found in response\n"); -// return NULL; -// } + const char *l_tx_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); + if (!l_tx_ticker) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TOKEN_TICKER, "Token_ticker not found in response"); + return NULL; + } -// bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker); + bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker); -// json_object *spent_outs = json_object_object_get(l_response_array, "all OUTs yet unspent"); -// const char *spent_outs_value = json_object_get_string(spent_outs); -// if (spent_outs_value && !dap_strcmp(spent_outs_value, "yes")) { -// printf("Error: Transaction output item already used\n"); -// return NULL; -// } + json_object *spent_outs = json_object_object_get(l_response_array, "all OUTs yet unspent"); + const char *spent_outs_value = json_object_get_string(spent_outs); + if (spent_outs_value && !dap_strcmp(spent_outs_value, "yes")) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_ALREADY_USED, "Transaction output item already used"); + return NULL; + } -// if (!dap_chain_addr_compare(&l_seller_addr, &l_cond_tx->subtype.srv_xchange.seller_addr)) { -// printf("Only owner can invalidate exchange transaction"); -// return NULL; -// } + if (!dap_chain_addr_compare(&l_seller_addr, &l_cond_tx->subtype.srv_xchange.seller_addr)) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_OWNER, "Only owner can invalidate exchange transaction"); + return NULL; + } -// // create empty transaction -// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); -// // add 'in' item to buy from conditional transaction -// dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0); -// uint256_t l_net_fee = {}; -// dap_chain_addr_t* l_addr_fee = NULL; -// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port); -// uint256_t l_total_fee = a_price->fee; -// if (l_net_fee_used) -// SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // add 'in' item to buy from conditional transaction + dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0); + uint256_t l_net_fee = {}; + dap_chain_addr_t* l_addr_fee = NULL; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, a_config); + uint256_t l_total_fee = a_price->fee; + if (l_net_fee_used) + SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); -// if (!l_single_channel) { -// json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_str, &l_seller_addr, l_url_str, l_port); -// if (!l_outs_native) { -// return NULL; -// } -// int l_out_native_count = json_object_array_length(l_outs_native); -// uint256_t l_transfer_fee = {}, l_fee_back = {}; -// // list of transaction with 'out' items to get net fee -// dap_list_t *l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, -// l_total_fee, -// &l_transfer_fee); -// if (!l_list_fee_out) { -// printf("Not enough funds to pay fee"); -// json_object_put(l_outs_native); -// return NULL; -// } + if (!l_single_channel) { + json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, &l_seller_addr, a_config); + if (!l_outs_native) { + return NULL; + } + int l_out_native_count = json_object_array_length(l_outs_native); + uint256_t l_transfer_fee = {}, l_fee_back = {}; + // list of transaction with 'out' items to get net fee + dap_list_t *l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, + l_total_fee, + &l_transfer_fee); + if (!l_list_fee_out) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INSUFFICIENT_FUNDS, "Not enough funds to pay fee"); + json_object_put(l_outs_native); + return NULL; + } -// // add 'in' items to net fee -// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); -// dap_list_free_full(l_list_fee_out, NULL); -// if (!EQUAL_256(l_value_to_items, l_transfer_fee)) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Can't compose the transaction input"); -// return NULL; -// } -// // return coins to owner -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_cond_tx->header.value, l_tx_ticker) == -1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add returning coins output"); -// return NULL; -// } -// // Network fee -// if (l_net_fee_used && -// dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add network fee output"); -// return NULL; -// } -// // put fee coinback -// SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back); -// if (!IS_ZERO_256(l_fee_back) && -// dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add fee cachback output"); -// return NULL; -// } -// } else { -// uint256_t l_coin_back = {}; -// if (compare256(l_total_fee, l_cond_tx->header.value) >= 0) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Total fee is greater or equal than order liquidity"); -// return NULL; -// } -// SUBTRACT_256_256(l_cond_tx->header.value, l_total_fee, &l_coin_back); -// // return coins to owner -// if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add returning coins output"); -// return NULL; -// } -// // Network fee -// if (l_net_fee_used && -// dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add network fee output"); -// return NULL; -// } -// } -// // Validator's fee -// if (!IS_ZERO_256(a_price->fee)) { -// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add validator's fee output"); -// return NULL; -// } -// } -// // // add 'sign' items -// // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); -// // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) { -// // dap_chain_datum_tx_delete(l_tx); -// // dap_enc_key_delete(l_seller_key); -// // log_it( L_ERROR, "Can't add sign output"); -// // return false; -// // } -// // dap_enc_key_delete(l_seller_key); -// // l_ret = s_xchange_tx_put(l_tx, a_price->net); + // add 'in' items to net fee + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + dap_list_free_full(l_list_fee_out, NULL); + if (!EQUAL_256(l_value_to_items, l_transfer_fee)) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE_FAILED, "Can't compose the transaction input"); + return NULL; + } + // return coins to owner + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_cond_tx->header.value, l_tx_ticker) == -1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_COIN_RETURN_FAILED, "Cant add returning coins output"); + return NULL; + } + // Network fee + if (l_net_fee_used && + dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NET_FEE_FAILED, "Cant add network fee output"); + return NULL; + } + // put fee coinback + SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back); + if (!IS_ZERO_256(l_fee_back) && + dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_COINBACK_FAILED, "Cant add fee cachback output"); + return NULL; + } + } else { + uint256_t l_coin_back = {}; + if (compare256(l_total_fee, l_cond_tx->header.value) >= 0) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_TOO_HIGH, "Total fee is greater or equal than order liquidity"); + return NULL; + } + SUBTRACT_256_256(l_cond_tx->header.value, l_total_fee, &l_coin_back); + // return coins to owner + if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_COIN_RETURN_FAILED, "Cant add returning coins output"); + return NULL; + } + // Network fee + if (l_net_fee_used && + dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NET_FEE_FAILED, "Cant add network fee output"); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_price->fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_VALIDATOR_FEE_FAILED, "Cant add validator's fee output"); + return NULL; + } + } + // // add 'sign' items + // dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); + // if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) { + // dap_chain_datum_tx_delete(l_tx); + // dap_enc_key_delete(l_seller_key); + // log_it( L_ERROR, "Can't add sign output"); + // return false; + // } + // dap_enc_key_delete(l_seller_key); + // l_ret = s_xchange_tx_put(l_tx, a_price->net); -// return l_tx; -// } + return l_tx; +} -// dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, -// dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port) { -// if (!a_net_str || !a_hash_tx || !a_wallet) { -// return NULL; -// } -// if(IS_ZERO_256(a_fee)){ -// return NULL; -// } +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(dap_hash_fast_t *a_hash_tx, uint256_t a_fee, + dap_chain_wallet_t *a_wallet, compose_config_t *a_config) { + if (!a_hash_tx || !a_wallet || !a_config) { + return NULL; + } + if(IS_ZERO_256(a_fee)){ + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, "Fee must be greater than 0"); + return NULL; + } -// dap_time_t ts_created = 0; + dap_time_t ts_created = 0; -// dap_chain_tx_out_cond_t *l_cond_tx = NULL; -// char data[512]; -// snprintf(data, sizeof(data), -// "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", -// dap_chain_hash_fast_to_str_static(a_hash_tx), a_net_str); + dap_chain_tx_out_cond_t *l_cond_tx = NULL; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_hash_fast_to_str_static(a_hash_tx), a_config->net_name); -// json_object *response = dap_request_command_to_rpc(data, a_net_str, l_url_str, l_port); -// if (!response) { -// printf("Error: Failed to get response from remote node\n"); -// return NULL; -// } + json_object *response = dap_request_command_to_rpc(data, a_config); + if (!response) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE, "Failed to get response from remote node"); + return NULL; + } -// const char *items_str = json_object_get_string(response); -// json_object *l_response_array = json_object_array_get_idx(response, 0); -// if (!l_response_array) { -// printf("Error: Can't get the first element from the response array\n"); -// json_object_put(response); -// return NULL; -// } -// json_object *items = json_object_object_get(l_response_array, "ITEMS"); -// if (!items) { -// printf("Error: No items found in response\n"); -// return NULL; -// } -// int items_count = json_object_array_length(items); -// for (int i = 0; i < items_count; i++) { -// json_object *item = json_object_array_get_idx(items, i); -// const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); -// if (dap_strcmp(item_type, "OUT COND") == 0) { -// const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); -// if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { -// l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); -// l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; -// l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); -// l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; -// l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); -// l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); -// strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); -// l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; -// l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); -// l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); -// break; -// } -// } -// } -// if (!l_cond_tx) { -// printf("Error: No transaction output condition found\n"); -// return NULL; -// } + const char *items_str = json_object_get_string(response); + json_object *l_response_array = json_object_array_get_idx(response, 0); + if (!l_response_array) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT, "Can't get the first element from the response array"); + json_object_put(response); + return NULL; + } + json_object *items = json_object_object_get(l_response_array, "ITEMS"); + if (!items) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_ITEMS_FOUND, "No items found in response"); + return NULL; + } + int items_count = json_object_array_length(items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (dap_strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { + l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); + l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; + l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); + l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; + l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); + l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); + strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); + l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; + l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); + l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); + break; + } + } + } + if (!l_cond_tx) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_COND_TX, "No transaction output condition found"); + return NULL; + } -// const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); -// if (!token_ticker) { -// printf("Error: Token_ticker not found in response\n"); -// return NULL; -// } -// const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created")); -// if (ts_created_str) { -// ts_created = dap_time_from_str_rfc822(ts_created_str); -// } else { -// printf("Error: TS_Created not found in response\n"); -// return NULL; -// } + const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); + if (!token_ticker) { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TOKEN_TICKER, "Token_ticker not found in response"); + return NULL; + } + const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created")); + if (ts_created_str) { + ts_created = dap_time_from_str_rfc822(ts_created_str); + } else { + dap_json_compose_error_add(a_config->response_handler, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TIMESTAMP, "TS_Created not found in response"); + return NULL; + } -// dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(a_net_str, l_cond_tx, ts_created, token_ticker, a_hash_tx, &a_fee, false, l_url_str, l_port); -// if (!l_price) { -// return NULL; -// } -// dap_chain_datum_tx_t *l_tx = dap_xchange_tx_invalidate_compose(a_net_str, l_price, a_wallet, l_url_str, l_port); -// json_object * l_json_obj_ret = json_object_new_object(); -// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); -// printf("%s", json_object_to_json_string(l_json_obj_ret)); -// json_object_put(l_json_obj_ret); + dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(l_cond_tx, ts_created, token_ticker, a_hash_tx, &a_fee, false, a_config); + if (!l_price) { + return NULL; + } + dap_chain_datum_tx_t *l_tx = dap_xchange_tx_invalidate_compose(a_hash_tx, a_wallet, a_config); + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); -// DAP_DELETE(l_price); -// return l_tx; -// } + DAP_DELETE(l_price); + return l_tx; +} // srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value> diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 8eca82a87f..12a262cc3c 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -88,7 +88,43 @@ typedef enum { } dap_cli_srv_stake_order_create_staker_error_t; json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port); -int dap_cli_srv_stake_order_remove_compose(int a_argc, char **a_argv); +typedef enum { + SRV_STAKE_ORDER_REMOVE_COMPOSE_OK = 0, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_WALLET_NOT_FOUND, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_KEY_NOT_FOUND, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ORDER_HASH, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_RPC_RESPONSE, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ADDR, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TAX, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_COND_TX, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TOKEN_TICKER, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TS_CREATED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PRICE, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TX, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_ENOUGH_FUNDS, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_SIGN, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_ITEMS_FOUND, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_COND_TX, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TOKEN_TICKER, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TIMESTAMP, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INSUFFICIENT_FUNDS, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE_FAILED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_COIN_RETURN_FAILED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NET_FEE_FAILED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_COINBACK_FAILED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_TOO_HIGH, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_VALIDATOR_FEE_FAILED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_ALREADY_USED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_OWNER +} srv_stake_order_remove_compose_error_t; +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(dap_hash_fast_t *a_hash_tx, uint256_t a_fee, + dap_chain_wallet_t *a_wallet, compose_config_t *a_config); +json_object* dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port); typedef enum { STAKE_DELEGATE_COMPOSE_OK = 0, @@ -218,8 +254,7 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(dap_enc_key_t *a_key, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, compose_config_t *a_config); -dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(const char *a_net_str, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, - dap_chain_wallet_t *a_wallet, const char *l_url_str, int l_port); + #ifdef __cplusplus diff --git a/modules/net/dap_chain_net_tx.c b/modules/net/dap_chain_net_tx.c index e507d20378..04ae89062d 100644 --- a/modules/net/dap_chain_net_tx.c +++ b/modules/net/dap_chain_net_tx.c @@ -1584,7 +1584,8 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json json_object_object_add(json_obj_item,"type", json_object_new_string("out_cond")); const char *l_coins_str, *l_value_str = dap_uint256_to_char(((dap_chain_tx_out_cond_t*)item)->header.value, &l_coins_str); dap_time_t l_ts_exp = ((dap_chain_tx_out_cond_t*)item)->header.ts_expires; - dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_ts_exp); + if (l_ts_exp > 0) + dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_ts_exp); json_object_object_add(json_obj_item,"ts_expires", l_ts_exp ? json_object_new_string(l_tmp_buf) : json_object_new_string("never")); json_object_object_add(json_obj_item,"value", json_object_new_string(l_value_str)); sprintf(l_tmp_buff,"0x%016"DAP_UINT64_FORMAT_x"",((dap_chain_tx_out_cond_t*)item)->header.srv_uid.uint64); -- GitLab From 902262eb163572c38257407afe63306fb40c2123 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Fri, 11 Apr 2025 16:22:33 +0700 Subject: [PATCH 47/53] [*] refactor tx --- modules/compose/dap_chain_tx_compose.c | 776 +++++++++--------- .../compose/include/dap_chain_tx_compose.h | 15 +- 2 files changed, 381 insertions(+), 410 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 023f896b69..d8fea72ff3 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -437,50 +437,50 @@ bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t * return true; } -// bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, -// json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port) { -// char data[512]; -// snprintf(data, sizeof(data), -// "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", -// dap_chain_addr_to_str(a_addr_from), a_token_ticker, l_net_name); -// json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, a_url_str, a_port); -// if (!l_json_outs) { -// return false; -// } +bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, + json_object **l_outs, int *l_outputs_count, compose_config_t *a_config) { + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"wallet\",\"params\": [\"wallet;outputs;-addr;%s;-token;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_addr_to_str(a_addr_from), a_token_ticker, a_config->net_name); + json_object *l_json_outs = dap_request_command_to_rpc(data, a_config); + if (!l_json_outs) { + return false; + } -// if (!json_object_is_type(l_json_outs, json_type_array)) { -// json_object_put(l_json_outs); -// return false; -// } + if (!json_object_is_type(l_json_outs, json_type_array)) { + json_object_put(l_json_outs); + return false; + } -// if (json_object_array_length(l_json_outs) == 0) { -// json_object_put(l_json_outs); -// return false; -// } + if (json_object_array_length(l_json_outs) == 0) { + json_object_put(l_json_outs); + return false; + } -// json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0); -// if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) { -// json_object_put(l_json_outs); -// return false; -// } + json_object *l_first_array = json_object_array_get_idx(l_json_outs, 0); + if (!l_first_array || !json_object_is_type(l_first_array, json_type_array)) { + json_object_put(l_json_outs); + return false; + } -// json_object *l_first_item = json_object_array_get_idx(l_first_array, 0); -// if (!l_first_item) { -// json_object_put(l_json_outs); -// return false; -// } + json_object *l_first_item = json_object_array_get_idx(l_first_array, 0); + if (!l_first_item) { + json_object_put(l_json_outs); + return false; + } -// if (!json_object_object_get_ex(l_first_item, "outs", l_outs) || -// !json_object_is_type(*l_outs, json_type_array)) { -// json_object_put(l_json_outs); -// return false; -// } + if (!json_object_object_get_ex(l_first_item, "outs", l_outs) || + !json_object_is_type(*l_outs, json_type_array)) { + json_object_put(l_json_outs); + return false; + } -// *l_outputs_count = json_object_array_length(*l_outs); -// json_object_get(*l_outs); -// json_object_put(l_json_outs); -// return true; -// } + *l_outputs_count = json_object_array_length(*l_outs); + json_object_get(*l_outs); + json_object_put(l_json_outs); + return true; +} // int dap_tx_create_xchange_compose(int argc, char ** argv) { @@ -591,403 +591,366 @@ bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t * -// int dap_tx_create_compose(int argc, char ** argv) { -// int arg_index = 1; -// const char *addr_base58_to = NULL; -// const char *str_tmp = NULL; -// const char * l_from_wallet_name = NULL; -// const char * l_wallet_fee_name = NULL; -// const char * l_token_ticker = NULL; -// const char * l_net_name = NULL; -// const char * l_chain_name = NULL; -// const char * l_url_str = NULL; -// uint16_t l_port = 0; - -// const char * l_hash_out_type = NULL; -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type); -// if(!l_hash_out_type) -// l_hash_out_type = "hex"; -// if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) { -// printf("Invalid parameter -H, valid values: -H <hex | base58>"); -// return -1; -// } - -// const char *l_wallet_path = NULL; -// dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); -// if (!l_wallet_path) { -// l_wallet_path = -// #ifdef DAP_OS_WINDOWS -// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); -// #elif defined DAP_OS_MAC -// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); -// #elif defined DAP_OS_UNIX -// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); -// #endif -// } - -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); -// if (!l_net_name) { -// printf("tx_create requires parameter '-net'"); -// return -1; -// } - -// if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str)) { -// l_url_str = dap_compose_get_net_url(l_net_name); -// } -// const char *l_port_str = NULL; -// if (!dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str)) { -// l_port = dap_compose_get_net_port(l_net_name); -// } else { -// l_port = atoi(l_port_str); -// } - -// uint256_t *l_value = NULL; -// uint256_t l_value_fee = {}; -// dap_chain_addr_t **l_addr_to = NULL; -// size_t l_addr_el_count = 0; -// size_t l_value_el_count = 0; -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-wallet_fee", &l_wallet_fee_name); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name); +typedef enum { + TX_CREATE_COMPOSE_OK = 0, + TX_CREATE_COMPOSE_MEMORY_ERROR = -1, + TX_CREATE_COMPOSE_ADDR_ERROR = -2, + TX_CREATE_COMPOSE_VALUE_ERROR = -3, + TX_CREATE_COMPOSE_WALLET_ERROR = -4, + TX_CREATE_COMPOSE_INVALID_PARAMS = -5, + TX_CREATE_COMPOSE_FEE_ERROR = -6, + TX_CREATE_COMPOSE_FUNDS_ERROR = -7, + TX_CREATE_COMPOSE_OUT_ERROR = -8 +} tx_create_compose_error_t; -// // Validator's fee -// if (dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) { -// if (!str_tmp) { -// printf("tx_create requires parameter '-fee'"); -// return -1; -// } -// l_value_fee = dap_chain_balance_scan(str_tmp); -// } -// if (IS_ZERO_256(l_value_fee) && (str_tmp && strcmp(str_tmp, "0"))) { -// printf("tx_create requires parameter '-fee' to be valid uint256"); -// return -2; -// } +json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) { + + compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port); + if (!l_config) { + json_object* l_json_obj_ret = json_object_new_object(); + dap_json_compose_error_add(l_json_obj_ret, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, "Can't create compose config"); + return l_json_obj_ret; + } -// if (!l_from_wallet_name) { -// printf("tx_create requires parameter '-from_wallet'"); -// return -3; -// } + uint256_t *l_value = NULL; + uint256_t l_value_fee = {}; + dap_chain_addr_t **l_addr_to = NULL; + size_t l_addr_el_count = 0; + size_t l_value_el_count = 0; -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker); -// if (!l_token_ticker) { -// printf("tx_create requires parameter '-token'"); -// return -4; -// } -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp); + l_value_fee = dap_chain_balance_scan(l_fee_str); + if (IS_ZERO_256(l_value_fee) && (l_fee_str && strcmp(l_fee_str, "0"))) { + dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "tx_create requires parameter '-fee' to be valid uint256"); + return s_compose_config_return_response_handler(l_config); + } -// if (!str_tmp) { -// printf("tx_create requires parameter '-value' to be valid uint256 value"); -// return -6; -// } -// l_value_el_count = dap_str_symbol_count(str_tmp, ',') + 1; + l_value_el_count = dap_str_symbol_count(l_value_str, ',') + 1; -// if (addr_base58_to) -// l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1; -// else -// l_addr_el_count = l_value_el_count; + if (addr_base58_to) + l_addr_el_count = dap_str_symbol_count(addr_base58_to, ',') + 1; + else + l_addr_el_count = l_value_el_count; -// if (addr_base58_to && l_addr_el_count != l_value_el_count) { -// printf("num of '-to_addr' and '-value' should be equal"); -// return -5; -// } + if (addr_base58_to && l_addr_el_count != l_value_el_count) { + dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_INVALID_PARAMS, "num of '-to_addr' and '-value' should be equal"); + return s_compose_config_return_response_handler(l_config); + } -// l_value = DAP_NEW_Z_COUNT(uint256_t, l_value_el_count); -// if (!l_value) { -// printf("Can't allocate memory"); -// return -6; -// } -// char **l_value_array = dap_strsplit(str_tmp, ",", l_value_el_count); -// if (!l_value_array) { -// DAP_DELETE(l_value); -// printf("Can't read '-to_addr' arg"); -// return -7; -// } -// for (size_t i = 0; i < l_value_el_count; ++i) { -// l_value[i] = dap_chain_balance_scan(l_value_array[i]); -// if(IS_ZERO_256(l_value[i])) { -// DAP_DEL_MULTY(l_value_array, l_value); -// printf("tx_create requires parameter '-value' to be valid uint256 value"); -// return -8; -// } -// } -// DAP_DELETE(l_value_array); + l_value = DAP_NEW_Z_COUNT(uint256_t, l_value_el_count); + if (!l_value) { + dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_MEMORY_ERROR, "Can't allocate memory"); + return s_compose_config_return_response_handler(l_config); + } + char **l_value_array = dap_strsplit(l_value_str, ",", l_value_el_count); + if (!l_value_array) { + DAP_DELETE(l_value); + dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_ADDR_ERROR, "Can't read '-to_addr' arg"); + return s_compose_config_return_response_handler(l_config); + } + for (size_t i = 0; i < l_value_el_count; ++i) { + l_value[i] = dap_chain_balance_scan(l_value_array[i]); + if(IS_ZERO_256(l_value[i])) { + DAP_DEL_MULTY(l_value_array, l_value); + dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_VALUE_ERROR, "tx_create requires parameter '-value' to be valid uint256 value"); + return s_compose_config_return_response_handler(l_config); + } + } + DAP_DELETE(l_value_array); -// if (addr_base58_to) { -// l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count); -// if (!l_addr_to) { -// printf("Can't allocate memory"); -// DAP_DELETE(l_value); -// return -9; -// } -// char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count); -// if (!l_addr_base58_to_array) { -// DAP_DEL_MULTY(l_addr_to, l_value); -// printf("Can't read '-to_addr' arg"); -// return -10; -// } -// for (size_t i = 0; i < l_addr_el_count; ++i) { -// l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]); -// if(!l_addr_to[i]) { -// for (size_t j = 0; j < i; ++j) { -// DAP_DELETE(l_addr_to[j]); -// } -// DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value); -// printf("destination address is invalid"); -// return -11; -// } -// } -// DAP_DELETE(l_addr_base58_to_array); -// } + if (addr_base58_to) { + l_addr_to = DAP_NEW_Z_COUNT(dap_chain_addr_t *, l_addr_el_count); + if (!l_addr_to) { + dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_MEMORY_ERROR, "Can't allocate memory"); + DAP_DELETE(l_value); + return s_compose_config_return_response_handler(l_config); + } + char **l_addr_base58_to_array = dap_strsplit(addr_base58_to, ",", l_addr_el_count); + if (!l_addr_base58_to_array) { + DAP_DEL_MULTY(l_addr_to, l_value); + dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_ADDR_ERROR, "Can't read '-to_addr' arg"); + return s_compose_config_return_response_handler(l_config); + } + for (size_t i = 0; i < l_addr_el_count; ++i) { + l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]); + if(!l_addr_to[i]) { + for (size_t j = 0; j < i; ++j) { + DAP_DELETE(l_addr_to[j]); + } + DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value); + dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_ADDR_ERROR, "destination address is invalid"); + return s_compose_config_return_response_handler(l_config); + } + } + DAP_DELETE(l_addr_base58_to_array); + } -// dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, l_wallet_path, NULL); -// if(!l_wallet) { -// printf("Can't open wallet %s", l_from_wallet_name); -// return -12; -// } + dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); + if(!l_wallet) { + dap_json_compose_error_add(l_config->response_handler, TX_CREATE_COMPOSE_WALLET_ERROR, "Can't open wallet %s", l_wallet_str); + return s_compose_config_return_response_handler(l_config); + } -// dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)); -// for (size_t i = 0; l_addr_to && i < l_addr_el_count; ++i) { -// if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) { -// printf("The transaction cannot be directed to the same address as the source."); -// for (size_t j = 0; j < l_addr_el_count; ++j) { -// DAP_DELETE(l_addr_to[j]); -// } -// DAP_DEL_MULTY(l_addr_to, l_value); -// return -13; -// } -// } + dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_str)); + for (size_t i = 0; l_addr_to && i < l_addr_el_count; ++i) { + if (dap_chain_addr_compare(l_addr_to[i], l_addr_from)) { + printf("The transaction cannot be directed to the same address as the source."); + for (size_t j = 0; j < l_addr_el_count; ++j) { + DAP_DELETE(l_addr_to[j]); + } + DAP_DEL_MULTY(l_addr_to, l_value); + return s_compose_config_return_response_handler(l_config); + } + } -// dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose(l_net_name, l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count, l_url_str, l_port); + dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create_compose( l_addr_from, l_addr_to, l_token_ticker, l_value, l_value_fee, l_addr_el_count, l_config); + if (l_tx) { + dap_chain_net_tx_to_json(l_tx, l_config->response_handler); + dap_chain_datum_tx_delete(l_tx); + DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from); + return s_compose_config_return_response_handler(l_config); + } -// json_object * l_json_obj_ret = json_object_new_object(); -// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); -// printf("%s", json_object_to_json_string(l_json_obj_ret)); -// json_object_put(l_json_obj_ret); -// dap_chain_datum_tx_delete(l_tx); -// DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from); -// return 0; -// } + DAP_DEL_MULTY(l_addr_to, l_value, l_addr_from); + return s_compose_config_return_response_handler(l_config); +} -// int dap_chain_datum_tx_add_out_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value) { -// if (IS_ZERO_256(a_value)) -// return -1; +int dap_chain_datum_tx_add_out_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value) { + if (IS_ZERO_256(a_value)) + return -1; -// dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t); -// if (!l_item) -// return -1; + dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t); + if (!l_item) + return -1; -// l_item->header.type = TX_ITEM_TYPE_OUT; -// l_item->header.value = a_value; + l_item->header.type = TX_ITEM_TYPE_OUT; + l_item->header.value = a_value; -// int res = dap_chain_datum_tx_add_item(a_tx, l_item); -// DAP_DELETE(l_item); + int res = dap_chain_datum_tx_add_item(a_tx, l_item); + DAP_DELETE(l_item); -// return res; -// } + return res; +} -// int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value, const char *a_token) -// { -// if (!a_token || IS_ZERO_256(a_value)) -// return -1; +int dap_chain_datum_tx_add_out_ext_item_without_addr(dap_chain_datum_tx_t **a_tx, uint256_t a_value, const char *a_token) +{ + if (!a_token || IS_ZERO_256(a_value)) + return -1; -// dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t); -// if (!l_item) -// return -2; -// l_item->header.type = TX_ITEM_TYPE_OUT_EXT; -// l_item->header.value = a_value; -// dap_strncpy((char*)l_item->token, a_token, sizeof(l_item->token) - 1); + dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t); + if (!l_item) + return -2; + l_item->header.type = TX_ITEM_TYPE_OUT_EXT; + l_item->header.value = a_value; + dap_strncpy((char*)l_item->token, a_token, sizeof(l_item->token) - 1); -// int result = dap_chain_datum_tx_add_item(a_tx, l_item); -// DAP_DELETE(l_item); -// return result; -// } + int result = dap_chain_datum_tx_add_item(a_tx, l_item); + DAP_DELETE(l_item); + return result; +} -// dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, -// const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port) -// { -// if (!a_addr_from || !a_token_ticker || !a_value) { -// return NULL; -// } +dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, + const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, compose_config_t *a_config) +{ + if (!a_config) { + return NULL; + } + if (!a_addr_from || !a_token_ticker || !a_value) { + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_INVALID_PARAMS, "Invalid parameters"); + return NULL; + } -// if (dap_chain_addr_check_sum(a_addr_from)) { -// return NULL; -// } + if (dap_chain_addr_check_sum(a_addr_from)) { + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_ADDR_ERROR, "Invalid source address"); + return NULL; + } -// for (size_t i = 0; i < a_tx_num; ++i) { -// // if (!a_addr_to || !a_addr_to[i]) { -// // return NULL; -// // } -// if (a_addr_to && dap_chain_addr_check_sum(a_addr_to[i])) { -// return NULL; -// } -// if (IS_ZERO_256(a_value[i])) { -// return NULL; -// } -// } -// const char * l_native_ticker = s_get_native_ticker(l_net_name); -// bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker); + for (size_t i = 0; i < a_tx_num; ++i) { + // if (!a_addr_to || !a_addr_to[i]) { + // return NULL; + // } + if (a_addr_to && dap_chain_addr_check_sum(a_addr_to[i])) { + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_ADDR_ERROR, "Invalid destination address"); + return NULL; + } + if (IS_ZERO_256(a_value[i])) { + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_VALUE_ERROR, "Invalid value"); + return NULL; + } + } + const char * l_native_ticker = s_get_native_ticker(a_config->net_name); + bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker); -// uint256_t l_value_transfer = {}; // how many coins to transfer -// uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {}; -// for (size_t i = 0; i < a_tx_num; ++i) { -// SUM_256_256(l_value_total, a_value[i], &l_value_total); -// } -// uint256_t l_value_need = l_value_total; + uint256_t l_value_transfer = {}; // how many coins to transfer + uint256_t l_value_total = {}, l_total_fee = {}, l_fee_transfer = {}; + for (size_t i = 0; i < a_tx_num; ++i) { + SUM_256_256(l_value_total, a_value[i], &l_value_total); + } + uint256_t l_value_need = l_value_total; -// dap_list_t *l_list_fee_out = NULL; -// uint256_t l_net_fee = {}; -// dap_chain_addr_t *l_addr_fee = NULL; -// if (!dap_get_remote_net_fee_and_address(l_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port)) { -// return NULL; -// } + dap_list_t *l_list_fee_out = NULL; + uint256_t l_net_fee = {}; + dap_chain_addr_t *l_addr_fee = NULL; + if (!dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, a_config)) { + return NULL; + } -// bool l_net_fee_used = !IS_ZERO_256(l_net_fee); -// SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); -// json_object *l_outs = NULL; -// int l_outputs_count = 0; -// if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, l_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) { -// return NULL; -// } + bool l_net_fee_used = !IS_ZERO_256(l_net_fee); + SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); + json_object *l_outs = NULL; + int l_outputs_count = 0; + if (!dap_get_remote_wallet_outs_and_count(a_addr_from, a_token_ticker, &l_outs, &l_outputs_count, a_config)) { + return NULL; + } -// if (l_single_channel) -// SUM_256_256(l_value_need, l_total_fee, &l_value_need); -// else if (!IS_ZERO_256(l_total_fee)) { -// l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, -// l_total_fee, -// &l_fee_transfer); -// if (!l_list_fee_out) { -// printf("Not enough funds to pay fee"); -// json_object_put(l_outs); -// return NULL; -// } -// } -// dap_list_t *l_list_used_out = NULL; -// l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, -// l_value_need, -// &l_value_transfer); -// json_object_put(l_outs); -// if (!l_list_used_out) { -// printf("Not enough funds to transfer"); -// return NULL; -// } -// // create empty transaction -// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); -// // add 'in' items -// { -// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); -// assert(EQUAL_256(l_value_to_items, l_value_transfer)); -// dap_list_free_full(l_list_used_out, NULL); -// if (l_list_fee_out) { -// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); -// assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); -// dap_list_free_full(l_list_fee_out, NULL); -// } + if (l_single_channel) + SUM_256_256(l_value_need, l_total_fee, &l_value_need); + else if (!IS_ZERO_256(l_total_fee)) { + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_total_fee, + &l_fee_transfer); + if (!l_list_fee_out) { + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Not enough funds to pay fee"); + json_object_put(l_outs); + return NULL; + } + } + dap_list_t *l_list_used_out = NULL; + l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_value_need, + &l_value_transfer); + json_object_put(l_outs); + if (!l_list_used_out) { + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Not enough funds to transfer"); + return NULL; + } + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // add 'in' items + { + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + if (l_list_fee_out) { + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); + dap_list_free_full(l_list_fee_out, NULL); + } -// } -// if (a_tx_num > 1) { -// uint32_t l_tx_num = a_tx_num; -// dap_chain_tx_tsd_t *l_out_count = dap_chain_datum_tx_item_tsd_create(&l_tx_num, DAP_CHAIN_DATUM_TRANSFER_TSD_TYPE_OUT_COUNT, sizeof(uint32_t)); -// dap_chain_datum_tx_add_item(&l_tx, l_out_count); -// } + } + if (a_tx_num > 1) { + uint32_t l_tx_num = a_tx_num; + dap_chain_tx_tsd_t *l_out_count = dap_chain_datum_tx_item_tsd_create(&l_tx_num, DAP_CHAIN_DATUM_TRANSFER_TSD_TYPE_OUT_COUNT, sizeof(uint32_t)); + dap_chain_datum_tx_add_item(&l_tx, l_out_count); + } -// if (l_single_channel) { // add 'out' items -// uint256_t l_value_pack = {}; // how much datoshi add to 'out' items -// for (size_t i = 0; i < a_tx_num; ++i) { -// if (a_addr_to) { -// if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } else { -// if (dap_chain_datum_tx_add_out_without_addr(&l_tx, a_value[i]) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// SUM_256_256(l_value_pack, a_value[i], &l_value_pack); -// } -// // Network fee -// if (l_net_fee_used) { -// if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) -// SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); -// else { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// // Validator's fee -// if (!IS_ZERO_256(a_value_fee)) { -// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) -// SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); -// else { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// // coin back -// uint256_t l_value_back; -// SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); -// if(!IS_ZERO_256(l_value_back)) { -// if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// } else { // add 'out_ext' items -// for (size_t i = 0; i < a_tx_num; ++i) { -// if (a_addr_to) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } else { -// if (dap_chain_datum_tx_add_out_ext_item_without_addr(&l_tx, a_value[i], a_token_ticker) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// } -// // coin back -// uint256_t l_value_back; -// SUBTRACT_256_256(l_value_transfer, l_value_total, &l_value_back); -// if(!IS_ZERO_256(l_value_back)) { -// if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// // Network fee -// if (l_net_fee_used) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// // Validator's fee -// if (!IS_ZERO_256(a_value_fee)) { -// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// // fee coin back -// SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back); -// if(!IS_ZERO_256(l_value_back)) { -// if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// } -// DAP_DELETE(l_addr_fee); -// return l_tx; -// } + if (l_single_channel) { // add 'out' items + uint256_t l_value_pack = {}; // how much datoshi add to 'out' items + for (size_t i = 0; i < a_tx_num; ++i) { + if (a_addr_to) { + if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to[i], a_value[i]) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'out' item"); + return NULL; + } + } else { + if (dap_chain_datum_tx_add_out_without_addr(&l_tx, a_value[i]) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'out' without address"); + return NULL; + } + } + SUM_256_256(l_value_pack, a_value[i], &l_value_pack); + } + // Network fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) + SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Can't add network 'fee' item"); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) + SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Can't add validator's 'fee' item"); + return NULL; + } + } + // coin back + uint256_t l_value_back; + SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); + if(!IS_ZERO_256(l_value_back)) { + if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'coin back' item"); + return NULL; + } + } + } else { // add 'out_ext' items + for (size_t i = 0; i < a_tx_num; ++i) { + if (a_addr_to) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to[i], a_value[i], a_token_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'out_ext' item"); + return NULL; + } + } else { + if (dap_chain_datum_tx_add_out_ext_item_without_addr(&l_tx, a_value[i], a_token_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'out_ext' without address"); + return NULL; + } + } + } + // coin back + uint256_t l_value_back; + SUBTRACT_256_256(l_value_transfer, l_value_total, &l_value_back); + if(!IS_ZERO_256(l_value_back)) { + if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, a_token_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'coin back' item"); + return NULL; + } + } + // Network fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add network 'fee' item"); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Can't add validator's 'fee' item"); + return NULL; + } + } + // fee coin back + SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back); + if(!IS_ZERO_256(l_value_back)) { + if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_OUT_ERROR, "Can't add 'coin back' item"); + return NULL; + } + } + } + DAP_DELETE(l_addr_fee); + return l_tx; +} dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer) { @@ -3062,10 +3025,17 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, - const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port) + const char *a_wallet_path, const char *a_cert_str, const char *a_fee_str, const char *a_url_str, uint16_t a_port) { compose_config_t* l_config = s_compose_config_init(a_net_str, a_url_str, a_port); dap_hash_fast_t l_tx_hash = {}; + + uint256_t l_fee = dap_chain_balance_scan(a_fee_str); + if (IS_ZERO_256(l_fee)) { + dap_json_compose_error_add(l_config->response_handler, DAP_CLI_STAKE_INVALIDATE_FEE_ERROR, "Unrecognized number in '-fee' param"); + return s_compose_config_return_response_handler(l_config); + } + if (a_tx_hash_str) { dap_chain_hash_fast_from_str(a_tx_hash_str, &l_tx_hash); } else { @@ -3210,7 +3180,7 @@ json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const c return s_compose_config_return_response_handler(l_config); } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); - dap_chain_datum_tx_t *l_tx = dap_stake_tx_invalidate_compose(&l_tx_hash, a_fee, l_enc_key, l_config); + dap_chain_datum_tx_t *l_tx = dap_stake_tx_invalidate_compose(&l_tx_hash, l_fee, l_enc_key, l_config); if (l_tx) { dap_chain_net_tx_to_json(l_tx, l_config->response_handler); DAP_DELETE(l_tx); diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 12a262cc3c..7c6203532d 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -68,7 +68,7 @@ extern "C" { const char* dap_compose_get_net_url(const char* name); uint16_t dap_compose_get_net_port(const char* name); -int dap_tx_create_compose(int argc, char ** argv); +json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port); int dap_tx_create_xchange_compose(int argc, char ** argv); int dap_tx_cond_create_compose(int argc, char ** argv); int dap_cli_hold_compose(int a_argc, char **a_argv); @@ -197,11 +197,12 @@ typedef enum { DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR = -25, DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR = -26, DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27, - DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28 + DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28, + DAP_CLI_STAKE_INVALIDATE_FEE_ERROR = -29 } dap_cli_stake_invalidate_error_t; dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, compose_config_t *a_config); json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, - const char *a_wallet_path, const char *a_cert_str, uint256_t a_fee, const char *a_url_str, uint16_t a_port); + const char *a_wallet_path, const char *a_cert_str, const char *a_fee_str, const char *a_url_str, uint16_t a_port); typedef enum { DAP_COMPOSE_ERROR_NONE = 0, @@ -215,8 +216,8 @@ json_object* dap_request_command_to_rpc(const char *request, compose_config_t *a int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer); -dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(const char * l_net_name, dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, - const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, const char * a_url_str, uint16_t a_port); +dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, + const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, compose_config_t *a_config); dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, const char *a_token_sell, uint256_t a_datoshi_sell, uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port); dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, @@ -229,8 +230,8 @@ dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net uint256_t a_value_fee, const void *a_cond, size_t a_cond_size, const char *a_url_str, uint16_t a_port); bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, compose_config_t *a_config); -bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, const char *l_net_name, - json_object **l_outs, int *l_outputs_count, const char * a_url_str, uint16_t a_port); +bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, + json_object **l_outs, int *l_outputs_count, compose_config_t *a_config); dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, const char *a_main_ticker, uint256_t a_value, uint256_t a_value_fee, -- GitLab From 89e0057f9b8fe6c5a72f31e726f9515395813cf7 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Fri, 11 Apr 2025 16:50:47 +0700 Subject: [PATCH 48/53] [*] refactor xchange --- modules/compose/dap_chain_tx_compose.c | 713 +++++++++--------- .../compose/include/dap_chain_tx_compose.h | 14 +- 2 files changed, 355 insertions(+), 372 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index d8fea72ff3..2349aa5e5d 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -483,111 +483,7 @@ bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const c } -// int dap_tx_create_xchange_compose(int argc, char ** argv) { -// int arg_index = 1; -// const char *l_net_name = NULL; -// const char *l_token_sell = NULL; -// const char *l_token_buy = NULL; -// const char *l_wallet_name = NULL; -// const char *l_value_str = NULL; -// const char *l_rate_str = NULL; -// const char *l_fee_str = NULL; -// const char *l_url_str = NULL; -// const char *l_port_str = NULL; -// uint16_t l_port = 0; - -// const char *l_wallet_path = NULL; -// dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); -// if (!l_wallet_path) { -// l_wallet_path = -// #ifdef DAP_OS_WINDOWS -// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); -// #elif defined DAP_OS_MAC -// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); -// #elif defined DAP_OS_UNIX -// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); -// #endif -// } - -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_sell", &l_token_sell); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token_buy", &l_token_buy); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-rate", &l_rate_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str); - -// if (!l_net_name) { -// printf("xchange_create requires parameter '-net'"); -// return -1; -// } - -// if (!l_url_str) { -// l_url_str = dap_compose_get_net_url(l_net_name); -// } - -// if (!l_port_str) { -// l_port = dap_compose_get_net_port(l_net_name); -// } else { -// l_port = atoi(l_port_str); -// } - -// if (!l_token_buy) { -// printf("xchange_create requires parameter '-token_buy'"); -// return -1; -// } - -// if (!l_token_sell) { -// printf("xchange_create requires parameter '-token_sell'"); -// return -1; -// } - -// if (!l_wallet_name) { -// printf("xchange_create requires parameter '-w'"); -// return -1; -// } - -// if (!l_value_str) { -// printf("xchange_create requires parameter '-value'"); -// return -1; -// } -// if (!l_rate_str) { -// printf("xchange_create requires parameter '-rate'"); -// return -1; -// } - -// if (!l_fee_str) { -// printf("xchange_create requires parameter '-fee'"); -// return -1; -// } - -// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL); -// if(!l_wallet) { -// printf("wallet %s does not exist", l_wallet_name); -// return -1; -// } - - -// uint256_t l_value = dap_chain_balance_scan(l_value_str); -// uint256_t l_rate = dap_chain_balance_scan(l_rate_str); -// uint256_t l_fee = dap_chain_balance_scan(l_fee_str); -// if (IS_ZERO_256(l_value) || IS_ZERO_256(l_rate) || IS_ZERO_256(l_fee)) { -// printf("Invalid parameter value, rate or fee is 0, use required format 1.0e+18 ot in datoshi"); -// return -1; -// } - -// dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_net_name, l_token_buy, -// l_token_sell, l_value, l_rate, l_fee, l_wallet, l_url_str, l_port); -// json_object *l_ret = json_object_new_object(); -// dap_chain_net_tx_to_json(l_tx, l_ret); -// printf("%s", json_object_to_json_string(l_ret)); -// json_object_put(l_ret); -// dap_chain_datum_tx_delete(l_tx); -// return 0; -// } @@ -603,7 +499,7 @@ typedef enum { TX_CREATE_COMPOSE_OUT_ERROR = -8 } tx_create_compose_error_t; -json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) { +json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) { compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port); if (!l_config) { @@ -1015,127 +911,6 @@ dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, } } -// uint256_t get_balance_from_json(json_object *l_json_outs, const char *a_token_sell) { -// uint256_t l_value = {}; -// if (l_json_outs && json_object_is_type(l_json_outs, json_type_array)) { -// for (size_t i = 0; i < json_object_array_length(l_json_outs); i++) { -// json_object *outer_array = json_object_array_get_idx(l_json_outs, i); -// if (json_object_is_type(outer_array, json_type_array)) { -// for (size_t j = 0; j < json_object_array_length(outer_array); j++) { -// json_object *addr_obj = json_object_array_get_idx(outer_array, j); -// if (json_object_is_type(addr_obj, json_type_object)) { -// json_object *tokens = NULL; -// if (json_object_object_get_ex(addr_obj, "tokens", &tokens) && json_object_is_type(tokens, json_type_array)) { -// for (size_t k = 0; k < json_object_array_length(tokens); k++) { -// json_object *token_obj = json_object_array_get_idx(tokens, k); -// json_object *token = NULL; -// if (json_object_object_get_ex(token_obj, "token", &token) && json_object_is_type(token, json_type_object)) { -// json_object *ticker = NULL; -// if (json_object_object_get_ex(token, "ticker", &ticker) && json_object_is_type(ticker, json_type_string)) { -// const char *ticker_str = json_object_get_string(ticker); -// if (strcmp(ticker_str, a_token_sell) == 0) { -// json_object *datoshi = NULL; -// if (json_object_object_get_ex(token_obj, "datoshi", &datoshi) && json_object_is_type(datoshi, json_type_string)) { -// const char *datoshi_str = json_object_get_string(datoshi); -// l_value = dap_uint256_scan_uninteger(datoshi_str); -// break; -// } -// } -// } -// } -// } -// } -// } -// } -// } -// } -// } -// return l_value; -// } - -// bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) { -// if (json_object_is_type(l_json_coins, json_type_array)) { -// for (size_t i = 0; i < json_object_array_length(l_json_coins); i++) { -// json_object *token_array = json_object_array_get_idx(l_json_coins, i); -// if (json_object_is_type(token_array, json_type_array)) { -// for (size_t j = 0; j < json_object_array_length(token_array); j++) { -// json_object *token_obj = json_object_array_get_idx(token_array, j); -// json_object *token_name = NULL; -// if (json_object_object_get_ex(token_obj, "-->Token name", &token_name) && json_object_is_type(token_name, json_type_string)) { -// const char *token_name_str = json_object_get_string(token_name); -// if (strcmp(token_name_str, a_token) == 0) { -// return true; -// } -// } -// } -// } -// } -// } -// return false; -// } - -// dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, -// const char *a_token_sell, uint256_t a_datoshi_sell, -// uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port){ -// if (!a_net_name || !a_token_buy || !a_token_sell || !a_wallet) { -// return NULL; // XCHANGE_CREATE_ERROR_INVALID_ARGUMEN -// } -// if (IS_ZERO_256(a_rate)) { -// return NULL; // XCHANGE_CREATE_ERROR_RATE_IS_ZERO -// } -// if (IS_ZERO_256(a_fee)) { -// return NULL; // XCHANGE_CREATE_ERROR_FEE_IS_ZERO -// } -// if (IS_ZERO_256(a_datoshi_sell)) { -// return NULL; // XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO -// } -// char data[512]; -// snprintf(data, sizeof(data), -// "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name); -// json_object *l_json_coins = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port); -// if (!l_json_coins) { -// return NULL; // XCHANGE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS -// } -// if (!check_token_in_ledger(l_json_coins, a_token_sell) || !check_token_in_ledger(l_json_coins, a_token_buy)) { -// json_object_put(l_json_coins); -// return NULL; // XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER -// } -// json_object_put(l_json_coins); -// dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name)); -// snprintf(data, sizeof(data), -// "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", -// dap_chain_addr_to_str(l_wallet_addr), a_net_name); -// DAP_DEL_Z(l_wallet_addr); -// json_object *l_json_outs = dap_request_command_to_rpc(data, a_net_name, a_url_str, a_port); -// uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell); - -// uint256_t l_value_sell = a_datoshi_sell; -// if (!dap_strcmp(s_get_native_ticker(a_net_name), a_token_sell)) { -// if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) { -// return NULL; // XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE -// } -// } else { // sell non-native ticker -// uint256_t l_fee_value = get_balance_from_json(l_json_outs, s_get_native_ticker(a_net_name)); -// if (compare256(l_fee_value, a_fee) == -1) { -// return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET -// } -// } -// if (compare256(l_value, l_value_sell) == -1) { -// return NULL; // XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET -// } -// // Create the price -// dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); -// if (!l_price) { -// return NULL; // XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED -// } -// dap_stpcpy(l_price->token_sell, a_token_sell); -// dap_stpcpy(l_price->token_buy, a_token_buy); -// l_price->datoshi_sell = a_datoshi_sell; -// l_price->rate = a_rate; -// l_price->fee = a_fee; -// dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_net_name), a_net_name, a_url_str, a_port); -// return l_tx; -// } json_object *dap_get_remote_tx_outs(const char *a_token_ticker, dap_chain_addr_t * a_addr, compose_config_t *a_config) { char data[512]; @@ -1186,151 +961,359 @@ json_object *dap_get_remote_tx_outs(const char *a_token_ticker, dap_chain_addr_ return l_outs; } +uint256_t get_balance_from_json(json_object *l_json_outs, const char *a_token_sell) { + uint256_t l_value = {}; + if (l_json_outs && json_object_is_type(l_json_outs, json_type_array)) { + for (size_t i = 0; i < json_object_array_length(l_json_outs); i++) { + json_object *outer_array = json_object_array_get_idx(l_json_outs, i); + if (json_object_is_type(outer_array, json_type_array)) { + for (size_t j = 0; j < json_object_array_length(outer_array); j++) { + json_object *addr_obj = json_object_array_get_idx(outer_array, j); + if (json_object_is_type(addr_obj, json_type_object)) { + json_object *tokens = NULL; + if (json_object_object_get_ex(addr_obj, "tokens", &tokens) && json_object_is_type(tokens, json_type_array)) { + for (size_t k = 0; k < json_object_array_length(tokens); k++) { + json_object *token_obj = json_object_array_get_idx(tokens, k); + json_object *token = NULL; + if (json_object_object_get_ex(token_obj, "token", &token) && json_object_is_type(token, json_type_object)) { + json_object *ticker = NULL; + if (json_object_object_get_ex(token, "ticker", &ticker) && json_object_is_type(ticker, json_type_string)) { + const char *ticker_str = json_object_get_string(ticker); + if (strcmp(ticker_str, a_token_sell) == 0) { + json_object *datoshi = NULL; + if (json_object_object_get_ex(token_obj, "datoshi", &datoshi) && json_object_is_type(datoshi, json_type_string)) { + const char *datoshi_str = json_object_get_string(datoshi); + l_value = dap_uint256_scan_uninteger(datoshi_str); + break; + } + } + } + } + } + } + } + } + } + } + } + return l_value; +} -// dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, -// const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port) -// { -// if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) { -// return NULL; -// } -// const char *l_native_ticker = s_get_native_ticker(a_net_name); -// bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker); -// // find the transactions from which to take away coins -// uint256_t l_value_transfer; // how many coins to transfer -// uint256_t l_value_need = a_price->datoshi_sell, -// l_net_fee, -// l_total_fee = a_price->fee, -// l_fee_transfer; -// dap_chain_addr_t * l_addr_net_fee = NULL; -// dap_list_t *l_list_fee_out = NULL; +bool check_token_in_ledger(json_object *l_json_coins, const char *a_token) { + if (json_object_is_type(l_json_coins, json_type_array)) { + for (size_t i = 0; i < json_object_array_length(l_json_coins); i++) { + json_object *token_array = json_object_array_get_idx(l_json_coins, i); + if (json_object_is_type(token_array, json_type_array)) { + for (size_t j = 0; j < json_object_array_length(token_array); j++) { + json_object *token_obj = json_object_array_get_idx(token_array, j); + json_object *token_name = NULL; + if (json_object_object_get_ex(token_obj, "-->Token name", &token_name) && json_object_is_type(token_name, json_type_string)) { + const char *token_name_str = json_object_get_string(token_name); + if (strcmp(token_name_str, a_token) == 0) { + return true; + } + } + } + } + } + } + return false; +} -// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_net_fee, a_url_str, a_port); -// if (l_net_fee_used) -// SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); -// dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_name)); -// dap_chain_addr_t l_seller_addr = *l_wallet_addr; -// json_object *l_outs_native = dap_get_remote_tx_outs(a_native_ticker, a_net_name, l_wallet_addr, a_url_str, a_port); -// if (!l_outs_native) { -// return NULL; -// } +typedef enum dap_xchange_compose_error { + DAP_XCHANGE_COMPOSE_ERROR_NONE = 0, + DAP_XCHANGE_COMPOSE_ERROR_INVALID_ARGUMENT, + DAP_XCHANGE_COMPOSE_ERROR_RATE_IS_ZERO, + DAP_XCHANGE_COMPOSE_ERROR_FEE_IS_ZERO, + DAP_XCHANGE_COMPOSE_ERROR_VALUE_SELL_IS_ZERO, + DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_GET_TX_OUTS, + DAP_XCHANGE_COMPOSE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER, + DAP_XCHANGE_COMPOSE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE, + DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET, + DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET, + DAP_XCHANGE_COMPOSE_ERROR_MEMORY_ALLOCATED, + DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS_TO_PAY_FEE, + DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS_TO_TRANSFER, + DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_COMPOSE_THE_TRANSACTION_INPUT, + DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_COMPOSE_THE_TRANSACTION_CONDITIONAL_OUTPUT, + DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_NETWORK_FEE_OUTPUT, + DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_VALIDATOR_FEE_OUTPUT, + DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_COIN_BACK_OUTPUT, + DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_FEE_BACK_OUTPUT, + DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE +} dap_xchange_compose_error_t; + +json_object* dap_tx_create_xchange_compose(const char *l_net_name, const char *l_token_buy, const char *l_token_sell, const char *l_wallet_name, const char *l_wallet_path, const char *l_value_str, const char *l_rate_str, const char *l_fee_str, const char *l_url_str, uint16_t l_port){ + compose_config_t *l_config = s_compose_config_init(l_net_name, l_url_str, l_port); + if (!l_config) { + json_object* l_json_obj_ret = json_object_new_object(); + dap_json_compose_error_add(l_json_obj_ret, DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE, "Can't create compose config"); + return l_json_obj_ret; + } -// json_object *l_outs = NULL; -// if (!dap_strcmp(a_price->token_sell, a_native_ticker)) { -// l_outs = l_outs_native; -// } else { -// l_outs = dap_get_remote_tx_outs(a_price->token_sell, a_net_name, l_wallet_addr, a_url_str, a_port); -// } -// DAP_DELETE(l_wallet_addr); -// int l_out_native_count = json_object_array_length(l_outs_native); -// int l_out_count = json_object_array_length(l_outs); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL); + if(!l_wallet) { + dap_json_compose_error_add(l_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE, "wallet %s does not exist", l_wallet_name); + return s_compose_config_return_response_handler(l_config); + } -// if (l_single_channel) -// SUM_256_256(l_value_need, l_total_fee, &l_value_need); -// else if (!IS_ZERO_256(l_total_fee)) { -// l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, -// l_total_fee, -// &l_fee_transfer); -// if (!l_list_fee_out) { -// printf("Not enough funds to pay fee"); -// json_object_put(l_outs_native); -// json_object_put(l_outs); -// return NULL; -// } -// } -// dap_list_t *l_list_used_out = NULL; -// l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_out_count, -// l_value_need, -// &l_value_transfer); -// if (!l_list_used_out) { -// printf("Not enough funds to transfer"); -// json_object_put(l_outs_native); -// json_object_put(l_outs); -// return NULL; -// } -// // create empty transaction -// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); -// // add 'in' items to sell -// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); -// dap_list_free_full(l_list_used_out, NULL); -// if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Can't compose the transaction input\n"); -// return NULL; -// } -// if (!l_single_channel) { -// // add 'in' items to fee -// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); -// if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Can't compose the transaction input\n"); -// return NULL; -// } -// } + uint256_t l_value = dap_chain_balance_scan(l_value_str); + if (IS_ZERO_256(l_value)) { + dap_json_compose_error_add(l_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE, "Invalid parameter value, rate or fee is 0, use required format 1.0e+18 ot in datoshi"); + return s_compose_config_return_response_handler(l_config); + } + uint256_t l_rate = dap_chain_balance_scan(l_rate_str); + if (IS_ZERO_256(l_rate)) { + dap_json_compose_error_add(l_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE, "Invalid parameter rate"); + return s_compose_config_return_response_handler(l_config); + } + uint256_t l_fee = dap_chain_balance_scan(l_fee_str); + if (IS_ZERO_256(l_fee)) { + dap_json_compose_error_add(l_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_FEE, "Invalid parameter fee"); + return s_compose_config_return_response_handler(l_config); + } -// // add 'out_cond' & 'out' items + dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_create_compose(l_token_buy, + l_token_sell, l_value, l_rate, l_fee, l_wallet, l_config); + if (l_tx) { + dap_chain_net_tx_to_json(l_tx, l_config->response_handler); + dap_chain_datum_tx_delete(l_tx); + return s_compose_config_return_response_handler(l_config); + } -// { -// dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID }; -// dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(l_uid, s_get_net_id(a_net_name), a_price->datoshi_sell, -// s_get_net_id(a_net_name), a_price->token_buy, a_price->rate, -// &l_seller_addr, NULL, 0); -// if (!l_tx_out) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Can't compose the transaction conditional output\n"); -// return NULL; -// } -// dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); -// DAP_DELETE(l_tx_out); -// // Network fee -// if (l_net_fee_used) { -// if ((l_single_channel && -// dap_chain_datum_tx_add_out_item(&l_tx, l_addr_net_fee, l_net_fee) != 1) || -// (!l_single_channel && -// dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add network fee output\n"); -// return NULL; -// } -// } -// DAP_DELETE(l_addr_net_fee); -// // Validator's fee -// if (!IS_ZERO_256(a_price->fee)) { -// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add validator's fee output\n"); -// return NULL; -// } -// } -// // coin back -// uint256_t l_value_back = {}; -// SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back); -// if (!IS_ZERO_256(l_value_back)) { -// if ((l_single_channel && -// dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) || -// (!l_single_channel && -// dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_value_back, a_price->token_sell) != 1)) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add coin back output\n"); -// return NULL; -// } -// } -// // Fee coinback -// if (!l_single_channel) { -// uint256_t l_fee_coinback = {}; -// SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback); -// if (!IS_ZERO_256(l_fee_coinback)) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add fee back output\n"); -// return NULL; -// } -// } -// } -// } -// return l_tx; -// } + return s_compose_config_return_response_handler(l_config); +} + + +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_token_buy, + const char *a_token_sell, uint256_t a_datoshi_sell, + uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, compose_config_t *a_config){ + if (!a_config) { + return NULL; + } + if ( !a_token_buy || !a_token_sell || !a_wallet) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_ARGUMENT, "Invalid parameter"); + return NULL; + } + if (IS_ZERO_256(a_rate)) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_RATE_IS_ZERO, "Invalid parameter rate"); + return NULL; + } + if (IS_ZERO_256(a_fee)) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_FEE_IS_ZERO, "Invalid parameter fee"); + return NULL; + } + if (IS_ZERO_256(a_datoshi_sell)) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_VALUE_SELL_IS_ZERO, "Invalid parameter value sell"); + return NULL; + } + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_config->net_name); + json_object *l_json_coins = dap_request_command_to_rpc(data, a_config); + if (!l_json_coins) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_GET_TX_OUTS, "Can't get tx outs"); + return NULL; + } + if (!check_token_in_ledger(l_json_coins, a_token_sell) || !check_token_in_ledger(l_json_coins, a_token_buy)) { + json_object_put(l_json_coins); + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_TOKEN_TICKER_SELL_OR_BUY_IS_NOT_FOUND_LEDGER, "Token ticker sell or buy is not found in ledger"); + return NULL; + } + json_object_put(l_json_coins); + dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_config->net_name)); + snprintf(data, sizeof(data), + "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", + dap_chain_addr_to_str(l_wallet_addr), a_config->net_name); + DAP_DEL_Z(l_wallet_addr); + json_object *l_json_outs = dap_request_command_to_rpc(data, a_config); + uint256_t l_value = get_balance_from_json(l_json_outs, a_token_sell); + + uint256_t l_value_sell = a_datoshi_sell; + if (!dap_strcmp(s_get_native_ticker(a_config->net_name), a_token_sell)) { + if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE, "Integer overflow with sum of value and fee"); + return NULL; + } + } else { // sell non-native ticker + uint256_t l_fee_value = get_balance_from_json(l_json_outs, s_get_native_ticker(a_config->net_name)); + if (compare256(l_fee_value, a_fee) == -1) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET, "Not enough cash for fee in specified wallet"); + return NULL; + } + } + if (compare256(l_value, l_value_sell) == -1) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET, "Not enough cash in specified wallet"); + return NULL; + } + // Create the price + dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); + if (!l_price) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_MEMORY_ALLOCATED, "Memory allocated"); + return NULL; + } + dap_stpcpy(l_price->token_sell, a_token_sell); + dap_stpcpy(l_price->token_buy, a_token_buy); + l_price->datoshi_sell = a_datoshi_sell; + l_price->rate = a_rate; + l_price->fee = a_fee; + dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_request_compose(l_price, a_wallet, s_get_native_ticker(a_config->net_name), a_config); + return l_tx; +} + + + +dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, + const char *a_native_ticker, compose_config_t *a_config) +{ + if (!a_config) { + return NULL; + } + if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_INVALID_ARGUMENT, "Invalid parameter"); + return NULL; + } + const char *l_native_ticker = s_get_native_ticker(a_config->net_name); + bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker); + // find the transactions from which to take away coins + uint256_t l_value_transfer; // how many coins to transfer + uint256_t l_value_need = a_price->datoshi_sell, + l_net_fee, + l_total_fee = a_price->fee, + l_fee_transfer; + dap_chain_addr_t * l_addr_net_fee = NULL; + dap_list_t *l_list_fee_out = NULL; + + bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_net_fee, a_config); + if (l_net_fee_used) + SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); + + dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_config->net_name)); + dap_chain_addr_t l_seller_addr = *l_wallet_addr; + json_object *l_outs_native = dap_get_remote_tx_outs(a_native_ticker, l_wallet_addr, a_config); + if (!l_outs_native) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_GET_TX_OUTS, "Can't get tx outs"); + return NULL; + } + + json_object *l_outs = NULL; + if (!dap_strcmp(a_price->token_sell, a_native_ticker)) { + l_outs = l_outs_native; + } else { + l_outs = dap_get_remote_tx_outs(a_price->token_sell, l_wallet_addr, a_config); + } + DAP_DELETE(l_wallet_addr); + int l_out_native_count = json_object_array_length(l_outs_native); + int l_out_count = json_object_array_length(l_outs); + + if (l_single_channel) + SUM_256_256(l_value_need, l_total_fee, &l_value_need); + else if (!IS_ZERO_256(l_total_fee)) { + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, + l_total_fee, + &l_fee_transfer); + if (!l_list_fee_out) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS_TO_PAY_FEE, "Not enough funds to pay fee"); + json_object_put(l_outs_native); + json_object_put(l_outs); + return NULL; + } + } + dap_list_t *l_list_used_out = NULL; + l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_out_count, + l_value_need, + &l_value_transfer); + if (!l_list_used_out) { + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS_TO_TRANSFER, "Not enough funds to transfer"); + json_object_put(l_outs_native); + json_object_put(l_outs); + return NULL; + } + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // add 'in' items to sell + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + dap_list_free_full(l_list_used_out, NULL); + if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_COMPOSE_THE_TRANSACTION_INPUT, "Can't compose the transaction input"); + return NULL; + } + if (!l_single_channel) { + // add 'in' items to fee + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_COMPOSE_THE_TRANSACTION_INPUT, "Can't compose the transaction input"); + return NULL; + } + } + + // add 'out_cond' & 'out' items + + { + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID }; + dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(l_uid, s_get_net_id(a_config->net_name), a_price->datoshi_sell, + s_get_net_id(a_config->net_name), a_price->token_buy, a_price->rate, + &l_seller_addr, NULL, 0); + if (!l_tx_out) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_COMPOSE_THE_TRANSACTION_CONDITIONAL_OUTPUT, "Can't compose the transaction conditional output"); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); + DAP_DELETE(l_tx_out); + // Network fee + if (l_net_fee_used) { + if ((l_single_channel && + dap_chain_datum_tx_add_out_item(&l_tx, l_addr_net_fee, l_net_fee) != 1) || + (!l_single_channel && + dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_NETWORK_FEE_OUTPUT, "Can't add network fee output"); + return NULL; + } + } + DAP_DELETE(l_addr_net_fee); + // Validator's fee + if (!IS_ZERO_256(a_price->fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_VALIDATOR_FEE_OUTPUT, "Can't add validator's fee output"); + return NULL; + } + } + // coin back + uint256_t l_value_back = {}; + SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if ((l_single_channel && + dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) || + (!l_single_channel && + dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_value_back, a_price->token_sell) != 1)) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_COIN_BACK_OUTPUT, "Can't add coin back output"); + return NULL; + } + } + // Fee coinback + if (!l_single_channel) { + uint256_t l_fee_coinback = {}; + SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback); + if (!IS_ZERO_256(l_fee_coinback)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_XCHANGE_COMPOSE_ERROR_CAN_NOT_ADD_FEE_BACK_OUTPUT, "Can't add fee back output"); + return NULL; + } + } + } + } + return l_tx; +} // // tx_cond_create -net <net_name> -token <token_ticker> -w <wallet_name> -cert <pub_cert_name> -value <value_datoshi> -fee <value> -unit {B | SEC} -srv_uid <numeric_uid> // int dap_tx_cond_create_compose(int argc, char ** argv) @@ -4013,7 +3996,7 @@ static dap_chain_datum_tx_t *dap_order_tx_create_compose(dap_enc_key_t *a_key, } -json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) { +json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) { compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port); if (!l_config) { json_object *l_json_obj_ret = json_object_new_object(); @@ -4076,7 +4059,7 @@ json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str return s_compose_config_return_response_handler(l_config); } -json_object * dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port) { +json_object * dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) { compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port); if (!l_config) { diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 7c6203532d..fcca731a13 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -68,8 +68,8 @@ extern "C" { const char* dap_compose_get_net_url(const char* name); uint16_t dap_compose_get_net_port(const char* name); -json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port); -int dap_tx_create_xchange_compose(int argc, char ** argv); +json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port); +json_object* dap_tx_create_xchange_compose(const char *l_net_str, const char *l_token_sell, const char *l_token_buy, const char *l_wallet_str, const char *l_wallet_path, const char *l_value_str, const char *l_rate_str, const char *l_fee_str, const char *l_url_str, uint16_t l_port); int dap_tx_cond_create_compose(int argc, char ** argv); int dap_cli_hold_compose(int a_argc, char **a_argv); int dap_cli_take_compose(int a_argc, char **a_argv); @@ -86,7 +86,7 @@ typedef enum { STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -8, STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -9 } dap_cli_srv_stake_order_create_staker_error_t; -json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port); +json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port); typedef enum { SRV_STAKE_ORDER_REMOVE_COMPOSE_OK = 0, @@ -124,7 +124,7 @@ typedef enum { } srv_stake_order_remove_compose_error_t; dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(dap_hash_fast_t *a_hash_tx, uint256_t a_fee, dap_chain_wallet_t *a_wallet, compose_config_t *a_config); -json_object* dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, int l_port); +json_object* dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port); typedef enum { STAKE_DELEGATE_COMPOSE_OK = 0, @@ -218,10 +218,10 @@ int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); dap_list_t *dap_ledger_get_list_tx_outs_from_json(json_object * a_outputs_array, int a_outputs_count, uint256_t a_value_need, uint256_t *a_value_transfer); dap_chain_datum_tx_t *dap_chain_datum_tx_create_compose(dap_chain_addr_t* a_addr_from, dap_chain_addr_t** a_addr_to, const char* a_token_ticker, uint256_t *a_value, uint256_t a_value_fee, size_t a_tx_num, compose_config_t *a_config); -dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_net_name, const char *a_token_buy, const char *a_token_sell, uint256_t a_datoshi_sell, - uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, const char * a_url_str, uint16_t a_port); +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_token_buy, const char *a_token_sell, uint256_t a_datoshi_sell, + uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, compose_config_t *a_config); dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, - const char *a_native_ticker, const char *a_net_name, const char * a_url_str, uint16_t a_port); + const char *a_native_ticker, compose_config_t *a_config); dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name, dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], -- GitLab From b52a5e93f425309f3a5b9cd38a4bafa78fe437a4 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Mon, 14 Apr 2025 14:47:25 +0700 Subject: [PATCH 49/53] [*] hold tx_cond --- modules/compose/dap_chain_tx_compose.c | 1045 ++++++++--------- .../compose/include/dap_chain_tx_compose.h | 30 +- 2 files changed, 488 insertions(+), 587 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 2349aa5e5d..ad09be62ec 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -1315,640 +1315,525 @@ dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xc return l_tx; } -// // tx_cond_create -net <net_name> -token <token_ticker> -w <wallet_name> -cert <pub_cert_name> -value <value_datoshi> -fee <value> -unit {B | SEC} -srv_uid <numeric_uid> -// int dap_tx_cond_create_compose(int argc, char ** argv) -// { -// int arg_index = 1; -// const char * l_token_ticker = NULL; -// const char * l_wallet_str = NULL; -// const char * l_cert_str = NULL; -// const char * l_value_datoshi_str = NULL; -// const char * l_value_fee_str = NULL; -// const char * l_net_name = NULL; -// const char * l_unit_str = NULL; -// const char * l_srv_uid_str = NULL; -// uint256_t l_value_datoshi = {}; -// uint256_t l_value_fee = {}; -// const char * l_url_str = NULL; -// const char * l_port_str = NULL; -// uint16_t l_port = 0; - -// const char *l_wallet_path = NULL; -// dap_cli_server_cmd_find_option_val(argv, 1, argc, "-wallet_path", &l_wallet_path); -// if (!l_wallet_path) { -// l_wallet_path = -// #ifdef DAP_OS_WINDOWS -// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); -// #elif defined DAP_OS_MAC -// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); -// #elif defined DAP_OS_UNIX -// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); -// #endif -// } - -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value_datoshi_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_value_fee_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-url", &l_url_str); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-port", &l_port_str); -// if(!l_token_ticker) { -// printf("tx_cond_create requires parameter '-token'\n"); -// return -2; -// } -// if (!l_wallet_str) { -// printf("tx_cond_create requires parameter '-w'\n"); -// return -3; -// } -// if (!l_cert_str) { -// printf("tx_cond_create requires parameter '-cert'\n"); -// return -4; -// } -// if(!l_value_datoshi_str) { -// printf("tx_cond_create requires parameter '-value'\n"); -// return -5; -// } -// if(!l_value_fee_str){ -// printf("tx_cond_create requires parameter '-fee'\n"); -// return -6; -// } -// if(!l_net_name) { -// printf("tx_cond_create requires parameter '-net'\n"); -// return -7; -// } -// if(!l_url_str) { -// l_url_str = dap_compose_get_net_url(l_net_name); -// } -// if(!l_port_str) { -// l_port = dap_compose_get_net_port(l_net_name); -// } else { -// l_port = atoi(l_port_str); -// } -// if(!l_unit_str) { -// printf("tx_cond_create requires parameter '-unit'\n"); -// return -8; -// } - -// if(!l_srv_uid_str) { -// printf("tx_cond_create requires parameter '-srv_uid'\n"); -// return -9; -// } -// dap_chain_net_srv_uid_t l_srv_uid = {}; -// l_srv_uid.uint64 = strtoll(l_srv_uid_str, NULL, 10); -// if (!l_srv_uid.uint64) { -// printf("Can't find service UID %s\n", l_srv_uid_str); -// return -10; -// } - -// dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)l_unit_str)}; - -// if(l_price_unit.enm == SERV_UNIT_UNDEFINED) { -// printf("Can't recognize unit '%s'. Unit must look like { B | SEC }\n", l_unit_str); -// return -11; -// } - -// l_value_datoshi = dap_chain_balance_scan(l_value_datoshi_str); -// if(IS_ZERO_256(l_value_datoshi)) { -// printf("Can't recognize value '%s' as a number\n", l_value_datoshi_str); -// return -12; -// } - -// l_value_fee = dap_chain_balance_scan(l_value_fee_str); -// if(IS_ZERO_256(l_value_fee)) { -// printf("Can't recognize value '%s' as a number\n", l_value_fee_str); -// return -13; -// } - -// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); -// if(!l_wallet) { -// printf("Can't open wallet '%s'\n", l_wallet_str); -// return -15; -// } - -// dap_cert_t *l_cert_cond = dap_cert_find_by_name(l_cert_str); -// if(!l_cert_cond) { -// dap_chain_wallet_close(l_wallet); -// printf("Can't find cert '%s'\n", l_cert_str); -// return -16; -// } - -// dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet, 0); -// dap_pkey_t *l_key_cond = dap_pkey_from_enc_key(l_cert_cond->enc_key); -// if (!l_key_cond) { -// dap_chain_wallet_close(l_wallet); -// dap_enc_key_delete(l_key_from); -// printf("Cert '%s' doesn't contain a valid public key\n", l_cert_str); -// return -17; -// } - -// uint256_t l_value_per_unit_max = {}; -// dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_net_name, l_key_from, l_key_cond, l_token_ticker, -// l_value_datoshi, l_value_per_unit_max, l_price_unit, -// l_srv_uid, l_value_fee, NULL, 0, l_url_str, l_port); +json_object* dap_tx_cond_create_compose(const char *a_net_name, const char *a_token_ticker, const char *a_wallet_str, const char *a_wallet_path, + const char *a_cert_str, const char *a_value_datoshi_str, const char *a_value_fee_str, const char *a_unit_str, + const char *a_srv_uid_str, const char *a_url_str, uint16_t a_port) { + compose_config_t *l_config = s_compose_config_init(a_net_name, a_url_str, a_port); + if (!l_config) { + json_object* l_json_obj_ret = json_object_new_object(); + dap_json_compose_error_add(l_json_obj_ret, TX_COND_CREATE_COMPOSE_ERROR_INVALID_FEE, "Can't create compose config"); + return l_json_obj_ret; + } -// json_object * l_json_obj_ret = json_object_new_object(); -// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); -// printf("%s", json_object_to_json_string(l_json_obj_ret)); -// json_object_put(l_json_obj_ret); -// dap_chain_datum_tx_delete(l_tx); -// dap_chain_wallet_close(l_wallet); -// dap_enc_key_delete(l_key_from); -// DAP_DELETE(l_key_cond); -// return 0; -// } + uint256_t l_value_datoshi = {}; + uint256_t l_value_fee = {}; + dap_chain_net_srv_uid_t l_srv_uid = {}; + l_srv_uid.uint64 = strtoll(a_srv_uid_str, NULL, 10); + if (!l_srv_uid.uint64) { + dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_INVALID_SERVICE_UID, "Can't find service UID %s", a_srv_uid_str); + return s_compose_config_return_response_handler(l_config); + } + dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)a_unit_str)}; -// dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name, -// dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, -// const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], -// uint256_t a_value, uint256_t a_value_per_unit_max, -// dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, -// uint256_t a_value_fee, const void *a_cond, -// size_t a_cond_size, const char *a_url_str, uint16_t a_port) -// { -// // check valid param -// if (!a_net_name || !*a_net_name || !a_key_from || !a_key_cond || -// !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value) || !a_url_str || !*a_url_str || a_port == 0) -// return NULL; + if(l_price_unit.enm == SERV_UNIT_UNDEFINED) { + dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_INVALID_UNIT, "Can't recognize unit '%s'. Unit must look like { B | SEC }\n", a_unit_str); + return s_compose_config_return_response_handler(l_config); + } -// if (dap_strcmp(s_get_native_ticker(a_net_name), a_token_ticker)) { -// printf("Pay for service should be only in native token ticker\n"); -// return NULL; -// } + l_value_datoshi = dap_chain_balance_scan(a_value_datoshi_str); + if(IS_ZERO_256(l_value_datoshi)) { + dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_INVALID_VALUE, "Can't recognize value '%s' as a number\n", a_value_datoshi_str); + return s_compose_config_return_response_handler(l_config); + } -// uint256_t l_net_fee = {}; -// dap_chain_addr_t* l_addr_fee = NULL; -// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, a_url_str, a_port); -// // find the transactions from which to take away coins -// uint256_t l_value_transfer = {}; // how many coins to transfer -// uint256_t l_value_need = {}; -// SUM_256_256(a_value, a_value_fee, &l_value_need); -// if (l_net_fee_used) { -// SUM_256_256(l_value_need, l_net_fee, &l_value_need); -// } -// // where to take coins for service -// dap_chain_addr_t l_addr_from; -// dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, s_get_net_id(a_net_name)); -// // list of transaction with 'out' items -// json_object *l_outs = NULL; -// int l_outputs_count = 0; -// if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, a_net_name, &l_outs, &l_outputs_count, a_url_str, a_port)) { -// return NULL; -// } -// dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, -// l_value_need, -// &l_value_transfer); -// json_object_put(l_outs); -// if(!l_list_used_out) { -// printf("Nothing to transfer (not enough funds)\n"); -// return NULL; -// } + l_value_fee = dap_chain_balance_scan(a_value_fee_str); + if(IS_ZERO_256(l_value_fee)) { + dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_INVALID_VALUE, "Can't recognize value '%s' as a number\n", a_value_fee_str); + return s_compose_config_return_response_handler(l_config); + } -// // create empty transaction -// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); -// // add 'in' items -// { -// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); -// assert(EQUAL_256(l_value_to_items, l_value_transfer)); -// dap_list_free_full(l_list_used_out, NULL); -// } -// // add 'out_cond' and 'out' items -// { -// uint256_t l_value_pack = {}; // how much coin add to 'out' items -// if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond, -// a_cond_size) == 1) { -// SUM_256_256(l_value_pack, a_value, &l_value_pack); -// } else { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add conditional output\n"); -// return NULL; -// } -// // Network fee -// if (l_net_fee_used) { -// if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) -// SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); -// else { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// // Validator's fee -// if (!IS_ZERO_256(a_value_fee)) { -// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) -// SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); -// else { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// // coin back -// uint256_t l_value_back = {}; -// SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); -// if (!IS_ZERO_256(l_value_back)) { -// if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Cant add coin back output\n"); -// return NULL; -// } -// } -// } + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path, NULL); + if(!l_wallet) { + dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_WALLET_OPEN_FAILED, "Can't open wallet '%s'\n", a_wallet_str); + return s_compose_config_return_response_handler(l_config); + } -// return l_tx; -// } + dap_cert_t *l_cert_cond = dap_cert_find_by_name(a_cert_str); + if(!l_cert_cond) { + dap_chain_wallet_close(l_wallet); + dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_CERT_NOT_FOUND, "Can't find cert '%s'\n", a_cert_str); + return s_compose_config_return_response_handler(l_config); + } -// // stake_lock hold -net <net_name> -w <wallet_name> -time_staking <YYMMDD> -token <ticker> -value <value> -fee <value>[-chain <chain_name>] [-reinvest <percentage>] -// int dap_cli_hold_compose(int a_argc, char **a_argv) -// { -// int arg_index = 1; -// const char *l_net_name = NULL, *l_ticker_str = NULL, *l_coins_str = NULL, -// *l_wallet_str = NULL, *l_cert_str = NULL, *l_chain_id_str = NULL, -// *l_time_staking_str = NULL, *l_reinvest_percent_str = NULL, *l_value_fee_str = NULL; - -// char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; -// dap_time_t l_time_staking = 0; -// uint256_t l_reinvest_percent = {}; -// uint256_t l_value_delegated = {}; -// uint256_t l_value_fee = {}; -// uint256_t l_value; -// dap_enc_key_t *l_key_from; -// dap_chain_wallet_t *l_wallet; -// dap_chain_addr_t *l_addr_holder; -// const char *l_url_str = NULL; -// uint16_t l_port = 0; + dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet, 0); + dap_pkey_t *l_key_cond = dap_pkey_from_enc_key(l_cert_cond->enc_key); + if (!l_key_cond) { + dap_chain_wallet_close(l_wallet); + dap_enc_key_delete(l_key_from); + dap_json_compose_error_add(l_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_INVALID_CERT_KEY, "Cert '%s' doesn't contain a valid public key\n", a_cert_str); + return s_compose_config_return_response_handler(l_config); + } -// const char *l_wallet_path = NULL; -// dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); -// if (!l_wallet_path) { -// l_wallet_path = -// #ifdef DAP_OS_WINDOWS -// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); -// #elif defined DAP_OS_MAC -// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); -// #elif defined DAP_OS_UNIX -// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); -// #endif -// } + uint256_t l_value_per_unit_max = {}; + dap_chain_datum_tx_t *l_tx = dap_chain_mempool_tx_create_cond_compose(l_key_from, l_key_cond, a_token_ticker, + l_value_datoshi, l_value_per_unit_max, l_price_unit, + l_srv_uid, l_value_fee, NULL, 0, l_config); + if (l_tx) { + dap_chain_net_tx_to_json(l_tx, l_config->response_handler); + dap_chain_datum_tx_delete(l_tx); + } + dap_chain_wallet_close(l_wallet); + dap_enc_key_delete(l_key_from); + DAP_DELETE(l_key_cond); + return s_compose_config_return_response_handler(l_config); +} -// const char *l_hash_out_type = NULL; -// dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); -// if(!l_hash_out_type) -// l_hash_out_type = "hex"; -// if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type, "base58")) { -// printf("Error: Invalid hash type argument\n"); -// return -1; -// } +dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, + const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], + uint256_t a_value, uint256_t a_value_per_unit_max, + dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, + uint256_t a_value_fee, const void *a_cond, + size_t a_cond_size, compose_config_t *a_config) +{ + // check valid param + if (!a_config->net_name || !*a_config->net_name || !a_key_from || !a_key_cond || + !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value) || !a_config->url_str || !*a_config->url_str || a_config->port == 0) + return NULL; -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_name) || NULL == l_net_name) { -// printf("Error: Missing or invalid network argument\n"); -// return -2; -// } + if (dap_strcmp(s_get_native_ticker(a_config->net_name), a_token_ticker)) { + dap_json_compose_error_add(a_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_NATIVE_TOKEN_REQUIRED, "Pay for service should be only in native token ticker\n"); + return NULL; + } -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_ticker_str) || NULL == l_ticker_str || dap_strlen(l_ticker_str) > 8) { -// printf("Error: Missing or invalid token argument\n"); -// return -3; -// } + uint256_t l_net_fee = {}; + dap_chain_addr_t* l_addr_fee = NULL; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, a_config); + // find the transactions from which to take away coins + uint256_t l_value_transfer = {}; // how many coins to transfer + uint256_t l_value_need = {}; + SUM_256_256(a_value, a_value_fee, &l_value_need); + if (l_net_fee_used) { + SUM_256_256(l_value_need, l_net_fee, &l_value_need); + } + // where to take coins for service + dap_chain_addr_t l_addr_from; + dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, s_get_net_id(a_config->net_name)); + // list of transaction with 'out' items + json_object *l_outs = NULL; + int l_outputs_count = 0; + if (!dap_get_remote_wallet_outs_and_count(&l_addr_from, a_token_ticker, &l_outs, &l_outputs_count, a_config)) { + return NULL; + } + dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_value_need, + &l_value_transfer); + json_object_put(l_outs); + if(!l_list_used_out) { + dap_json_compose_error_add(a_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS, "Nothing to transfer (not enough funds)\n"); + return NULL; + } -// if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) { -// l_url_str = dap_compose_get_net_url(l_net_name); -// } + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // add 'in' items + { + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + } + // add 'out_cond' and 'out' items + { + uint256_t l_value_pack = {}; // how much coin add to 'out' items + if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond, + a_cond_size) == 1) { + SUM_256_256(l_value_pack, a_value, &l_value_pack); + } else { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_COND_OUTPUT_FAILED, "Cant add conditional output\n"); + return NULL; + } + // Network fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) + SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) + SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // coin back + uint256_t l_value_back = {}; + SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_COND_CREATE_COMPOSE_ERROR_COIN_BACK_FAILED, "Cant add coin back output\n"); + return NULL; + } + } + } -// const char *l_port_str = NULL; -// if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) { -// l_port = dap_compose_get_net_port(l_net_name); -// } else { -// l_port = atoi(l_port_str); -// } + return l_tx; +} -// char data[512]; -// snprintf(data, sizeof(data), -// "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_name); -// json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port); -// if (!l_json_coins) { -// return -4; -// } -// if (!check_token_in_ledger(l_json_coins, l_ticker_str)) { -// printf("Error: Invalid token '%s'\n", l_ticker_str); -// return -4; -// } +enum cli_hold_compose_error { + CLI_HOLD_COMPOSE_ERROR_INVALID_CONFIG = -1, + CLI_HOLD_COMPOSE_ERROR_INVALID_TOKEN = -2, + CLI_HOLD_COMPOSE_ERROR_INVALID_COINS = -3, + CLI_HOLD_COMPOSE_ERROR_NO_DELEGATED_TOKEN = -4, + CLI_HOLD_COMPOSE_ERROR_INVALID_EMISSION_RATE = -5, + CLI_HOLD_COMPOSE_ERROR_INVALID_COINS_FORMAT = -6, + CLI_HOLD_COMPOSE_ERROR_INVALID_FEE = -7, + CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING = -8, + CLI_HOLD_COMPOSE_ERROR_INVALID_REINVEST_PERCENTAGE = -9, + CLI_HOLD_COMPOSE_ERROR_UNABLE_TO_OPEN_WALLET = -10, + CLI_HOLD_COMPOSE_ERROR_UNABLE_TO_GET_WALLET_ADDRESS = -11, + CLI_HOLD_COMPOSE_ERROR_INSUFFICIENT_FUNDS = -12 +}; -// if ((!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-coins", &l_coins_str) || NULL == l_coins_str) && -// (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-value", &l_coins_str) || NULL == l_coins_str)) { -// printf("Error: Missing coins or value argument\n"); -// return -5; -// } +json_object * dap_cli_hold_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_ticker_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_coins_str, const char *a_time_staking_str, + const char *a_cert_str, const char *a_value_fee_str, const char *a_reinvest_percent_str, const char *a_url_str, uint16_t a_port) { + + compose_config_t *l_config = s_compose_config_init(a_net_name, a_url_str, a_port); + if (!l_config) { + json_object* l_json_obj_ret = json_object_new_object(); + dap_json_compose_error_add(l_json_obj_ret, CLI_HOLD_COMPOSE_ERROR_INVALID_CONFIG, "Can't create compose config"); + return l_json_obj_ret; + } + + char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; + dap_enc_key_t *l_key_from; + dap_chain_wallet_t *l_wallet; + dap_chain_addr_t *l_addr_holder; + dap_time_t l_time_staking = 0; + uint256_t l_reinvest_percent = {}; + uint256_t l_value_delegated = {}; + uint256_t l_value_fee = {}; + uint256_t l_value = {}; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_config->net_name); + json_object *l_json_coins = dap_request_command_to_rpc(data, l_config); + if (!l_json_coins) { + return s_compose_config_return_response_handler(l_config); + } + if (!check_token_in_ledger(l_json_coins, a_ticker_str)) { + json_object_put(l_json_coins); + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TOKEN, "Invalid token '%s'\n", a_ticker_str); + return s_compose_config_return_response_handler(l_config); + } -// if (IS_ZERO_256((l_value = dap_chain_balance_scan(l_coins_str)))) { -// printf("Error: Invalid coins format\n"); -// return -6; -// } -// dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str); + if (IS_ZERO_256((l_value = dap_chain_balance_scan(a_coins_str)))) { + json_object_put(l_json_coins); + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_COINS, "Invalid coins format\n"); + return s_compose_config_return_response_handler(l_config); + } + + dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, a_ticker_str); -// if (!check_token_in_ledger(l_json_coins, l_delegated_ticker_str)) { -// printf("Error: No delegated token found\n"); -// return -7; -// } -// json_object_put(l_json_coins); + if (!check_token_in_ledger(l_json_coins, l_delegated_ticker_str)) { + json_object_put(l_json_coins); + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_NO_DELEGATED_TOKEN, "No delegated token found\n"); + return s_compose_config_return_response_handler(l_config); + } + json_object_put(l_json_coins); -// uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001"); // TODO 16126 -// // uint256_t l_emission_rate = dap_ledger_token_get_emission_rate(l_ledger, l_delegated_ticker_str); -// // if (IS_ZERO_256(l_emission_rate)) { -// // printf("Error: Invalid token emission rate\n"); -// // return -8; -// // } + uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001"); // TODO 16126 + // uint256_t l_emission_rate = dap_ledger_token_get_emission_rate(l_ledger, l_delegated_ticker_str); + // if (IS_ZERO_256(l_emission_rate)) { + // printf("Error: Invalid token emission rate\n"); + // return -8; + // } -// if (MULT_256_COIN(l_value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) { -// printf("Error: Invalid coins format\n"); -// return -9; -// } + if (MULT_256_COIN(l_value, l_emission_rate, &l_value_delegated) || IS_ZERO_256(l_value_delegated)) { + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_EMISSION_RATE, "Invalid coins format\n"); + return s_compose_config_return_response_handler(l_config); + } -// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str); -// if (!l_chain_id_str) { -// printf("Error: Missing or invalid chain_id argument\n"); -// return -10; -// } -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) { -// printf("Error: Missing wallet argument\n"); -// return -11; -// } + if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(a_value_fee_str)))) { + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_FEE, "Invalid fee format\n"); + return s_compose_config_return_response_handler(l_config); + } -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) { -// printf("Error: Missing fee argument\n"); -// return -12; -// } + // Read time staking -// if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) { -// printf("Error: Invalid fee format\n"); -// return -13; -// } -// // Read time staking -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-time_staking", &l_time_staking_str) || !l_time_staking_str) { -// printf("Error: Missing time staking argument\n"); -// return -14; -// } + if (dap_strlen(a_time_staking_str) != 6) { + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING, "Invalid time staking format\n"); + return s_compose_config_return_response_handler(l_config); + } -// if (dap_strlen(l_time_staking_str) != 6) { -// printf("Error: Invalid time staking format\n"); -// return -15; -// } + char l_time_staking_month_str[3] = {a_time_staking_str[2], a_time_staking_str[3], 0}; + int l_time_staking_month = atoi(l_time_staking_month_str); + if (l_time_staking_month < 1 || l_time_staking_month > 12) { + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING, "Invalid time staking month\n"); + return s_compose_config_return_response_handler(l_config); + } -// char l_time_staking_month_str[3] = {l_time_staking_str[2], l_time_staking_str[3], 0}; -// int l_time_staking_month = atoi(l_time_staking_month_str); -// if (l_time_staking_month < 1 || l_time_staking_month > 12) { -// printf("Error: Invalid time staking month\n"); -// return -16; -// } + char l_time_staking_day_str[3] = {a_time_staking_str[4], a_time_staking_str[5], 0}; + int l_time_staking_day = atoi(l_time_staking_day_str); + if (l_time_staking_day < 1 || l_time_staking_day > 31) { + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING, "Invalid time staking day\n"); + return s_compose_config_return_response_handler(l_config); + } -// char l_time_staking_day_str[3] = {l_time_staking_str[4], l_time_staking_str[5], 0}; -// int l_time_staking_day = atoi(l_time_staking_day_str); -// if (l_time_staking_day < 1 || l_time_staking_day > 31) { -// printf("Error: Invalid time staking day\n"); -// return -17; -// } + l_time_staking = dap_time_from_str_simplified(a_time_staking_str); + if (0 == l_time_staking) { + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING, "Invalid time staking\n"); + return s_compose_config_return_response_handler(l_config); + } + dap_time_t l_time_now = dap_time_now(); + if (l_time_staking < l_time_now) { + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_TIME_STAKING, "Time staking is in the past\n"); + return s_compose_config_return_response_handler(l_config); + } + l_time_staking -= l_time_now; -// l_time_staking = dap_time_from_str_simplified(l_time_staking_str); -// if (0 == l_time_staking) { -// printf("Error: Invalid time staking\n"); -// return -18; -// } -// dap_time_t l_time_now = dap_time_now(); -// if (l_time_staking < l_time_now) { -// printf("Error: Time staking is in the past\n"); -// return -19; -// } -// l_time_staking -= l_time_now; + if ( NULL != a_reinvest_percent_str) { + l_reinvest_percent = dap_chain_coins_to_balance(a_reinvest_percent_str); + if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1) { + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_REINVEST_PERCENTAGE, "Invalid reinvest percentage\n"); + return s_compose_config_return_response_handler(l_config); + } + if (IS_ZERO_256(l_reinvest_percent)) { + int l_reinvest_percent_int = atoi(a_reinvest_percent_str); + if (l_reinvest_percent_int < 0 || l_reinvest_percent_int > 100) { + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INVALID_REINVEST_PERCENTAGE, "Invalid reinvest percentage\n"); + return s_compose_config_return_response_handler(l_config); + } + l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int); + MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent); + } + } -// if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-reinvest", &l_reinvest_percent_str) && NULL != l_reinvest_percent_str) { -// l_reinvest_percent = dap_chain_coins_to_balance(l_reinvest_percent_str); -// if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1) { -// printf("Error: Invalid reinvest percentage\n"); -// return -20; -// } -// if (IS_ZERO_256(l_reinvest_percent)) { -// int l_reinvest_percent_int = atoi(l_reinvest_percent_str); -// if (l_reinvest_percent_int < 0 || l_reinvest_percent_int > 100) { -// printf("Error: Invalid reinvest percentage\n"); -// return -21; -// } -// l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int); -// MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent); -// } -// } + if(NULL == (l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path, NULL))) { + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_UNABLE_TO_OPEN_WALLET, "Unable to open wallet '%s'\n", a_wallet_str); + return s_compose_config_return_response_handler(l_config); + } -// if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) { -// printf("Error: Unable to open wallet '%s'\n", l_wallet_str); -// return -22; -// } + if (NULL == (l_addr_holder = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(a_net_name)))) { + dap_chain_wallet_close(l_wallet); + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_UNABLE_TO_GET_WALLET_ADDRESS, "Unable to get wallet address for '%s'\n", a_wallet_str); + return s_compose_config_return_response_handler(l_config); + } -// if (NULL == (l_addr_holder = dap_chain_wallet_get_addr(l_wallet, s_get_net_id(l_net_name)))) { -// dap_chain_wallet_close(l_wallet); -// printf("Error: Unable to get wallet address for '%s'\n", l_wallet_str); -// return -24; -// } + snprintf(data, sizeof(data), + "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", + dap_chain_addr_to_str(l_addr_holder), l_config->net_name); + DAP_DEL_Z(l_addr_holder); -// snprintf(data, sizeof(data), -// "{\"method\": \"wallet\",\"params\": [\"wallet;info;-addr;%s;-net;%s\"],\"id\": \"2\"}", -// dap_chain_addr_to_str(l_addr_holder), l_net_name); -// DAP_DEL_Z(l_addr_holder); - -// json_object *l_json_outs = dap_request_command_to_rpc(data, l_net_name, l_url_str, l_port); -// uint256_t l_value_balance = get_balance_from_json(l_json_outs, l_ticker_str); -// json_object_put(l_json_outs); -// if (compare256(l_value_balance, l_value) == -1) { -// dap_chain_wallet_close(l_wallet); -// printf("Error: Insufficient funds in wallet\n"); -// return -23; -// } + json_object *l_json_outs = dap_request_command_to_rpc(data, l_config); + uint256_t l_value_balance = get_balance_from_json(l_json_outs, a_ticker_str); + json_object_put(l_json_outs); + if (compare256(l_value_balance, l_value) == -1) { + dap_chain_wallet_close(l_wallet); + dap_json_compose_error_add(l_config->response_handler, CLI_HOLD_COMPOSE_ERROR_INSUFFICIENT_FUNDS, "Insufficient funds in wallet\n"); + return s_compose_config_return_response_handler(l_config); + } -// l_key_from = dap_chain_wallet_get_key(l_wallet, 0); + l_key_from = dap_chain_wallet_get_key(l_wallet, 0); -// // Make transfer transaction -// dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_net_name, l_key_from, -// l_ticker_str, l_value, l_value_fee, -// l_time_staking, l_reinvest_percent, -// l_delegated_ticker_str, l_value_delegated, l_chain_id_str, l_url_str, l_port); + // Make transfer transaction + dap_chain_datum_tx_t *l_tx = dap_stake_lock_datum_create_compose(l_key_from, + a_ticker_str, l_value, l_value_fee, + l_time_staking, l_reinvest_percent, + l_delegated_ticker_str, l_value_delegated, a_chain_id_str, l_config); -// json_object * l_json_obj_ret = json_object_new_object(); -// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); -// printf("%s", json_object_to_json_string(l_json_obj_ret)); -// json_object_put(l_json_obj_ret); -// dap_chain_datum_tx_delete(l_tx); + dap_chain_wallet_close(l_wallet); + dap_enc_key_delete(l_key_from); + if (l_tx) { + dap_chain_net_tx_to_json(l_tx, l_config->response_handler); + dap_chain_datum_tx_delete(l_tx); + } -// dap_chain_wallet_close(l_wallet); -// dap_enc_key_delete(l_key_from); - -// return 0; -// } + return s_compose_config_return_response_handler(l_config); +} +typedef enum { + STAKE_LOCK_DATUM_CREATE_ERROR_NOT_ENOUGH_FUNDS_TO_PAY_FEE = -1, + STAKE_LOCK_DATUM_CREATE_ERROR_NOT_ENOUGH_FUNDS_TO_TRANSFER = -2, + STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_CONDITIONAL_OUTPUT = -3, + STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_NETWORK_FEE_OUTPUT = -4, + STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_VALIDATOR_FEE_OUTPUT = -5, + STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_COIN_BACK_OUTPUT_FOR_MAIN_TICKER = -6, + STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_COIN_BACK_OUTPUT_FOR_NATIVE_TICKER = -7, + STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_DELEGATED_TOKEN_EMISSION_OUTPUT = -8 +} stake_lock_datum_create_error_t; + +dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(dap_enc_key_t *a_key_from, + const char *a_main_ticker, + uint256_t a_value, uint256_t a_value_fee, + dap_time_t a_time_staking, uint256_t a_reinvest_percent, + const char *a_delegated_ticker_str, uint256_t a_delegated_value, + const char * a_chain_id_str, compose_config_t *a_config) +{ + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID }; + // check valid param + if (!a_config->net_name || !a_key_from || + !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value)) + return NULL; -// dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, -// const char *a_main_ticker, -// uint256_t a_value, uint256_t a_value_fee, -// dap_time_t a_time_staking, uint256_t a_reinvest_percent, -// const char *a_delegated_ticker_str, uint256_t a_delegated_value, -// const char * l_chain_id_str, const char *l_url_str, uint16_t l_port) -// { -// dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID }; -// // check valid param -// if (!a_net_name || !a_key_from || -// !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value)) -// return NULL; + const char *l_native_ticker = s_get_native_ticker(a_config->net_name); + bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker); + // find the transactions from which to take away coins + uint256_t l_value_transfer = {}; // how many coins to transfer + uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {}; + dap_chain_addr_t * l_addr_fee = NULL; + dap_chain_addr_t l_addr = {}; -// const char *l_native_ticker = s_get_native_ticker(a_net_name); -// bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker); -// // find the transactions from which to take away coins -// uint256_t l_value_transfer = {}; // how many coins to transfer -// uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {}; -// dap_chain_addr_t * l_addr_fee = NULL; -// dap_chain_addr_t l_addr = {}; + dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_config->net_name)); + bool l_net_fee_used = dap_get_remote_net_fee_and_address( &l_net_fee, &l_addr_fee, a_config); + SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); -// dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name)); -// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port); -// SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); + json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, &l_addr, a_config); + if (!l_outs_native) { + return NULL; + } -// json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port); -// if (!l_outs_native) { -// return NULL; -// } + json_object *l_outs_main = NULL; + if (!dap_strcmp(a_main_ticker, l_native_ticker)) { + l_outs_main = l_outs_native; + } else { + l_outs_main = dap_get_remote_tx_outs(a_main_ticker, &l_addr, a_config); + } + int l_out_native_count = json_object_array_length(l_outs_native); + int l_out_main_count = json_object_array_length(l_outs_main); -// json_object *l_outs_main = NULL; -// if (!dap_strcmp(a_main_ticker, l_native_ticker)) { -// l_outs_main = l_outs_native; -// } else { -// l_outs_main = dap_get_remote_tx_outs(a_main_ticker, a_net_name, &l_addr, l_url_str, l_port); -// } -// int l_out_native_count = json_object_array_length(l_outs_native); -// int l_out_main_count = json_object_array_length(l_outs_main); - -// dap_list_t *l_list_fee_out = NULL; -// if (l_main_native) -// SUM_256_256(l_value_need, l_total_fee, &l_value_need); -// else if (!IS_ZERO_256(l_total_fee)) { -// l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, -// l_total_fee, -// &l_fee_transfer); -// if (!l_list_fee_out) { -// printf("Not enough funds to pay fee"); -// json_object_put(l_outs_native); -// json_object_put(l_outs_main); -// return NULL; -// } -// } -// // list of transaction with 'out' items -// dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_main, l_out_main_count, -// l_value_need, -// &l_value_transfer); -// if (!l_list_used_out) { -// printf("Not enough funds to transfer"); -// json_object_put(l_outs_native); -// json_object_put(l_outs_main); -// return NULL; -// } + dap_list_t *l_list_fee_out = NULL; + if (l_main_native) + SUM_256_256(l_value_need, l_total_fee, &l_value_need); + else if (!IS_ZERO_256(l_total_fee)) { + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, + l_total_fee, + &l_fee_transfer); + if (!l_list_fee_out) { + dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_NOT_ENOUGH_FUNDS_TO_PAY_FEE, "Not enough funds to pay fee"); + json_object_put(l_outs_native); + json_object_put(l_outs_main); + return NULL; + } + } + // list of transaction with 'out' items + dap_list_t * l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_main, l_out_main_count, + l_value_need, + &l_value_transfer); + if (!l_list_used_out) { + dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_NOT_ENOUGH_FUNDS_TO_TRANSFER, "Not enough funds to transfer"); + json_object_put(l_outs_native); + json_object_put(l_outs_main); + return NULL; + } -// // create empty transaction -// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); -// // add 'in' items -// { -// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); -// assert(EQUAL_256(l_value_to_items, l_value_transfer)); -// dap_list_free_full(l_list_used_out, NULL); -// if (l_list_fee_out) { -// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); -// assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); -// dap_list_free_full(l_list_fee_out, NULL); -// } -// } + // add 'in' items + { + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + if (l_list_fee_out) { + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); + dap_list_free_full(l_list_fee_out, NULL); + } + } -// // add 'in_ems' item -// { -// dap_chain_id_t l_chain_id = { }; -// dap_chain_id_parse(l_chain_id_str, &l_chain_id); -// dap_hash_fast_t l_blank_hash = {}; -// dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(l_chain_id, &l_blank_hash, a_delegated_ticker_str); -// dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems); -// } + // add 'in_ems' item + { + dap_chain_id_t l_chain_id = { }; + dap_chain_id_parse(a_chain_id_str, &l_chain_id); + dap_hash_fast_t l_blank_hash = {}; + dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(l_chain_id, &l_blank_hash, a_delegated_ticker_str); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems); + } -// // add 'out_cond' and 'out_ext' items -// { -// uint256_t l_value_pack = {}, l_native_pack = {}; // how much coin add to 'out_ext' items -// dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock( -// l_uid, a_value, a_time_staking, a_reinvest_percent); -// if (l_tx_out_cond) { -// SUM_256_256(l_value_pack, a_value, &l_value_pack); -// dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond); -// DAP_DEL_Z(l_tx_out_cond); -// } else { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Cant add conditional output\n"); -// return NULL; -// } + // add 'out_cond' and 'out_ext' items + { + uint256_t l_value_pack = {}, l_native_pack = {}; // how much coin add to 'out_ext' items + dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock( + l_uid, a_value, a_time_staking, a_reinvest_percent); + if (l_tx_out_cond) { + SUM_256_256(l_value_pack, a_value, &l_value_pack); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond); + DAP_DEL_Z(l_tx_out_cond); + } else { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_CONDITIONAL_OUTPUT, "Cant add conditional output\n"); + return NULL; + } -// uint256_t l_value_back = {}; -// // Network fee -// if (l_net_fee_used) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Cant add network fee output\n"); -// return NULL; -// } -// if (l_main_native) -// SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); -// else -// SUM_256_256(l_native_pack, l_net_fee, &l_native_pack); -// } -// // Validator's fee -// if (!IS_ZERO_256(a_value_fee)) { -// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Cant add validator's fee output\n"); -// return NULL; -// } -// if (l_main_native) -// SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); -// else -// SUM_256_256(l_native_pack, a_value_fee, &l_native_pack); -// } -// // coin back -// SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); -// if (!IS_ZERO_256(l_value_back)) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Cant add coin back output for main ticker\n"); -// return NULL; -// } -// } -// // fee coin back -// if (!IS_ZERO_256(l_fee_transfer)) { -// SUBTRACT_256_256(l_fee_transfer, l_native_pack, &l_value_back); -// if (!IS_ZERO_256(l_value_back)) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Cant add coin back output for native ticker\n"); -// return NULL; -// } -// } -// } -// } + uint256_t l_value_back = {}; + // Network fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_NETWORK_FEE_OUTPUT, "Cant add network fee output\n"); + return NULL; + } + if (l_main_native) + SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); + else + SUM_256_256(l_native_pack, l_net_fee, &l_native_pack); + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_VALIDATOR_FEE_OUTPUT, "Cant add validator's fee output\n"); + return NULL; + } + if (l_main_native) + SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); + else + SUM_256_256(l_native_pack, a_value_fee, &l_native_pack); + } + // coin back + SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_COIN_BACK_OUTPUT_FOR_MAIN_TICKER, "Cant add coin back output for main ticker\n"); + return NULL; + } + } + // fee coin back + if (!IS_ZERO_256(l_fee_transfer)) { + SUBTRACT_256_256(l_fee_transfer, l_native_pack, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_COIN_BACK_OUTPUT_FOR_NATIVE_TICKER, "Cant add coin back output for native ticker\n"); + return NULL; + } + } + } + } -// // add delegated token emission 'out_ext' -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_delegated_value, a_delegated_ticker_str) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Cant add delegated token emission output\n"); -// return NULL; -// } + // add delegated token emission 'out_ext' + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_delegated_value, a_delegated_ticker_str) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, STAKE_LOCK_DATUM_CREATE_ERROR_CANT_ADD_DELEGATED_TOKEN_EMISSION_OUTPUT, "Cant add delegated token emission output\n"); + return NULL; + } -// return l_tx; -// } + return l_tx; +} // int dap_cli_take_compose(int a_argc, char **a_argv) diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index fcca731a13..2328c76e0b 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -70,8 +70,25 @@ uint16_t dap_compose_get_net_port(const char* name); json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port); json_object* dap_tx_create_xchange_compose(const char *l_net_str, const char *l_token_sell, const char *l_token_buy, const char *l_wallet_str, const char *l_wallet_path, const char *l_value_str, const char *l_rate_str, const char *l_fee_str, const char *l_url_str, uint16_t l_port); -int dap_tx_cond_create_compose(int argc, char ** argv); -int dap_cli_hold_compose(int a_argc, char **a_argv); +typedef enum dap_tx_cond_create_compose_error { + TX_COND_CREATE_COMPOSE_ERROR_INVALID_FEE = 1, + TX_COND_CREATE_COMPOSE_ERROR_INVALID_SERVICE_UID, + TX_COND_CREATE_COMPOSE_ERROR_INVALID_UNIT, + TX_COND_CREATE_COMPOSE_ERROR_INVALID_VALUE, + TX_COND_CREATE_COMPOSE_ERROR_WALLET_OPEN_FAILED, + TX_COND_CREATE_COMPOSE_ERROR_CERT_NOT_FOUND, + TX_COND_CREATE_COMPOSE_ERROR_INVALID_CERT_KEY, + TX_COND_CREATE_COMPOSE_ERROR_NATIVE_TOKEN_REQUIRED, + TX_COND_CREATE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS, + TX_COND_CREATE_COMPOSE_ERROR_COND_OUTPUT_FAILED, + TX_COND_CREATE_COMPOSE_ERROR_COIN_BACK_FAILED +} dap_tx_cond_create_compose_error_t; +json_object* dap_tx_cond_create_compose(const char *a_net_name, const char *a_token_ticker, const char *a_wallet_str, const char *a_wallet_path, + const char *a_cert_str, const char *a_value_datoshi_str, const char *a_value_fee_str, const char *a_unit_str, + const char *a_srv_uid_str, const char *a_url_str, uint16_t a_port); + +json_object * dap_cli_hold_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_ticker_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_coins_str, const char *a_time_staking_str, + const char *a_cert_str, const char *a_value_fee_str, const char *a_reinvest_percent_str, const char *a_url_str, uint16_t a_port); int dap_cli_take_compose(int a_argc, char **a_argv); int dap_cli_voting_compose(int a_argc, char **a_argv); typedef enum { @@ -222,22 +239,21 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_create_compose(const char *a_tok uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, compose_config_t *a_config); dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, const char *a_native_ticker, compose_config_t *a_config); -dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(const char *a_net_name, - dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, +dap_chain_datum_tx_t *dap_chain_mempool_tx_create_cond_compose(dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond, const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX], uint256_t a_value, uint256_t a_value_per_unit_max, dap_chain_net_srv_price_unit_uid_t a_unit, dap_chain_net_srv_uid_t a_srv_uid, uint256_t a_value_fee, const void *a_cond, - size_t a_cond_size, const char *a_url_str, uint16_t a_port); + size_t a_cond_size, compose_config_t *a_config); bool dap_get_remote_net_fee_and_address(uint256_t *a_net_fee, dap_chain_addr_t **l_addr_fee, compose_config_t *a_config); bool dap_get_remote_wallet_outs_and_count(dap_chain_addr_t *a_addr_from, const char *a_token_ticker, json_object **l_outs, int *l_outputs_count, compose_config_t *a_config); -dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, +dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(dap_enc_key_t *a_key_from, const char *a_main_ticker, uint256_t a_value, uint256_t a_value_fee, dap_time_t a_time_staking, uint256_t a_reinvest_percent, const char *a_delegated_ticker_str, uint256_t a_delegated_value, - const char * l_chain_id_str, const char *l_url_str, uint16_t l_port); + const char * a_chain_id_str, compose_config_t *a_config); bool check_token_in_ledger(json_object *l_json_coins, const char *a_token); dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, -- GitLab From 68b6bc2f77c6c7a565a77ec59749b65f835f72ef Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Mon, 14 Apr 2025 16:02:15 +0700 Subject: [PATCH 50/53] [*] cli take --- modules/compose/dap_chain_tx_compose.c | 657 +++++++++--------- .../compose/include/dap_chain_tx_compose.h | 7 +- 2 files changed, 329 insertions(+), 335 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index ad09be62ec..7c60204231 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -1836,368 +1836,361 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(dap_enc_key_t *a_key_ } -// int dap_cli_take_compose(int a_argc, char **a_argv) -// { -// int arg_index = 1; -// const char *l_net_str, *l_ticker_str, *l_wallet_str, *l_tx_str, *l_tx_burning_str, *l_chain_id_str, *l_value_fee_str; -// l_net_str = l_ticker_str = l_wallet_str = l_tx_str = l_tx_burning_str = l_chain_id_str = l_value_fee_str = NULL; -// char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; -// int l_prev_cond_idx = 0; -// uint256_t l_value_delegated = {}; -// uint256_t l_value_fee = {}; -// dap_chain_wallet_t *l_wallet; -// dap_hash_fast_t l_tx_hash; -// dap_chain_tx_out_cond_t *l_cond_tx = NULL; -// dap_enc_key_t *l_owner_key; -// const char *l_url_str = NULL; -// uint16_t l_port = 0; - - -// const char *l_wallet_path = NULL; -// dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); -// if (!l_wallet_path) { -// l_wallet_path = -// #ifdef DAP_OS_WINDOWS -// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); -// #elif defined DAP_OS_MAC -// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); -// #elif defined DAP_OS_UNIX -// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); -// #endif -// } - - -// const char *l_hash_out_type = NULL; -// dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-H", &l_hash_out_type); -// if (!l_hash_out_type) -// l_hash_out_type = "hex"; -// if (dap_strcmp(l_hash_out_type, "hex") && dap_strcmp(l_hash_out_type, "base58")) { -// printf("Error: Invalid hash type argument\n"); -// return -1; -// } - -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str) || NULL == l_net_str) { -// printf("Error: Missing or invalid network argument\n"); -// return -2; -// } - -// if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-url", &l_url_str)) { -// l_url_str = dap_compose_get_net_url(l_net_str); -// } - -// const char *l_port_str = NULL; -// if (!dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-port", &l_port_str)) { -// l_port = dap_compose_get_net_port(l_net_str); -// } else { -// l_port = atoi(l_port_str); -// } - -// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_id", &l_chain_id_str); -// if (!l_chain_id_str) { -// printf("Error: Missing or invalid chain_id argument\n"); -// return -10; -// } - -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_str) || NULL == l_tx_str) { -// printf("Error: Missing or invalid transaction argument\n"); -// return -5; -// } +typedef enum { + CLI_TAKE_COMPOSE_OK = 0, + CLI_TAKE_COMPOSE_ERROR_UNABLE_TO_INIT_CONFIG = -1, + CLI_TAKE_COMPOSE_ERROR_INVALID_TRANSACTION_HASH = -2, + CLI_TAKE_COMPOSE_ERROR_FAILED_TO_GET_RESPONSE = -3, + CLI_TAKE_COMPOSE_ERROR_NO_ITEMS_FOUND = -4, + CLI_TAKE_COMPOSE_ERROR_NO_TX_OUT_CONDITION = -5, + CLI_TAKE_COMPOSE_ERROR_TX_OUT_ALREADY_USED = -6, + CLI_TAKE_COMPOSE_ERROR_FAILED_GET_ITEMS_ARRAY = -7, + CLI_TAKE_COMPOSE_ERROR_TOKEN_TICKER_NOT_FOUND = -8, + CLI_TAKE_COMPOSE_ERROR_INVALID_COINS_FORMAT = -9, + CLI_TAKE_COMPOSE_ERROR_INVALID_FEE_FORMAT = -10, + CLI_TAKE_COMPOSE_ERROR_UNABLE_TO_OPEN_WALLET = -11, + CLI_TAKE_COMPOSE_ERROR_OWNER_KEY_NOT_FOUND = -12, + CLI_TAKE_COMPOSE_ERROR_NOT_ENOUGH_TIME_PASSED = -13 +} cli_take_compose_error_t; + +json_object* dap_cli_take_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_tx_str, const char *a_tx_burning_str, + const char *a_value_fee_str, const char *a_url_str, uint16_t a_port){ + + compose_config_t * l_config = s_compose_config_init(a_net_name, a_url_str, a_port); + if (!l_config) { + json_object * l_json_obj_ret = json_object_new_object(); + dap_json_compose_error_add(l_json_obj_ret, CLI_TAKE_COMPOSE_ERROR_UNABLE_TO_INIT_CONFIG, "Unable to init config\n"); + return l_json_obj_ret; + } -// if (dap_chain_hash_fast_from_str(l_tx_str, &l_tx_hash)) { -// printf("Error: Invalid transaction hash\n"); -// return -6; -// } + char l_delegated_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] = {}; + int l_prev_cond_idx = 0; + uint256_t l_value_delegated = {}; + uint256_t l_value_fee = {}; + dap_chain_wallet_t *l_wallet; + dap_hash_fast_t l_tx_hash; + dap_chain_tx_out_cond_t *l_cond_tx = NULL; + dap_enc_key_t *l_owner_key; + const char *l_ticker_str = NULL; + if (dap_chain_hash_fast_from_str(a_tx_str, &l_tx_hash)) { + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_INVALID_TRANSACTION_HASH, "Invalid transaction hash\n"); + return s_compose_config_return_response_handler(l_config); + } -// char data[512]; -// snprintf(data, sizeof(data), -// "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", -// l_tx_str, l_net_str); + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + a_tx_str, a_net_name); -// json_object *response = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); -// if (!response) { -// printf("Error: Failed to get response from remote node\n"); -// return -15; -// } + json_object *response = dap_request_command_to_rpc(data, l_config); + if (!response) { + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_FAILED_TO_GET_RESPONSE, "Failed to get response from remote node\n"); + return s_compose_config_return_response_handler(l_config); + } -// json_object *items = NULL; -// json_object *items_array = json_object_array_get_idx(response, 0); -// if (items_array) { -// items = json_object_object_get(items_array, "ITEMS"); -// } -// if (!items) { -// printf("Error: No items found in response\n"); -// return -16; -// } -// int items_count = json_object_array_length(items); -// for (int i = 0; i < items_count; i++) { -// json_object *item = json_object_array_get_idx(items, i); -// const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); -// if (dap_strcmp(item_type, "OUT COND") == 0) { -// const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); -// if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK")) { -// l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); -// l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; -// l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); -// l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK; -// l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); -// l_cond_tx->subtype.srv_stake_lock.time_unlock = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "time_unlock"))); -// break; -// } -// } -// } -// if (!l_cond_tx) { -// printf("Error: No transaction output condition found\n"); -// return -7; -// } + json_object *items = NULL; + json_object *items_array = json_object_array_get_idx(response, 0); + if (items_array) { + items = json_object_object_get(items_array, "ITEMS"); + } + if (!items) { + json_object_put(response); + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_NO_ITEMS_FOUND, "No items found in response\n"); + return s_compose_config_return_response_handler(l_config); + } + int items_count = json_object_array_length(items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (dap_strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK")) { + l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); + l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; + l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); + l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK; + l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); + l_cond_tx->subtype.srv_stake_lock.time_unlock = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "time_unlock"))); + break; + } + } + } + if (!l_cond_tx) { + json_object_put(response); + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_NO_TX_OUT_CONDITION, "No transaction output condition found\n"); + return s_compose_config_return_response_handler(l_config); + } -// json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); -// const char *spent_outs_value = json_object_get_string(spent_outs); -// if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { -// printf("Error: Transaction output item already used\n"); -// return -9; -// } + json_object *spent_outs = json_object_object_get(response, "all OUTs yet unspent"); + const char *spent_outs_value = json_object_get_string(spent_outs); + if (spent_outs_value && dap_strcmp(spent_outs_value, "yes") != 0) { + json_object_put(response); + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_TX_OUT_ALREADY_USED, "Transaction output item already used\n"); + return s_compose_config_return_response_handler(l_config); + } -// json_object *response_header_array = json_object_array_get_idx(response, 0); -// if (!response_header_array) { -// printf("Error: Failed to get items array from response\n"); -// return -10; -// } + json_object *response_header_array = json_object_array_get_idx(response, 0); + if (!response_header_array) { + json_object_put(response); + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_FAILED_GET_ITEMS_ARRAY, "Failed to get items array from response\n"); + return s_compose_config_return_response_handler(l_config); + } -// json_object *token_ticker_obj = json_object_object_get(response_header_array, "token ticker"); -// if (!token_ticker_obj) { -// printf("Error: Token ticker not found in response\n"); -// return -11; -// } -// l_ticker_str = json_object_get_string(token_ticker_obj); + json_object *token_ticker_obj = json_object_object_get(response_header_array, "token ticker"); + if (!token_ticker_obj) { + json_object_put(response); + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_TOKEN_TICKER_NOT_FOUND, "Token ticker not found in response\n"); + return s_compose_config_return_response_handler(l_config); + } + l_ticker_str = json_object_get_string(token_ticker_obj); -// dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str); + dap_chain_datum_token_get_delegated_ticker(l_delegated_ticker_str, l_ticker_str); -// uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001"); + uint256_t l_emission_rate = dap_chain_coins_to_balance("0.001"); -// if (IS_ZERO_256(l_emission_rate) || -// MULT_256_COIN(l_cond_tx->header.value, l_emission_rate, &l_value_delegated) || -// IS_ZERO_256(l_value_delegated)) { -// printf("Error: Invalid coins format\n"); -// return -12; -// } + if (IS_ZERO_256(l_emission_rate) || + MULT_256_COIN(l_cond_tx->header.value, l_emission_rate, &l_value_delegated) || + IS_ZERO_256(l_value_delegated)) { + json_object_put(response); + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_INVALID_COINS_FORMAT, "Invalid coins format\n"); + return s_compose_config_return_response_handler(l_config); + } + if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(a_value_fee_str)))) { + json_object_put(response); + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_INVALID_FEE_FORMAT, "Invalid fee format\n"); + return s_compose_config_return_response_handler(l_config); + } + json_object_put(response); -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str) || !l_wallet_str) { -// printf("Error: Missing or invalid wallet argument\n"); -// return -13; -// } + if (NULL == (l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path, NULL))) { + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_UNABLE_TO_OPEN_WALLET, "Unable to open wallet\n"); + return s_compose_config_return_response_handler(l_config); + } -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_value_fee_str) || !l_value_fee_str) { -// printf("Error: Missing or invalid fee argument\n"); -// return -14; -// } + if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) { + dap_chain_wallet_close(l_wallet); + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_OWNER_KEY_NOT_FOUND, "Owner key not found\n"); + return s_compose_config_return_response_handler(l_config); + } -// if (IS_ZERO_256((l_value_fee = dap_chain_balance_scan(l_value_fee_str)))) { -// printf("Error: Invalid fee format\n"); -// return -15; -// } + if (l_cond_tx->subtype.srv_stake_lock.time_unlock > dap_time_now()) { + dap_chain_wallet_close(l_wallet); + dap_enc_key_delete(l_owner_key); + dap_json_compose_error_add(l_config->response_handler, CLI_TAKE_COMPOSE_ERROR_NOT_ENOUGH_TIME_PASSED, "Not enough time has passed for unlocking\n"); + return s_compose_config_return_response_handler(l_config); + } + dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_owner_key, &l_tx_hash, l_prev_cond_idx, + l_ticker_str, l_cond_tx->header.value, l_value_fee, + l_delegated_ticker_str, l_value_delegated, l_config); -// if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL))) { -// printf("Error: Unable to open wallet\n"); -// return -16; -// } + json_object * l_json_obj_ret = json_object_new_object(); + dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); + printf("%s", json_object_to_json_string(l_json_obj_ret)); + json_object_put(l_json_obj_ret); -// if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) { -// dap_chain_wallet_close(l_wallet); -// printf("Error: Owner key not found\n"); -// return -17; -// } -// if (l_cond_tx->subtype.srv_stake_lock.time_unlock > dap_time_now()) { -// dap_chain_wallet_close(l_wallet); -// dap_enc_key_delete(l_owner_key); -// printf("Error: Not enough time has passed for unlocking\n"); -// return -19; -// } -// dap_chain_datum_tx_t *l_tx = dap_stake_unlock_datum_create_compose(l_net_str, l_owner_key, &l_tx_hash, l_prev_cond_idx, -// l_ticker_str, l_cond_tx->header.value, l_value_fee, -// l_delegated_ticker_str, l_value_delegated, l_url_str, l_port); + dap_chain_datum_tx_delete(l_tx); + dap_enc_key_delete(l_owner_key); -// json_object * l_json_obj_ret = json_object_new_object(); -// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); -// printf("%s", json_object_to_json_string(l_json_obj_ret)); -// json_object_put(l_json_obj_ret); + return 0; +} -// dap_chain_datum_tx_delete(l_tx); -// dap_enc_key_delete(l_owner_key); +typedef enum { + TX_STAKE_UNLOCK_COMPOSE_OK = 0, + TX_STAKE_UNLOCK_COMPOSE_INVALID_PARAMS = -1, + TX_STAKE_UNLOCK_COMPOSE_NOT_ENOUGH_FUNDS = -2, + TX_STAKE_UNLOCK_COMPOSE_TOTAL_FEE_MORE_THAN_STAKE = -3, + TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_NETWORK_FEE_OUTPUT = -4, + TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_VALIDATOR_FEE_OUTPUT = -5, + TX_STAKE_UNLOCK_COMPOSE_CANT_SUBTRACT_VALUE_PACK = -6, + TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_MAIN = -7, + TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_NATIVE = -8, + TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_BURNING_OUTPUT = -9, + TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_DELEGATED = -10 +} tx_stake_unlock_compose_error_t; + +dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(dap_enc_key_t *a_key_from, + dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, + const char *a_main_ticker, uint256_t a_value, + uint256_t a_value_fee, + const char *a_delegated_ticker_str, uint256_t a_delegated_value, + compose_config_t *a_config) +{ + // check valid param + if (!a_config || !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) { + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_INVALID_PARAMS, "Invalid parameters\n"); + return NULL; + } -// return 0; -// } + const char *l_native_ticker = s_get_native_ticker(a_config->net_name); + bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker); + // find the transactions from which to take away coins + uint256_t l_value_transfer = {}; // how many coins to transfer + uint256_t l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {}; + dap_chain_addr_t* l_addr_fee = NULL; + dap_chain_addr_t l_addr = {}; -// dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, -// dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, -// const char *a_main_ticker, uint256_t a_value, -// uint256_t a_value_fee, -// const char *a_delegated_ticker_str, uint256_t a_delegated_value, -// const char *l_url_str, uint16_t l_port) -// { -// // check valid param -// if (!a_net_name | !a_key_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || dap_hash_fast_is_blank(a_stake_tx_hash)) { -// printf("Error: Invalid parameters\n"); -// return NULL; -// } + dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_config->net_name)); + dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL; -// const char *l_native_ticker = s_get_native_ticker(a_net_name); -// bool l_main_native = !dap_strcmp(a_main_ticker, l_native_ticker); -// // find the transactions from which to take away coins -// uint256_t l_value_transfer = {}; // how many coins to transfer -// uint256_t l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {}; -// dap_chain_addr_t* l_addr_fee = NULL; -// dap_chain_addr_t l_addr = {}; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, a_config); -// dap_chain_addr_fill_from_key(&l_addr, a_key_from, s_get_net_id(a_net_name)); -// dap_list_t *l_list_fee_out = NULL, *l_list_used_out = NULL; + json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, &l_addr, a_config); + if (!l_outs_native) { + return NULL; + } -// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_name, &l_net_fee, &l_addr_fee, l_url_str, l_port); + json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, &l_addr, a_config); + if (!l_outs_delegated) { + return NULL; + } -// json_object *l_outs_native = dap_get_remote_tx_outs(l_native_ticker, a_net_name, &l_addr, l_url_str, l_port); -// if (!l_outs_native) { -// return NULL; -// } + int l_out_native_count = json_object_array_length(l_outs_native); + int l_out_delegated_count = json_object_array_length(l_outs_delegated); -// json_object *l_outs_delegated = dap_get_remote_tx_outs(a_delegated_ticker_str, a_net_name, &l_addr, l_url_str, l_port); -// if (!l_outs_delegated) { -// return NULL; -// } + SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); + if (!IS_ZERO_256(l_total_fee)) { + if (!l_main_native) { + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, + l_total_fee, + &l_fee_transfer); + if (!l_list_fee_out) { + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_NOT_ENOUGH_FUNDS, "Not enough funds to pay fee"); + json_object_put(l_outs_native); + json_object_put(l_outs_delegated); + return NULL; + } + } else if (compare256(a_value, l_total_fee) == -1) { + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_TOTAL_FEE_MORE_THAN_STAKE, "Total fee more than stake\n"); + json_object_put(l_outs_native); + json_object_put(l_outs_delegated); + return NULL; + } + } + if (!IS_ZERO_256(a_delegated_value)) { + l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count, + a_delegated_value, + &l_value_transfer); + if (!l_list_used_out) { + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_NOT_ENOUGH_FUNDS, "Not enough funds to pay fee"); + json_object_put(l_outs_native); + json_object_put(l_outs_delegated); + return NULL; + } + } -// int l_out_native_count = json_object_array_length(l_outs_native); -// int l_out_delegated_count = json_object_array_length(l_outs_delegated); - -// SUM_256_256(l_net_fee, a_value_fee, &l_total_fee); -// if (!IS_ZERO_256(l_total_fee)) { -// if (!l_main_native) { -// l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs_native, l_out_native_count, -// l_total_fee, -// &l_fee_transfer); -// if (!l_list_fee_out) { -// printf("Not enough funds to pay fee"); -// json_object_put(l_outs_native); -// json_object_put(l_outs_delegated); -// return NULL; -// } -// } else if (compare256(a_value, l_total_fee) == -1) { -// printf("Error: Total fee more than stake\n"); -// return NULL; -// } -// } -// if (!IS_ZERO_256(a_delegated_value)) { -// l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs_delegated, l_out_delegated_count, -// a_delegated_value, -// &l_value_transfer); -// if (!l_list_used_out) { -// printf("Not enough funds to pay fee"); -// json_object_put(l_outs_native); -// json_object_put(l_outs_delegated); -// return NULL; -// } -// } + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); -// // create empty transaction -// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // add 'in_cond' & 'in' items + { + dap_chain_datum_tx_add_in_cond_item(&l_tx, a_stake_tx_hash, a_prev_cond_idx, 0); + if (l_list_used_out) { + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + } + if (l_list_fee_out) { + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); + dap_list_free_full(l_list_fee_out, NULL); + } + } -// // add 'in_cond' & 'in' items -// { -// dap_chain_datum_tx_add_in_cond_item(&l_tx, a_stake_tx_hash, a_prev_cond_idx, 0); -// if (l_list_used_out) { -// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); -// assert(EQUAL_256(l_value_to_items, l_value_transfer)); -// dap_list_free_full(l_list_used_out, NULL); -// } -// if (l_list_fee_out) { -// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); -// assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); -// dap_list_free_full(l_list_fee_out, NULL); -// } -// } + // add 'out_ext' items + uint256_t l_value_back; + { + uint256_t l_value_pack = {}; // how much datoshi add to 'out' items + // Network fee + if(l_net_fee_used){ + if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker)){ + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_NETWORK_FEE_OUTPUT, "Can't add network fee output\n"); + return NULL; + } + SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) + { + SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); + } + else { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_VALIDATOR_FEE_OUTPUT, "Can't add validator's fee output\n"); + return NULL; + } + } + // coin back + //SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back); + if(l_main_native){ + if (SUBTRACT_256_256(a_value, l_value_pack, &l_value_back)) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_SUBTRACT_VALUE_PACK, "Can't subtract value pack from value\n"); + return NULL; + } + if(!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker)!=1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_MAIN, "Can't add coin back output for main ticker\n"); + return NULL; + } + } + } else { + SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back); + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_value, a_main_ticker)!=1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_MAIN, "Can't add coin back output for main ticker\n"); + return NULL; + } + else + { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker)!=1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_NATIVE, "Can't add coin back output for native ticker\n"); + return NULL; + } + } + } + } -// // add 'out_ext' items -// uint256_t l_value_back; -// { -// uint256_t l_value_pack = {}; // how much datoshi add to 'out' items -// // Network fee -// if(l_net_fee_used){ -// if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_fee, l_net_fee, l_native_ticker)){ -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Can't add network fee output\n"); -// return NULL; -// } -// SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); -// } -// // Validator's fee -// if (!IS_ZERO_256(a_value_fee)) { -// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) -// { -// SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); -// } -// else { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Can't add validator's fee output\n"); -// return NULL; -// } -// } -// // coin back -// //SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back); -// if(l_main_native){ -// if (SUBTRACT_256_256(a_value, l_value_pack, &l_value_back)) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Can't subtract value pack from value\n"); -// return NULL; -// } -// if(!IS_ZERO_256(l_value_back)) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_main_ticker)!=1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Can't add coin back output for main ticker\n"); -// return NULL; -// } -// } -// } else { -// SUBTRACT_256_256(l_fee_transfer, l_value_pack, &l_value_back); -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, a_value, a_main_ticker)!=1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Can't add coin back output for main ticker\n"); -// return NULL; -// } -// else -// { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, l_native_ticker)!=1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Can't add coin back output for native ticker\n"); -// return NULL; -// } -// } -// } -// } + // add burning 'out_ext' + if (!IS_ZERO_256(a_delegated_value)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &c_dap_chain_addr_blank, + a_delegated_value, a_delegated_ticker_str) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_BURNING_OUTPUT, "Can't add burning output for delegated value\n"); + return NULL; + } + // delegated token coin back + SUBTRACT_256_256(l_value_transfer, a_delegated_value, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_delegated_ticker_str) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_STAKE_UNLOCK_COMPOSE_CANT_ADD_COIN_BACK_DELEGATED, "Can't add coin back output for delegated ticker\n"); + return NULL; + } + } + } -// // add burning 'out_ext' -// if (!IS_ZERO_256(a_delegated_value)) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &c_dap_chain_addr_blank, -// a_delegated_value, a_delegated_ticker_str) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Can't add burning output for delegated value\n"); -// return NULL; -// } -// // delegated token coin back -// SUBTRACT_256_256(l_value_transfer, a_delegated_value, &l_value_back); -// if (!IS_ZERO_256(l_value_back)) { -// if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr, l_value_back, a_delegated_ticker_str) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// printf("Error: Can't add coin back output for delegated ticker\n"); -// return NULL; -// } -// } -// } + return l_tx; +} -// return l_tx; -// } +typedef enum { + GET_KEY_DELEGATING_MIN_VALUE_OK = 0, + GET_KEY_DELEGATING_MIN_VALUE_FAILED_TO_GET_RESPONSE = -1, + GET_KEY_DELEGATING_MIN_VALUE_INVALID_RESPONSE_FORMAT = -2, + GET_KEY_DELEGATING_MIN_VALUE_SUMMARY_NOT_FOUND = -3, + GET_KEY_DELEGATING_MIN_VALUE_MIN_VALUE_NOT_FOUND = -4, + GET_KEY_DELEGATING_MIN_VALUE_INVALID_VALUE_FORMAT = -5, + GET_KEY_DELEGATING_MIN_VALUE_UNRECOGNIZED_NUMBER = -6 +} get_key_delegating_min_value_error_t; uint256_t s_get_key_delegating_min_value(compose_config_t *a_config){ uint256_t l_key_delegating_min_value = uint256_0; @@ -2208,37 +2201,37 @@ uint256_t s_get_key_delegating_min_value(compose_config_t *a_config){ json_object *response = dap_request_command_to_rpc(data, a_config); if (!response) { - printf("Error: Failed to get response from remote node\n"); + dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_FAILED_TO_GET_RESPONSE, "Failed to get response from remote node\n"); return l_key_delegating_min_value; } json_object *response_array = json_object_array_get_idx(response, 0); if (!response_array) { - printf("Error: Invalid response format\n"); + dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_INVALID_RESPONSE_FORMAT, "Invalid response format\n"); return l_key_delegating_min_value; } json_object *summary_obj = json_object_array_get_idx(response_array, json_object_array_length(response_array) - 1); if (!summary_obj) { - printf("Error: Summary object not found in response\n"); + dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_SUMMARY_NOT_FOUND, "Summary object not found in response\n"); return l_key_delegating_min_value; } json_object *key_delegating_min_value_obj = json_object_object_get(summary_obj, "key_delegating_min_value"); if (!key_delegating_min_value_obj) { - printf("Error: key_delegating_min_value not found in summary\n"); + dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_MIN_VALUE_NOT_FOUND, "Key delegating min value not found in summary\n"); return l_key_delegating_min_value; } const char *key_delegating_min_value_str = json_object_get_string(key_delegating_min_value_obj); if (!key_delegating_min_value_str) { - printf("Error: Invalid key_delegating_min_value format\n"); + dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_INVALID_VALUE_FORMAT, "Invalid key_delegating_min_value format\n"); return l_key_delegating_min_value; } l_key_delegating_min_value = dap_chain_balance_scan(key_delegating_min_value_str); if (IS_ZERO_256(l_key_delegating_min_value)) { - printf("Error: Unrecognized number in key_delegating_min_value\n"); + dap_json_compose_error_add(a_config->response_handler, GET_KEY_DELEGATING_MIN_VALUE_UNRECOGNIZED_NUMBER, "Unrecognized number in key_delegating_min_value\n"); return l_key_delegating_min_value; } diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 2328c76e0b..7d42deaa98 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -89,7 +89,8 @@ json_object* dap_tx_cond_create_compose(const char *a_net_name, const char *a_to json_object * dap_cli_hold_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_ticker_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_coins_str, const char *a_time_staking_str, const char *a_cert_str, const char *a_value_fee_str, const char *a_reinvest_percent_str, const char *a_url_str, uint16_t a_port); -int dap_cli_take_compose(int a_argc, char **a_argv); +json_object* dap_cli_take_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_tx_str, const char *a_tx_burning_str, + const char *a_value_fee_str, const char *a_url_str, uint16_t a_port); int dap_cli_voting_compose(int a_argc, char **a_argv); typedef enum { STAKE_ORDER_CREATE_STAKER_OK = 0, @@ -255,12 +256,12 @@ dap_chain_datum_tx_t * dap_stake_lock_datum_create_compose(dap_enc_key_t *a_key_ const char *a_delegated_ticker_str, uint256_t a_delegated_value, const char * a_chain_id_str, compose_config_t *a_config); bool check_token_in_ledger(json_object *l_json_coins, const char *a_token); -dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(const char *a_net_name, dap_enc_key_t *a_key_from, +dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(dap_enc_key_t *a_key_from, dap_hash_fast_t *a_stake_tx_hash, uint32_t a_prev_cond_idx, const char *a_main_ticker, uint256_t a_value, uint256_t a_value_fee, const char *a_delegated_ticker_str, uint256_t a_delegated_value, - const char *l_url_str, uint16_t l_port); + compose_config_t *a_config); dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, -- GitLab From 5d2bdc4318108b7d4fe74c842c54126e1c15bf4f Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Mon, 14 Apr 2025 16:50:16 +0700 Subject: [PATCH 51/53] [*] voting --- modules/compose/dap_chain_tx_compose.c | 680 ++++++++++-------- .../compose/include/dap_chain_tx_compose.h | 149 +--- 2 files changed, 405 insertions(+), 424 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 7c60204231..01a0815284 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -309,7 +309,14 @@ static int s_cmd_request_get_response(struct cmd_request *a_cmd_request, json_ob return ret; } - +typedef enum { + DAP_COMPOSE_ERROR_NONE = 0, + DAP_COMPOSE_ERROR_RESPONSE_NULL = -1, + DAP_COMPOSE_ERROR_RESULT_NOT_FOUND = -2, + DAP_COMPOSE_ERROR_REQUEST_INIT_FAILED = -3, + DAP_COMPOSE_ERROR_REQUEST_TIMEOUT = -4, + DAP_COMPOSE_ERROR_REQUEST_FAILED = -5 +} dap_compose_error_t; static json_object* s_request_command_to_rpc(const char *request, compose_config_t *a_config) { json_object * l_response = NULL; size_t l_response_size = 0; @@ -373,6 +380,7 @@ static json_object* s_request_command_parse(json_object *l_response, compose_con return l_result; } + json_object* dap_request_command_to_rpc(const char *request, compose_config_t *a_config) { json_object * l_response = s_request_command_to_rpc(request, a_config); if (!l_response) { @@ -496,7 +504,8 @@ typedef enum { TX_CREATE_COMPOSE_INVALID_PARAMS = -5, TX_CREATE_COMPOSE_FEE_ERROR = -6, TX_CREATE_COMPOSE_FUNDS_ERROR = -7, - TX_CREATE_COMPOSE_OUT_ERROR = -8 + TX_CREATE_COMPOSE_OUT_ERROR = -8, + TX_CREATE_COMPOSE_INVALID_CONFIG = -9 } tx_create_compose_error_t; json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) { @@ -504,7 +513,7 @@ json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ti compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port); if (!l_config) { json_object* l_json_obj_ret = json_object_new_object(); - dap_json_compose_error_add(l_json_obj_ret, SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, "Can't create compose config"); + dap_json_compose_error_add(l_json_obj_ret, TX_CREATE_COMPOSE_INVALID_CONFIG, "Can't create compose config"); return l_json_obj_ret; } @@ -1316,6 +1325,19 @@ dap_chain_datum_tx_t *dap_xchange_tx_create_request_compose(dap_chain_net_srv_xc } +typedef enum dap_tx_cond_create_compose_error { + TX_COND_CREATE_COMPOSE_ERROR_INVALID_FEE = 1, + TX_COND_CREATE_COMPOSE_ERROR_INVALID_SERVICE_UID, + TX_COND_CREATE_COMPOSE_ERROR_INVALID_UNIT, + TX_COND_CREATE_COMPOSE_ERROR_INVALID_VALUE, + TX_COND_CREATE_COMPOSE_ERROR_WALLET_OPEN_FAILED, + TX_COND_CREATE_COMPOSE_ERROR_CERT_NOT_FOUND, + TX_COND_CREATE_COMPOSE_ERROR_INVALID_CERT_KEY, + TX_COND_CREATE_COMPOSE_ERROR_NATIVE_TOKEN_REQUIRED, + TX_COND_CREATE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS, + TX_COND_CREATE_COMPOSE_ERROR_COND_OUTPUT_FAILED, + TX_COND_CREATE_COMPOSE_ERROR_COIN_BACK_FAILED +} dap_tx_cond_create_compose_error_t; json_object* dap_tx_cond_create_compose(const char *a_net_name, const char *a_token_ticker, const char *a_wallet_str, const char *a_wallet_path, const char *a_cert_str, const char *a_value_datoshi_str, const char *a_value_fee_str, const char *a_unit_str, const char *a_srv_uid_str, const char *a_url_str, uint16_t a_port) { @@ -2239,320 +2261,292 @@ uint256_t s_get_key_delegating_min_value(compose_config_t *a_config){ } -// int dap_cli_voting_compose(int a_argc, char **a_argv) -// { -// int arg_index = 1; -// const char* l_question_str = NULL; -// const char* l_options_list_str = NULL; -// const char* l_voting_expire_str = NULL; -// const char* l_max_votes_count_str = NULL; -// const char* l_fee_str = NULL; -// const char* l_wallet_str = NULL; -// const char* l_net_str = NULL; -// const char* l_token_str = NULL; -// const char* l_url_str = NULL; -// uint16_t l_port = 0; -// const char *l_wallet_path = NULL; -// dap_cli_server_cmd_find_option_val(a_argv, 1, a_argc, "-wallet_path", &l_wallet_path); -// if (!l_wallet_path) { -// l_wallet_path = -// #ifdef DAP_OS_WINDOWS -// dap_strdup_printf("%s/var/lib/wallets", regGetUsrPath()); -// #elif defined DAP_OS_MAC -// dap_strdup_printf("Library/Application Support/CellframeNode/var/lib/wallets"); -// #elif defined DAP_OS_UNIX -// dap_strdup_printf("/opt/CellframeNode/var/lib/wallets"); -// #endif -// } - -// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); -// // Select chain network -// if(!l_net_str) { -// printf("Voting requires parameter '-net' to be valid.\n"); -// return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING; -// } - -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-url", &l_url_str)) { -// l_url_str = dap_compose_get_net_url(l_net_str); -// } - -// const char *l_port_str = NULL; -// if (!dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str)) { -// l_port = dap_compose_get_net_port(l_net_str); -// } else { -// l_port = atoi(l_port_str); -// } -// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str); -// if (!l_question_str){ -// printf("Voting requires a question parameter to be valid.\n"); -// return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_PARAM_MISSING; -// } - -// if (strlen(l_question_str) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ -// printf("The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH); -// return -DAP_CHAIN_NET_VOTE_CREATE_QUESTION_CONTAIN_MAX_CHARACTERS; -// } +json_object* dap_cli_voting_compose(const char *a_net_name, const char *a_question_str, const char *a_options_list_str, + const char *a_voting_expire_str, const char *a_max_votes_count_str, const char *a_fee_str, + bool a_is_delegated_key, bool a_is_vote_changing_allowed, const char *a_wallet_str, const char *a_wallet_path, + const char *a_token_str, const char *a_url_str, uint16_t a_port) { + + compose_config_t * l_config = s_compose_config_init(a_net_name, a_url_str, a_port); + if (!l_config) { + json_object * l_json_obj_ret = json_object_new_object(); + dap_json_compose_error_add(l_json_obj_ret, CLI_TAKE_COMPOSE_ERROR_UNABLE_TO_INIT_CONFIG, "Unable to init config\n"); + return l_json_obj_ret; + } + + if (strlen(a_question_str) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ + dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH, "The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH); + return s_compose_config_return_response_handler(l_config); + } -// dap_list_t *l_options_list = NULL; -// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-options", &l_options_list_str); -// if (!l_options_list_str){ -// printf("Voting requires a question parameter to be valid.\n"); -// return -DAP_CHAIN_NET_VOTE_CREATE_OPTION_PARAM_MISSING; -// } -// // Parse options list -// l_options_list = dap_get_options_list_from_str(l_options_list_str); -// if(!l_options_list || dap_list_length(l_options_list) < 2){ -// printf("Number of options must be 2 or greater.\n"); -// return -DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR; -// } + dap_list_t *l_options_list = NULL; + // Parse options list + l_options_list = dap_get_options_list_from_str(a_options_list_str); + if(!l_options_list || dap_list_length(l_options_list) < 2){ + dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_NUMBER_OPTIONS_ERROR, "Number of options must be 2 or greater.\n"); + return s_compose_config_return_response_handler(l_config); + } -// if(dap_list_length(l_options_list)>DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){ -// printf("The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT); -// return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS; -// } + if(dap_list_length(l_options_list)>DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){ + dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS, "The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT); + return s_compose_config_return_response_handler(l_config); + } + uint256_t l_value_fee = dap_chain_balance_scan(a_fee_str); -// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str); -// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str); -// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str); -// if (!l_fee_str){ -// printf("Voting requires parameter -fee to be valid.\n"); -// return -DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID; -// } -// uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str); -// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str); -// if (!l_wallet_str){ -// printf("Voting requires parameter -w to be valid.\n"); -// return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID; -// } + dap_time_t l_time_expire = 0; + if (a_voting_expire_str) + l_time_expire = dap_time_from_str_rfc822(a_voting_expire_str); + if (a_voting_expire_str && !l_time_expire){ + dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT, "Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"\n"); + return s_compose_config_return_response_handler(l_config); + } + uint64_t l_max_count = 0; + if (a_max_votes_count_str) + l_max_count = strtoul(a_max_votes_count_str, NULL, 10); -// dap_time_t l_time_expire = 0; -// if (l_voting_expire_str) -// l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str); -// if (l_voting_expire_str && !l_time_expire){ -// printf("Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\"\n"); -// return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT; -// } -// uint64_t l_max_count = 0; -// if (l_max_votes_count_str) -// l_max_count = strtoul(l_max_votes_count_str, NULL, 10); - -// bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false; -// bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false; -// dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, l_wallet_path, NULL); -// if (!l_wallet_fee) { -// printf("Wallet %s does not exist\n", l_wallet_str); -// return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; -// } + dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(a_wallet_str, a_wallet_path, NULL); + if (!l_wallet_fee) { + dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST, "Wallet %s does not exist\n", a_wallet_str); + return s_compose_config_return_response_handler(l_config); + } -// dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str); -// if (!l_token_str) { -// printf("Command required -token argument"); -// return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; -// } -// char data[512]; -// snprintf(data, sizeof(data), -// "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", l_net_str); -// json_object *l_json_coins = dap_request_command_to_rpc(data, l_net_str, l_url_str, l_port); -// if (!l_json_coins) { -// printf("Error: Can't get ledger coins list\n"); -// return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; -// } -// if (!check_token_in_ledger(l_json_coins, l_token_str)) { -// json_object_put(l_json_coins); -// printf("Token %s does not exist\n", l_token_str); -// return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN; -// } -// json_object_put(l_json_coins); - -// dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(l_question_str, l_options_list, l_time_expire, l_max_count, -// l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, -// l_wallet_fee, l_net_str, l_token_str, l_url_str, l_port); -// dap_list_free(l_options_list); -// dap_chain_wallet_close(l_wallet_fee); -// json_object * l_json_obj_ret = json_object_new_object(); -// dap_chain_net_tx_to_json(l_tx, l_json_obj_ret); -// printf("%s", json_object_to_json_string(l_json_obj_ret)); -// json_object_put(l_json_obj_ret); -// return 0; -// } - - -// dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, -// uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, -// bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, -// const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port) { + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;list;coins;-net;%s\"],\"id\": \"2\"}", a_net_name); + json_object *l_json_coins = dap_request_command_to_rpc(data, l_config); + if (!l_json_coins) { + dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS, "Can't get ledger coins list\n"); + return s_compose_config_return_response_handler(l_config); + } + if (!check_token_in_ledger(l_json_coins, a_token_str)) { + json_object_put(l_json_coins); + dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN, "Token %s does not exist\n", a_token_str); + return s_compose_config_return_response_handler(l_config); + } + json_object_put(l_json_coins); -// if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ -// return NULL; -// } + dap_chain_datum_tx_t* l_tx = dap_chain_net_vote_create_compose(a_question_str, l_options_list, l_time_expire, l_max_count, + l_value_fee, a_is_delegated_key, a_is_vote_changing_allowed, + l_wallet_fee, a_token_str, l_config); + dap_list_free(l_options_list); + dap_chain_wallet_close(l_wallet_fee); + if (l_tx) { + dap_chain_net_tx_to_json(l_tx, l_config->response_handler); + dap_chain_datum_tx_delete(l_tx); + } + return s_compose_config_return_response_handler(l_config); +} -// // Parse options list +typedef enum { + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_OK = 0, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_INVALID_CONFIG, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_QUESTION_TOO_LONG, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_TOO_MANY_OPTIONS, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_ZERO_FEE, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_WALLET_NOT_FOUND, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_OPTION_TOO_LONG, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_OPTION_CREATE_FAILED, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_INVALID_EXPIRE_TIME, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_EXPIRE_CREATE_FAILED, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_MAX_VOTES_CREATE_FAILED, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_DELEGATED_KEY_CREATE_FAILED, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_VOTE_CHANGING_CREATE_FAILED, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_TOKEN_CREATE_FAILED, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_FEE_OUTPUT_FAILED, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_COINBACK_FAILED, + DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_NOT_ENOUGH_FUNDS +} dap_chain_net_vote_create_compose_error_t; + +dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, + uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, + bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, + const char *a_token_ticker, compose_config_t *a_config) { + if (!a_config) { + return NULL; + } -// if(dap_list_length(a_options) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){ -// return NULL; -// } + if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_QUESTION_TOO_LONG, "The question must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH); + return NULL; + } -// if (IS_ZERO_256(a_fee)) { -// return NULL; -// } + // Parse options list -// dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str)); + if(dap_list_length(a_options) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT){ + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_TOO_MANY_OPTIONS, "The voting can contain no more than %d options\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_COUNT); + return NULL; + } -// if(!l_addr_from) { -// return NULL; -// } + if (IS_ZERO_256(a_fee)) { + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_ZERO_FEE, "Fee must be greater than 0\n"); + return NULL; + } -// const char *l_native_ticker = s_get_native_ticker(a_net_str); -// uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer; -// dap_chain_addr_t *l_addr_fee = NULL; -// bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee, l_url_str, l_port); -// SUM_256_256(l_net_fee, a_fee, &l_total_fee); + dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_config->net_name)); + if(!l_addr_from) { + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_WALLET_NOT_FOUND, "Wallet does not exist\n"); + return NULL; + } -// json_object *l_outs = NULL; -// int l_outputs_count = 0; -// if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, a_net_str, &l_outs, &l_outputs_count, l_url_str, l_port)) { -// return NULL; -// } + const char *l_native_ticker = s_get_native_ticker(a_config->net_name); + uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer; + dap_chain_addr_t *l_addr_fee = NULL; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, a_config); + SUM_256_256(l_net_fee, a_fee, &l_total_fee); -// dap_list_t *l_list_used_out = NULL; -// l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, -// l_total_fee, -// &l_value_transfer); + json_object *l_outs = NULL; + int l_outputs_count = 0; + if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_native_ticker, &l_outs, &l_outputs_count, a_config)) { + return NULL; + } -// json_object_put(l_outs); -// if (!l_list_used_out) { -// printf("Not enough funds to transfer"); -// return NULL; -// } + dap_list_t *l_list_used_out = NULL; + l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_total_fee, + &l_value_transfer); + json_object_put(l_outs); + if (!l_list_used_out) { + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_NOT_ENOUGH_FUNDS, "Not enough funds to transfer"); + return NULL; + } -// // create empty transaction -// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); -// // Add Voting item -// dap_chain_tx_voting_t* l_voting_item = dap_chain_datum_tx_item_voting_create(); + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); -// dap_chain_datum_tx_add_item(&l_tx, l_voting_item); -// DAP_DELETE(l_voting_item); + // Add Voting item + dap_chain_tx_voting_t* l_voting_item = dap_chain_datum_tx_item_voting_create(); -// // Add question to tsd data -// dap_chain_tx_tsd_t* l_question_tsd = dap_chain_datum_voting_question_tsd_create(a_question, strlen(a_question)); -// dap_chain_datum_tx_add_item(&l_tx, l_question_tsd); + dap_chain_datum_tx_add_item(&l_tx, l_voting_item); + DAP_DELETE(l_voting_item); -// // Add options to tsd -// dap_list_t *l_temp = a_options; -// while(l_temp){ -// if(strlen((char*)l_temp->data) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH){ -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// dap_chain_tx_tsd_t* l_option = dap_chain_datum_voting_answer_tsd_create((char*)l_temp->data, strlen((char*)l_temp->data)); -// if(!l_option){ -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// dap_chain_datum_tx_add_item(&l_tx, l_option); -// DAP_DEL_Z(l_option); + // Add question to tsd data + dap_chain_tx_tsd_t* l_question_tsd = dap_chain_datum_voting_question_tsd_create(a_question, strlen(a_question)); + dap_chain_datum_tx_add_item(&l_tx, l_question_tsd); -// l_temp = l_temp->next; -// } + // Add options to tsd + dap_list_t *l_temp = a_options; + while(l_temp){ + if(strlen((char*)l_temp->data) > DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH){ + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_OPTION_TOO_LONG, "The option must contain no more than %d characters\n", DAP_CHAIN_DATUM_TX_VOTING_OPTION_MAX_LENGTH); + return NULL; + } + dap_chain_tx_tsd_t* l_option = dap_chain_datum_voting_answer_tsd_create((char*)l_temp->data, strlen((char*)l_temp->data)); + if(!l_option){ + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_OPTION_CREATE_FAILED, "Failed to create option\n"); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_option); + DAP_DEL_Z(l_option); -// // add voting expire time if needed -// if(a_expire_vote != 0){ -// dap_time_t l_expired_vote = a_expire_vote; -// if (l_expired_vote < dap_time_now()){ -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } + l_temp = l_temp->next; + } -// dap_chain_tx_tsd_t* l_expired_item = dap_chain_datum_voting_expire_tsd_create(l_expired_vote); -// if(!l_expired_item){ -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// dap_chain_datum_tx_add_item(&l_tx, l_expired_item); -// DAP_DEL_Z(l_expired_item); -// } + // add voting expire time if needed + if(a_expire_vote != 0){ + dap_time_t l_expired_vote = a_expire_vote; + if (l_expired_vote < dap_time_now()){ + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_INVALID_EXPIRE_TIME, "Expire time must be in the future\n"); + return NULL; + } -// // Add vote max count if needed -// if (a_max_vote != 0) { -// dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote); -// if(!l_max_votes_item){ -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// dap_chain_datum_tx_add_item(&l_tx, l_max_votes_item); -// DAP_DEL_Z(l_max_votes_item); -// } + dap_chain_tx_tsd_t* l_expired_item = dap_chain_datum_voting_expire_tsd_create(l_expired_vote); + if(!l_expired_item){ + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_EXPIRE_CREATE_FAILED, "Failed to create expire time item\n"); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_expired_item); + DAP_DEL_Z(l_expired_item); + } -// if (a_delegated_key_required) { -// dap_chain_tx_tsd_t* l_delegated_key_req_item = dap_chain_datum_voting_delegated_key_required_tsd_create(true); -// if(!l_delegated_key_req_item){ -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// dap_chain_datum_tx_add_item(&l_tx, l_delegated_key_req_item); -// DAP_DEL_Z(l_delegated_key_req_item); -// } + // Add vote max count if needed + if (a_max_vote != 0) { + dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote); + if(!l_max_votes_item){ + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_MAX_VOTES_CREATE_FAILED, "Failed to create max votes item\n"); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_max_votes_item); + DAP_DEL_Z(l_max_votes_item); + } -// if(a_vote_changing_allowed){ -// dap_chain_tx_tsd_t* l_vote_changing_item = dap_chain_datum_voting_vote_changing_allowed_tsd_create(true); -// if(!l_vote_changing_item){ -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item); -// DAP_DEL_Z(l_vote_changing_item); -// } -// if (a_token_ticker) { -// dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker); -// if (!l_voting_token_item) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item); -// DAP_DEL_Z(l_voting_token_item); -// } + if (a_delegated_key_required) { + dap_chain_tx_tsd_t* l_delegated_key_req_item = dap_chain_datum_voting_delegated_key_required_tsd_create(true); + if(!l_delegated_key_req_item){ + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_DELEGATED_KEY_CREATE_FAILED, "Failed to create delegated key requirement item\n"); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_delegated_key_req_item); + DAP_DEL_Z(l_delegated_key_req_item); + } -// // add 'in' items -// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); -// assert(EQUAL_256(l_value_to_items, l_value_transfer)); -// dap_list_free_full(l_list_used_out, NULL); -// uint256_t l_value_pack = {}; -// // Network fee -// if (l_net_fee_used) { -// if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) -// SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); -// else { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// // Validator's fee -// if (!IS_ZERO_256(a_fee)) { -// if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1) -// SUM_256_256(l_value_pack, a_fee, &l_value_pack); -// else { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } -// // coin back -// uint256_t l_value_back; -// SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); -// if(!IS_ZERO_256(l_value_back)) { -// if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) { -// dap_chain_datum_tx_delete(l_tx); -// return NULL; -// } -// } + if(a_vote_changing_allowed){ + dap_chain_tx_tsd_t* l_vote_changing_item = dap_chain_datum_voting_vote_changing_allowed_tsd_create(true); + if(!l_vote_changing_item){ + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_VOTE_CHANGING_CREATE_FAILED, "Failed to create vote changing item\n"); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_vote_changing_item); + DAP_DEL_Z(l_vote_changing_item); + } + if (a_token_ticker) { + dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker); + if (!l_voting_token_item) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_TOKEN_CREATE_FAILED, "Failed to create token item\n"); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item); + DAP_DEL_Z(l_voting_token_item); + } + // add 'in' items + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + uint256_t l_value_pack = {}; + // Network fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_item(&l_tx, l_addr_fee, l_net_fee) == 1) + SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1) + SUM_256_256(l_value_pack, a_fee, &l_value_pack); + else { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_FEE_OUTPUT_FAILED, "Can't add fee output in tx"); + return NULL; + } + } + // coin back + uint256_t l_value_back; + SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); + if(!IS_ZERO_256(l_value_back)) { + if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_COMPOSE_ERR_COINBACK_FAILED, "Can't add coin back in tx"); + return NULL; + } + } -// return l_tx; -// } + return l_tx; +} /** int dap_cli_vote_compose(int a_argc, char **a_argv){ @@ -2885,6 +2879,38 @@ int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_c +typedef enum { + DAP_CLI_STAKE_INVALIDATE_OK = 0, + DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND = -1, + DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING = -2, + DAP_CLI_STAKE_INVALIDATE_WRONG_CERT = -3, + DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR = -4, + DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH = -5, + DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED = -6, + DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT = -7, + DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND = -8, + DAP_CLI_STAKE_INVALIDATE_TX_EXISTS = -9, + DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND = -10, + DAP_CLI_STAKE_INVALIDATE_COMPOSE_ERROR = -11, + DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR = -12, + DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND = -13, + DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT = -14, + DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND = -15, + DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR = -16, + DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND = -17, + DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND = -18, + DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR = -19, + DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER = -20, + DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND = -21, + DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND = -22, + DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS = -23, + DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR = -24, + DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR = -25, + DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR = -26, + DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27, + DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28, + DAP_CLI_STAKE_INVALIDATE_FEE_ERROR = -29 +} dap_cli_stake_invalidate_error_t; json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_cert_str, const char *a_fee_str, const char *a_url_str, uint16_t a_port) { @@ -3429,6 +3455,45 @@ dap_sign_t* dap_get_remote_srv_order_sign(const char* l_order_hash_str, compose_ +typedef enum { + STAKE_DELEGATE_COMPOSE_OK = 0, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE = -1, + STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND = -2, + STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND = -3, + STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG = -4, + STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE = -5, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY = -6, + STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED = -7, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR = -8, + STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND = -9, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE = -10, + STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED = -11, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED = -12, + STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER = -13, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT = -14, + STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE = -15, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE = -16, + STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS = -17, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR = -18, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR = -19, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR = -20, + STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER = -21, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW = -22, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH = -23, + STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER = -24, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER = -25, + STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX = -26, + STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN = -27, + DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS = -28, + DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE = -29, + DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE = -30, + DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR = -31, + DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR = -32, + DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR = -33, + DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR = -34, + DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -35, + DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -36 +} stake_delegate_error_t; json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path) { @@ -3874,6 +3939,18 @@ static dap_chain_datum_tx_t *dap_order_tx_create_compose(dap_enc_key_t *a_key, } +typedef enum { + STAKE_ORDER_CREATE_STAKER_OK = 0, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_PARAMS = -1, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -2, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -3, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -4, + STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -5, + STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -6, + STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -7, + STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -8, + STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -9 +} dap_cli_srv_stake_order_create_staker_error_t; json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) { compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port); if (!l_config) { @@ -3937,6 +4014,41 @@ json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str return s_compose_config_return_response_handler(l_config); } + +typedef enum { + SRV_STAKE_ORDER_REMOVE_COMPOSE_OK = 0, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_WALLET_NOT_FOUND, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_KEY_NOT_FOUND, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ORDER_HASH, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_RPC_RESPONSE, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ADDR, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TAX, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_COND_TX, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TOKEN_TICKER, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TS_CREATED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PRICE, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TX, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_ENOUGH_FUNDS, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_SIGN, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_ITEMS_FOUND, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_COND_TX, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TOKEN_TICKER, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TIMESTAMP, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INSUFFICIENT_FUNDS, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE_FAILED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_COIN_RETURN_FAILED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NET_FEE_FAILED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_COINBACK_FAILED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_TOO_HIGH, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_VALIDATOR_FEE_FAILED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_ALREADY_USED, + SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_OWNER +} srv_stake_order_remove_compose_error_t; json_object * dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port) { compose_config_t *l_config = s_compose_config_init(l_net_str, l_url_str, l_port); diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index 7d42deaa98..e70baec8da 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -70,19 +70,7 @@ uint16_t dap_compose_get_net_port(const char* name); json_object* dap_tx_create_compose(const char *l_net_str, const char *l_token_ticker, const char *l_value_str, const char *l_fee_str, const char *addr_base58_to, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port); json_object* dap_tx_create_xchange_compose(const char *l_net_str, const char *l_token_sell, const char *l_token_buy, const char *l_wallet_str, const char *l_wallet_path, const char *l_value_str, const char *l_rate_str, const char *l_fee_str, const char *l_url_str, uint16_t l_port); -typedef enum dap_tx_cond_create_compose_error { - TX_COND_CREATE_COMPOSE_ERROR_INVALID_FEE = 1, - TX_COND_CREATE_COMPOSE_ERROR_INVALID_SERVICE_UID, - TX_COND_CREATE_COMPOSE_ERROR_INVALID_UNIT, - TX_COND_CREATE_COMPOSE_ERROR_INVALID_VALUE, - TX_COND_CREATE_COMPOSE_ERROR_WALLET_OPEN_FAILED, - TX_COND_CREATE_COMPOSE_ERROR_CERT_NOT_FOUND, - TX_COND_CREATE_COMPOSE_ERROR_INVALID_CERT_KEY, - TX_COND_CREATE_COMPOSE_ERROR_NATIVE_TOKEN_REQUIRED, - TX_COND_CREATE_COMPOSE_ERROR_NOT_ENOUGH_FUNDS, - TX_COND_CREATE_COMPOSE_ERROR_COND_OUTPUT_FAILED, - TX_COND_CREATE_COMPOSE_ERROR_COIN_BACK_FAILED -} dap_tx_cond_create_compose_error_t; + json_object* dap_tx_cond_create_compose(const char *a_net_name, const char *a_token_ticker, const char *a_wallet_str, const char *a_wallet_path, const char *a_cert_str, const char *a_value_datoshi_str, const char *a_value_fee_str, const char *a_unit_str, const char *a_srv_uid_str, const char *a_url_str, uint16_t a_port); @@ -91,145 +79,26 @@ json_object * dap_cli_hold_compose(const char *a_net_name, const char *a_chain_i const char *a_cert_str, const char *a_value_fee_str, const char *a_reinvest_percent_str, const char *a_url_str, uint16_t a_port); json_object* dap_cli_take_compose(const char *a_net_name, const char *a_chain_id_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_tx_str, const char *a_tx_burning_str, const char *a_value_fee_str, const char *a_url_str, uint16_t a_port); -int dap_cli_voting_compose(int a_argc, char **a_argv); -typedef enum { - STAKE_ORDER_CREATE_STAKER_OK = 0, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_PARAMS = -1, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_VALUE = -2, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_FEE = -3, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_TAX = -4, - STAKE_ORDER_CREATE_STAKER_ERR_WALLET_NOT_FOUND = -5, - STAKE_ORDER_CREATE_STAKER_ERR_KEY_NOT_FOUND = -6, - STAKE_ORDER_CREATE_STAKER_ERR_INVALID_ADDR = -7, - STAKE_ORDER_CREATE_STAKER_ERR_TX_CREATE_FAILED = -8, - STAKE_ORDER_CREATE_STAKER_ERR_JSON_FAILED = -9 -} dap_cli_srv_stake_order_create_staker_error_t; +json_object* dap_cli_voting_compose(const char *a_net_name, const char *a_question_str, const char *a_options_list_str, + const char *a_voting_expire_str, const char *a_max_votes_count_str, const char *a_fee_str, + bool a_is_delegated_key, bool a_is_vote_changing_allowed, const char *a_wallet_str, const char *a_wallet_path, + const char *a_token_str, const char *a_url_str, uint16_t a_port); + json_object* dap_cli_srv_stake_order_create_staker_compose(const char *l_net_str, const char *l_value_str, const char *l_fee_str, const char *l_tax_str, const char *l_addr_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port); -typedef enum { - SRV_STAKE_ORDER_REMOVE_COMPOSE_OK = 0, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PARAMS, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_WALLET_NOT_FOUND, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_KEY_NOT_FOUND, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_FEE, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ORDER_HASH, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_RPC_RESPONSE, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_ADDR, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TAX, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_COND_TX, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TOKEN_TICKER, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TS_CREATED, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_PRICE, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_TX, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_ENOUGH_FUNDS, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_SIGN, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_ITEMS_FOUND, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_COND_TX, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TOKEN_TICKER, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NO_TIMESTAMP, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_INSUFFICIENT_FUNDS, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_COMPOSE_FAILED, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_COIN_RETURN_FAILED, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NET_FEE_FAILED, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_COINBACK_FAILED, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_FEE_TOO_HIGH, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_VALIDATOR_FEE_FAILED, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_TX_ALREADY_USED, - SRV_STAKE_ORDER_REMOVE_COMPOSE_ERR_NOT_OWNER -} srv_stake_order_remove_compose_error_t; dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(dap_hash_fast_t *a_hash_tx, uint256_t a_fee, dap_chain_wallet_t *a_wallet, compose_config_t *a_config); json_object* dap_cli_srv_stake_order_remove_compose(const char *l_net_str, const char *l_order_hash_str, const char *l_fee_str, const char *l_wallet_str, const char *l_wallet_path, const char *l_url_str, uint16_t l_port); -typedef enum { - STAKE_DELEGATE_COMPOSE_OK = 0, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_VALUE = -1, - STAKE_DELEGATE_COMPOSE_ERR_WALLET_NOT_FOUND = -2, - STAKE_DELEGATE_COMPOSE_ERR_CERT_NOT_FOUND = -3, - STAKE_DELEGATE_COMPOSE_ERR_CERT_WRONG = -4, - STAKE_DELEGATE_COMPOSE_ERR_WRONG_SIGN_TYPE = -5, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_PKEY = -6, - STAKE_DELEGATE_COMPOSE_ERR_PKEY_UNDEFINED = -7, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_NODE_ADDR = -8, - STAKE_DELEGATE_COMPOSE_ERR_ORDER_NOT_FOUND = -9, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER_SIZE = -10, - STAKE_DELEGATE_COMPOSE_ERR_CERT_REQUIRED = -11, - STAKE_DELEGATE_COMPOSE_ERR_VALUE_REQUIRED = -12, - STAKE_DELEGATE_COMPOSE_ERR_WRONG_TICKER = -13, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_FORMAT = -14, - STAKE_DELEGATE_COMPOSE_ERR_RPC_RESPONSE = -15, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_VALUE = -16, - STAKE_DELEGATE_COMPOSE_ERR_NO_ITEMS = -17, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_COND_TX_ADDR = -18, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_SIGNER_ADDR = -19, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_SOVEREIGN_ADDR = -20, - STAKE_DELEGATE_COMPOSE_ERR_NO_TOKEN_TICKER = -21, - STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_LOW = -22, - STAKE_DELEGATE_COMPOSE_ERR_VALUE_TOO_HIGH = -23, - STAKE_DELEGATE_COMPOSE_ERR_UNSIGNED_ORDER = -24, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_ORDER = -25, - STAKE_DELEGATE_COMPOSE_ERR_INVALID_TAX = -26, - STAKE_DELEGATE_COMPOSE_ERR_VALUE_BELOW_MIN = -27, - DAP_STAKE_TX_CREATE_COMPOSE_INVALID_PARAMS = -28, - DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_FEE = -29, - DAP_STAKE_TX_CREATE_COMPOSE_NOT_ENOUGH_FUNDS_VALUE = -30, - DAP_STAKE_TX_CREATE_COMPOSE_TX_IN_ERROR = -31, - DAP_STAKE_TX_CREATE_COMPOSE_TX_COND_OUT_ERROR = -32, - DAP_STAKE_TX_CREATE_COMPOSE_TX_OUT_ERROR = -33, - DAP_STAKE_TX_CREATE_COMPOSE_NET_FEE_ERROR = -34, - DAP_STAKE_TX_CREATE_COMPOSE_VALIDATOR_FEE_ERROR = -35, - DAP_STAKE_TX_CREATE_COMPOSE_FEE_BACK_ERROR = -36 -} stake_delegate_error_t; json_object* dap_cli_srv_stake_delegate_compose(const char* a_net_str, const char* a_wallet_str, const char* a_cert_str, const char* a_pkey_full_str, const char* a_sign_type_str, const char* a_value_str, const char* a_node_addr_str, const char* a_order_hash_str, const char* a_url_str, uint16_t a_port, const char* a_sovereign_addr_str, const char* a_fee_str, const char* a_wallets_path); -typedef enum { - DAP_CLI_STAKE_INVALIDATE_OK = 0, - DAP_CLI_STAKE_INVALIDATE_CERT_NOT_FOUND = -1, - DAP_CLI_STAKE_INVALIDATE_PRIVATE_KEY_MISSING = -2, - DAP_CLI_STAKE_INVALIDATE_WRONG_CERT = -3, - DAP_CLI_STAKE_INVALIDATE_LEDGER_ERROR = -4, - DAP_CLI_STAKE_INVALIDATE_INVALID_TX_HASH = -5, - DAP_CLI_STAKE_INVALIDATE_NOT_DELEGATED = -6, - DAP_CLI_STAKE_INVALIDATE_NO_DELEGATE_OUT = -7, - DAP_CLI_STAKE_INVALIDATE_PREV_TX_NOT_FOUND = -8, - DAP_CLI_STAKE_INVALIDATE_TX_EXISTS = -9, - DAP_CLI_STAKE_INVALIDATE_WALLET_NOT_FOUND = -10, - DAP_CLI_STAKE_INVALIDATE_COMPOSE_ERROR = -11, - DAP_STAKE_TX_INVALIDATE_COMPOSE_LEDGER_ERROR = -12, - DAP_STAKE_TX_INVALIDATE_COMPOSE_ITEMS_NOT_FOUND = -13, - DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTPUTS_SPENT = -14, - DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_HASH_NOT_FOUND = -15, - DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_ERROR = -16, - DAP_STAKE_TX_INVALIDATE_COMPOSE_COND_TX_NOT_FOUND = -17, - DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_NOT_FOUND = -18, - DAP_STAKE_TX_INVALIDATE_COMPOSE_SIG_DECODE_ERROR = -19, - DAP_STAKE_TX_INVALIDATE_COMPOSE_WRONG_OWNER = -20, - DAP_STAKE_TX_INVALIDATE_COMPOSE_TOKEN_NOT_FOUND = -21, - DAP_STAKE_TX_INVALIDATE_COMPOSE_OUTS_NOT_FOUND = -22, - DAP_STAKE_TX_INVALIDATE_COMPOSE_NOT_ENOUGH_FUNDS = -23, - DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_IN_ERROR = -24, - DAP_STAKE_TX_INVALIDATE_COMPOSE_TX_OUT_ERROR = -25, - DAP_STAKE_TX_INVALIDATE_COMPOSE_NET_FEE_ERROR = -26, - DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_ERROR = -27, - DAP_STAKE_TX_INVALIDATE_COMPOSE_FEE_BACK_ERROR = -28, - DAP_CLI_STAKE_INVALIDATE_FEE_ERROR = -29 -} dap_cli_stake_invalidate_error_t; + dap_chain_datum_tx_t *dap_stake_tx_invalidate_compose(dap_hash_fast_t *a_tx_hash, uint256_t a_fee, dap_enc_key_t *a_key, compose_config_t *a_config); json_object* dap_cli_srv_stake_invalidate_compose(const char *a_net_str, const char *a_tx_hash_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_cert_str, const char *a_fee_str, const char *a_url_str, uint16_t a_port); -typedef enum { - DAP_COMPOSE_ERROR_NONE = 0, - DAP_COMPOSE_ERROR_RESPONSE_NULL = -1, - DAP_COMPOSE_ERROR_RESULT_NOT_FOUND = -2, - DAP_COMPOSE_ERROR_REQUEST_INIT_FAILED = -3, - DAP_COMPOSE_ERROR_REQUEST_TIMEOUT = -4, - DAP_COMPOSE_ERROR_REQUEST_FAILED = -5 -} dap_compose_error_t; + json_object* dap_request_command_to_rpc(const char *request, compose_config_t *a_config); int dap_tx_json_tsd_add(json_object * json_tx, json_object * json_add); @@ -265,7 +134,7 @@ dap_chain_datum_tx_t *dap_stake_unlock_datum_create_compose(dap_enc_key_t *a_key dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, - const char *a_net_str, const char *a_token_ticker, const char *l_url_str, uint16_t l_port); + const char *a_token_ticker, compose_config_t *a_config); dap_chain_datum_tx_t *dap_stake_tx_create_compose(dap_enc_key_t *a_key, uint256_t a_value, uint256_t a_fee, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, -- GitLab From 7f651debd2867bb96a97b368c7c9fff0f7e7fcc6 Mon Sep 17 00:00:00 2001 From: Olzhas <oljas.jarasbaev@demlabs.net> Date: Thu, 17 Apr 2025 17:19:16 +0700 Subject: [PATCH 52/53] [+] purchase --- modules/compose/dap_chain_tx_compose.c | 1014 ++++++++++------- .../compose/include/dap_chain_tx_compose.h | 12 +- 2 files changed, 636 insertions(+), 390 deletions(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 01a0815284..56681e539e 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -2548,334 +2548,295 @@ dap_chain_datum_tx_t* dap_chain_net_vote_create_compose(const char *a_question, return l_tx; } -/** -int dap_cli_vote_compose(int a_argc, char **a_argv){ - const char* l_cert_name = NULL; - const char* l_fee_str = NULL; - const char* l_wallet_str = NULL; - const char* l_hash_str = NULL; - const char* l_option_idx_str = NULL; - const char* l_net_str = NULL; - int arg_index = 1; - - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); - if(!l_net_str) { - printf("command requires parameter '-net'\n"); - return -DAP_CHAIN_NET_VOTE_VOTING_NET_PARAM_MISSING; - } - - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hash", &l_hash_str); - if(!l_hash_str){ - printf("Command 'vote' require the parameter -hash\n"); - return -DAP_CHAIN_NET_VOTE_VOTING_HASH_NOT_FOUND; - } - dap_hash_fast_t l_voting_hash = {}; - if (dap_chain_hash_fast_from_str(l_hash_str, &l_voting_hash)) { - printf("Hash string is not recognozed as hex of base58 hash\n"); - return -DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID; - } - - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_name); - dap_cert_t * l_cert = dap_cert_find_by_name(l_cert_name); - if (l_cert_name){ - if (l_cert == NULL) { - printf("Can't find \"%s\" certificate\n", l_cert_name); - return -DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_FIND_CERT; - } - } +// json_object* dap_cli_vote_compose(const char *a_net_str, const char *a_hash_str, const char *a_cert_name, const char *a_fee_str, const char *a_wallet_str, const char *a_wallet_path, const char *a_option_idx_str, const char *a_url_str, uint16_t a_port) { +// compose_config_t *l_config = s_compose_config_init(a_net_str, a_url_str, a_port); +// if (!l_config) { +// json_object* l_json_obj_ret = json_object_new_object(); +// dap_json_compose_error_add(l_json_obj_ret, TX_CREATE_COMPOSE_INVALID_CONFIG, "Can't create compose config"); +// return l_json_obj_ret; +// } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str); - if (!l_fee_str){ - printf("Command 'vote' requires paramete -fee to be valid.\n"); - return -DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_NOT_VALID; - } - uint256_t l_value_fee = dap_chain_balance_scan(l_fee_str); - if (IS_ZERO_256(l_value_fee)) { - printf("command requires parameter '-fee' to be valid uint256\n"); - return -DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_BAD_TYPE; - } +// dap_hash_fast_t l_voting_hash = {}; +// if (dap_chain_hash_fast_from_str(a_hash_str, &l_voting_hash)) { +// dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_HASH_INVALID, "Hash string is not recognozed as hex of base58 hash\n"); +// return s_compose_config_return_response_handler(l_config); +// } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_str); - if (!l_wallet_str){ - printf("Command 'vote' requires parameter -w to be valid.\n"); - return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_PARAM_NOT_VALID; - } +// dap_cert_t * l_cert = dap_cert_find_by_name(a_cert_name); +// if (a_cert_name){ +// if (l_cert == NULL) { +// dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_FIND_CERT, "Can't find \"%s\" certificate\n", l_cert_name); +// return s_compose_config_return_response_handler(l_config); +// } +// } +// uint256_t l_value_fee = dap_chain_balance_scan(a_fee_str); +// if (IS_ZERO_256(l_value_fee)) { +// dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_FEE_PARAM_BAD_TYPE, "command requires parameter '-fee' to be valid uint256\n"); +// return s_compose_config_return_response_handler(l_config); +// } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-option_idx", &l_option_idx_str); - if (!l_option_idx_str){ - printf("Command 'vote' requires parameter -option_idx to be valid.\n"); - return -DAP_CHAIN_NET_VOTE_VOTING_OPTION_IDX_PARAM_NOT_VALID; - } - const char *l_wallet_path = dap_chain_wallet_get_path(g_config); - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallet_path,NULL); - if (!l_wallet) { - printf("Wallet %s does not exist\n", l_wallet_str); - return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST; - } +// const char *l_wallet_path = dap_chain_wallet_get_path(g_config); +// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_str, a_wallet_path,NULL); +// if (!l_wallet) { +// dap_json_compose_error_add(l_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST, "Wallet %s does not exist\n", a_wallet_str); +// return s_compose_config_return_response_handler(l_config); +// } - uint64_t l_option_idx_count = strtoul(l_option_idx_str, NULL, 10); +// uint64_t l_option_idx_count = strtoul(a_option_idx_str, NULL, 10); - char *l_hash_tx; +// char *l_hash_tx; - int res = dap_chain_net_vote_voting_compose(l_cert, l_value_fee, l_wallet, l_voting_hash, l_option_idx_count, - l_net_str, &l_hash_tx); - dap_chain_wallet_close(l_wallet); +// int res = dap_chain_net_vote_voting_compose(l_cert, l_value_fee, l_wallet, l_voting_hash, l_option_idx_count, &l_hash_tx, l_config); +// dap_chain_wallet_close(l_wallet); - return res; -} +// return res; +// } -int dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wallet_t *a_wallet, dap_hash_fast_t a_hash, - uint64_t a_option_idx, const char *a_net_str, const char *a_hash_out_type, - char **a_hash_tx_out) { - const char * l_hash_str = dap_chain_hash_fast_to_str_static(&a_hash); - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"voting\",\"params\": [\"voting;dump;-hash;%s\"],\"id\": \"2\"}", l_hash_str); - json_object *l_json_voting = dap_request_command_to_rpc(data); - if (!l_json_voting) { - printf("Error: Can't get voting info\n"); - return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; - } +// dap_chain_datum_tx_t* dap_chain_net_vote_voting_compose(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wallet_t *a_wallet, dap_hash_fast_t a_hash, +// uint64_t a_option_idx, const char *a_hash_out_type, +// char **a_hash_tx_out, compose_config_t *a_config) { +// if (!a_config) { +// return NULL; +// } +// const char * l_hash_str = dap_chain_hash_fast_to_str_static(&a_hash); +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"voting\",\"params\": [\"voting;dump;-hash;%s\"],\"id\": \"2\"}", l_hash_str); +// json_object *l_json_voting = dap_request_command_to_rpc(data, a_config); +// if (!l_json_voting) { +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS, "Error: Can't get voting info\n"); +// return NULL; +// } - json_object *l_voting_info = json_object_array_get_idx(l_json_voting, 0); - if (!l_voting_info) { - printf("Error: Can't get voting info from JSON\n"); - return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; - } - - const char *l_voting_tx = json_object_get_string(json_object_object_get(l_voting_info, "voting_tx")); - const char *l_expiration_str = json_object_get_string(json_object_object_get(l_voting_info, "expiration")); - const char *l_status = json_object_get_string(json_object_object_get(l_voting_info, "status")); - int l_votes_max = json_object_get_int(json_object_object_get(l_voting_info, "votes_max")); - int l_votes_available = json_object_get_int(json_object_object_get(l_voting_info, "votes_available")); - bool l_vote_changed = json_object_get_boolean(json_object_object_get(l_voting_info, "can_change_status")); - bool l_delegated_key_required = json_object_get_boolean(json_object_object_get(l_voting_info, "delegated_key_required")); - - json_object *l_results = json_object_object_get(l_voting_info, "results"); - if (!l_results) { - printf("Error: Can't get results from JSON\n"); - return -DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS; - } - - int l_results_count = json_object_array_length(l_results); +// json_object *l_voting_info = json_object_array_get_idx(l_json_voting, 0); +// if (!l_voting_info) { +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS, "Error: Can't get voting info from JSON\n"); +// return NULL; +// } +// const char *l_voting_tx = json_object_get_string(json_object_object_get(l_voting_info, "voting_tx")); +// const char *l_expiration_str = json_object_get_string(json_object_object_get(l_voting_info, "expiration")); +// const char *l_status = json_object_get_string(json_object_object_get(l_voting_info, "status")); +// int l_votes_max = json_object_get_int(json_object_object_get(l_voting_info, "votes_max")); +// int l_votes_available = json_object_get_int(json_object_object_get(l_voting_info, "votes_available")); +// bool l_vote_changed = json_object_get_boolean(json_object_object_get(l_voting_info, "can_change_status")); +// bool l_delegated_key_required = json_object_get_boolean(json_object_object_get(l_voting_info, "delegated_key_required")); + +// json_object *l_results = json_object_object_get(l_voting_info, "results"); +// if (!l_results) { +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_CREATE_ERROR_CAN_NOT_GET_TX_OUTS, "Error: Can't get results from JSON\n"); +// return NULL; +// } - if (l_votes_max && l_votes_max <= l_results_count) - return DAP_CHAIN_NET_VOTE_VOTING_THIS_VOTING_HAVE_MAX_VALUE_VOTES; +// int l_results_count = json_object_array_length(l_results); - if (l_expiration_str) { - struct tm tm; - strptime(l_expiration_str, "%a, %d %b %Y %H:%M:%S %z", &tm); - time_t l_expiration_time = mktime(&tm); - if (l_expiration_time && dap_time_now() > l_expiration_time) - return DAP_CHAIN_NET_VOTE_VOTING_ALREADY_EXPIRED; - } - dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_net_str)); - if (!l_addr_from) - return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID; +// if (l_votes_max && l_votes_max <= l_results_count) +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_THIS_VOTING_HAVE_MAX_VALUE_VOTES, "This voting have max value votes\n"); +// return NULL; - dap_hash_fast_t l_pkey_hash = {0}; - if (l_delegated_key_required) { - if (!a_cert) - return DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED; - if (dap_cert_get_pkey_hash(a_cert, &l_pkey_hash)) - return DAP_CHAIN_NET_VOTE_VOTING_NO_KEY_FOUND_IN_CERT; - char data[512]; - snprintf(data, sizeof(data), - "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); - json_object *l_json_coins = dap_request_command_to_rpc(data); - if (!l_json_coins) { - printf("Error: Failed to retrieve coins from ledger\n"); - return -4; - } - const char * l_hash_fast_str[DAP_HASH_FAST_STR_SIZE] = {}; - dap_chain_hash_fast_from_str(l_hash_fast_str, &l_pkey_hash); - if (!l_hash_fast_str) { - printf("Error: Can't covert l_pkey_hash to str"); - return -5; - } - int items_count = json_object_array_length(l_json_coins); - bool found = false; - for (int i = 0; i < items_count; i++) { - json_object *item = json_object_array_get_idx(l_json_coins, i); - const char *pkey_hash_str = json_object_get_string(json_object_object_get(item, "pkey_hash")); - if (l_hash_fast_str && !dap_strcmp(l_hash_fast_str, pkey_hash_str)) { - const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash")); - if (dap_chain_hash_fast_from_str(tx_hash_str, &l_pkey_hash)) { - printf("Invalid transaction hash format\n"); - return DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED; - } - found = true; - break; - } - } - if (!found) { - printf("Specified certificate/pkey hash is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n"); - return -9; - } +// if (l_expiration_str) { +// struct tm tm; +// strptime(l_expiration_str, "%a, %d %b %Y %H:%M:%S %z", &tm); +// time_t l_expiration_time = mktime(&tm); +// if (l_expiration_time && dap_time_now() > l_expiration_time) +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_ALREADY_EXPIRED, "This voting already expired\n"); +// return NULL; +// } +// dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(l_config->net_name)); +// if (!l_addr_from) +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID, "Source address is invalid\n"); +// return NULL; + +// dap_hash_fast_t l_pkey_hash = {0}; +// if (l_delegated_key_required) { +// if (!a_cert) +// return DAP_CHAIN_NET_VOTE_VOTING_CERT_REQUIRED; +// if (dap_cert_get_pkey_hash(a_cert, &l_pkey_hash)) +// return DAP_CHAIN_NET_VOTE_VOTING_NO_KEY_FOUND_IN_CERT; +// char data[512]; +// snprintf(data, sizeof(data), +// "{\"method\": \"srv_stake\",\"params\": [\"srv_stake;list;keys;-net;%s\"],\"id\": \"1\"}", a_net_str); +// json_object *l_json_coins = dap_request_command_to_rpc(data, a_config); +// if (!l_json_coins) { +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_FAILED_TO_RETRIEVE_COINS_FROM_LEDGER, "Failed to retrieve coins from ledger\n"); +// return NULL; +// } +// const char * l_hash_fast_str[DAP_HASH_FAST_STR_SIZE] = {}; +// dap_chain_hash_fast_from_str(l_hash_fast_str, &l_pkey_hash); +// if (!l_hash_fast_str) { +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_FAILED_TO_RETRIEVE_COINS_FROM_LEDGER, "Can't covert l_pkey_hash to str"); +// return NULL; +// } +// int items_count = json_object_array_length(l_json_coins); +// bool found = false; +// for (int i = 0; i < items_count; i++) { +// json_object *item = json_object_array_get_idx(l_json_coins, i); +// const char *pkey_hash_str = json_object_get_string(json_object_object_get(item, "pkey_hash")); +// if (l_hash_fast_str && !dap_strcmp(l_hash_fast_str, pkey_hash_str)) { +// const char *tx_hash_str = json_object_get_string(json_object_object_get(item, "tx_hash")); +// if (dap_chain_hash_fast_from_str(tx_hash_str, &l_pkey_hash)) { +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED, "Invalid transaction hash format\n"); +// return NULL; +// } +// found = true; +// break; +// } +// } +// if (!found) { +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_KEY_IS_NOT_DELEGATED, "Specified certificate/pkey hash is not delegated nor this delegating is approved. Try to invalidate with tx hash instead\n"); +// return NULL; +// } - } else - l_pkey_hash = l_addr_from->data.hash_fast; +// } else +// l_pkey_hash = l_addr_from->data.hash_fast; - const char *l_token_ticker = json_object_get_string(json_object_object_get(l_voting_info, "token")); - uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer; - dap_chain_addr_t* l_addr_fee = NULL; - bool l_net_fee_used = dap_get_remote_net_fee_and_address(a_net_str, &l_net_fee, &l_addr_fee); - if (l_net_fee_used) - SUM_256_256(l_net_fee, a_fee, &l_total_fee); - bool l_native_tx = !dap_strcmp(l_token_ticker, s_get_native_ticker(a_net_str)); +// const char *l_token_ticker = json_object_get_string(json_object_object_get(l_voting_info, "token")); +// uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer; +// dap_chain_addr_t* l_addr_fee = NULL; +// bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_addr_fee, l_config); +// if (l_net_fee_used) +// SUM_256_256(l_net_fee, a_fee, &l_total_fee); - json_object *l_outs = NULL; - int l_outputs_count = 0; - if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_token_ticker, a_net_str, &l_outs, &l_outputs_count)) { - return -11; - } +// bool l_native_tx = !dap_strcmp(l_token_ticker, s_get_native_ticker(l_config->net_name)); - dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, - l_total_fee, - &l_value_transfer); - json_object_put(l_outs); - if (!l_list_used_out) { - printf("Not enough funds to transfer"); - return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER; - } - - // check outputs UTXOs - uint256_t l_value_transfer_new = {}; - dap_list_t *it, *tmp; - DL_FOREACH_SAFE(l_list_used_out, it, tmp) { - dap_chain_tx_used_out_item_t *l_out = (dap_chain_tx_used_out_item_t *)it->data; - if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out, - l_vote_changed ? &l_pkey_hash : NULL)) { - l_list_used_out = dap_list_delete_link(l_list_used_out, it); - continue; - } - if (SUM_256_256(l_value_transfer_new, l_out->value, &l_value_transfer_new)) - return DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW; - } +// json_object *l_outs = NULL; +// int l_outputs_count = 0; +// if (!dap_get_remote_wallet_outs_and_count(l_addr_from, l_token_ticker, l_config->net_name, &l_outs, &l_outputs_count)) { +// dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_VOTE_VOTING_FAILED_TO_GET_REMOTE_WALLET_OUTS, "Failed to get remote wallet outs\n"); +// return NULL; +// } - if (IS_ZERO_256(l_value_transfer_new) || (l_native_tx && compare256(l_value_transfer_new, l_total_fee) <= 0)) - return DAP_CHAIN_NET_VOTE_VOTING_UNSPENT_UTX0_FOR_PARTICIPATION_THIS_VOTING; +// dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, +// l_total_fee, +// &l_value_transfer); +// json_object_put(l_outs); +// if (!l_list_used_out) { +// printf("Not enough funds to transfer"); +// return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER; +// } - l_value_transfer = l_value_transfer_new; +// // check outputs UTXOs +// uint256_t l_value_transfer_new = {}; +// dap_list_t *it, *tmp; +// DL_FOREACH_SAFE(l_list_used_out, it, tmp) { +// dap_chain_tx_used_out_item_t *l_out = (dap_chain_tx_used_out_item_t *)it->data; +// if (s_datum_tx_voting_coin_check_spent(a_net, a_hash, l_out->tx_hash_fast, l_out->num_idx_out, +// l_vote_changed ? &l_pkey_hash : NULL)) { +// l_list_used_out = dap_list_delete_link(l_list_used_out, it); +// continue; +// } +// if (SUM_256_256(l_value_transfer_new, l_out->value, &l_value_transfer_new)) +// return DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW; +// } - // create empty transaction - dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); +// if (IS_ZERO_256(l_value_transfer_new) || (l_native_tx && compare256(l_value_transfer_new, l_total_fee) <= 0)) +// return DAP_CHAIN_NET_VOTE_VOTING_UNSPENT_UTX0_FOR_PARTICIPATION_THIS_VOTING; - uint256_t l_value_back = l_value_transfer, l_fee_back = {}; - if (!l_native_tx) { - dap_list_t *l_list_fee_outs = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_net->pub.native_ticker, l_addr_from, l_total_fee, &l_fee_transfer); - if (!l_list_fee_outs) { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER; - } - uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_outs); - assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); - dap_list_free_full(l_list_fee_outs, NULL); - SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_back); - } else - SUBTRACT_256_256(l_value_transfer, l_total_fee, &l_value_back); +// l_value_transfer = l_value_transfer_new; - // add 'in' items - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); - assert(EQUAL_256(l_value_to_items, l_value_transfer)); - dap_list_free_full(l_list_used_out, NULL); +// // create empty transaction +// dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - // Add vote item - if (a_option_idx > dap_list_length(l_voting->voting_params.option_offsets_list)){ - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_INVALID_OPTION_INDEX; - } - dap_chain_tx_vote_t* l_vote_item = dap_chain_datum_tx_item_vote_create(&a_hash, &a_option_idx); - if(!l_vote_item){ - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_VOTE_ITEM; - } - dap_chain_datum_tx_add_item(&l_tx, l_vote_item); - DAP_DEL_Z(l_vote_item); - - // add out conds items - dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from); - for (dap_list_t *it = l_outs; it; it = it->next) { - dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data; - if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out, - l_vote_changed ? &l_pkey_hash : NULL) != 0) - continue; - dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out); - if(!l_item){ - dap_chain_datum_tx_delete(l_tx); - - dap_list_free_full(l_outs, NULL); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_TSD_TX_COND_ITEM; - } - dap_chain_datum_tx_add_item(&l_tx, l_item); - DAP_DEL_Z(l_item); - } - dap_list_free_full(l_outs, NULL); +// uint256_t l_value_back = l_value_transfer, l_fee_back = {}; +// if (!l_native_tx) { +// dap_list_t *l_list_fee_outs = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_net->pub.native_ticker, l_addr_from, l_total_fee, &l_fee_transfer); +// if (!l_list_fee_outs) { +// dap_chain_datum_tx_delete(l_tx); +// return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER; +// } +// uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_outs); +// assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); +// dap_list_free_full(l_list_fee_outs, NULL); +// SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_back); +// } else +// SUBTRACT_256_256(l_value_transfer, l_total_fee, &l_value_back); + +// // add 'in' items +// uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); +// assert(EQUAL_256(l_value_to_items, l_value_transfer)); +// dap_list_free_full(l_list_used_out, NULL); + +// // Add vote item +// if (a_option_idx > dap_list_length(l_voting->voting_params.option_offsets_list)){ +// dap_chain_datum_tx_delete(l_tx); +// return DAP_CHAIN_NET_VOTE_VOTING_INVALID_OPTION_INDEX; +// } +// dap_chain_tx_vote_t* l_vote_item = dap_chain_datum_tx_item_vote_create(&a_hash, &a_option_idx); +// if(!l_vote_item){ +// dap_chain_datum_tx_delete(l_tx); +// return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_VOTE_ITEM; +// } +// dap_chain_datum_tx_add_item(&l_tx, l_vote_item); +// DAP_DEL_Z(l_vote_item); + +// // add out conds items +// dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from); +// for (dap_list_t *it = l_outs; it; it = it->next) { +// dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data; +// if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out, +// l_vote_changed ? &l_pkey_hash : NULL) != 0) +// continue; +// dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out); +// if(!l_item){ +// dap_chain_datum_tx_delete(l_tx); + +// dap_list_free_full(l_outs, NULL); +// return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_CREATE_TSD_TX_COND_ITEM; +// } +// dap_chain_datum_tx_add_item(&l_tx, l_item); +// DAP_DEL_Z(l_item); +// } +// dap_list_free_full(l_outs, NULL); - // Network fee - if (l_net_fee_used && dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, a_net->pub.native_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; - } +// // Network fee +// if (l_net_fee_used && dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, a_net->pub.native_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; +// } - // Validator's fee - if (!IS_ZERO_256(a_fee) && dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; - } +// // Validator's fee +// if (!IS_ZERO_256(a_fee) && dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; +// } - // coin back - if (!IS_ZERO_256(l_value_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_token_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; - } - if (!IS_ZERO_256(l_fee_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_fee_back, a_net->pub.native_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; - } +// // coin back +// if (!IS_ZERO_256(l_value_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_token_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; +// } +// if (!IS_ZERO_256(l_fee_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_fee_back, a_net->pub.native_ticker) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; +// } - dap_enc_key_t *l_priv_key = dap_chain_wallet_get_key(a_wallet, 0); - // add 'sign' items with wallet sign - if (dap_chain_datum_tx_add_sign_item(&l_tx, l_priv_key) != 1) { - dap_chain_datum_tx_delete(l_tx); - dap_enc_key_delete(l_priv_key); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX; - } - dap_enc_key_delete(l_priv_key); +// dap_enc_key_t *l_priv_key = dap_chain_wallet_get_key(a_wallet, 0); +// // add 'sign' items with wallet sign +// if (dap_chain_datum_tx_add_sign_item(&l_tx, l_priv_key) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// dap_enc_key_delete(l_priv_key); +// return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX; +// } +// dap_enc_key_delete(l_priv_key); - // add 'sign' items with delegated key if needed - if (a_cert && dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX; - } +// // add 'sign' items with delegated key if needed +// if (a_cert && dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) { +// dap_chain_datum_tx_delete(l_tx); +// return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_SIGN_TX; +// } - size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx); - dap_hash_fast_t l_tx_hash; - dap_hash_fast(l_tx, l_tx_size, &l_tx_hash); - dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, l_tx_size); - DAP_DELETE(l_tx); - dap_chain_t* l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX); - char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, a_hash_out_type); - DAP_DELETE(l_datum); - if (l_ret) { - *a_hash_tx_out = l_ret; - return DAP_CHAIN_NET_VOTE_VOTING_OK; - } else { - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_POOL_IN_MEMPOOL; - } -} +// return l_tx; +// } -*/ @@ -4494,109 +4455,388 @@ dap_chain_datum_tx_t* dap_chain_net_srv_xchange_remove_compose(dap_hash_fast_t * DAP_DELETE(l_price); return l_tx; } +typedef enum dap_tx_create_xchange_purchase_compose_error { + DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_NONE = 0, + DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_CONFIG_CREATE, + DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_FEE, + DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_HASH, + DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_WALLET_NOT_FOUND +} dap_tx_create_xchange_purchase_compose_error_t; + +json_object *dap_tx_create_xchange_purchase_compose (const char *a_net_name, const char *a_order_hash, const char* a_value, + const char* a_fee, const char *a_wallet_name, const char *a_wallet_path, + const char *a_url_str, uint16_t a_port) { + compose_config_t *l_config = s_compose_config_init(a_net_name, a_url_str, a_port); + if (!l_config) { + json_object *l_json_obj_ret = json_object_new_object(); + dap_json_compose_error_add(l_json_obj_ret, DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_CONFIG_CREATE, "Can't create compose config"); + return l_json_obj_ret; + } + uint256_t l_datoshi_buy = dap_chain_balance_scan(a_value); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(a_wallet_name, a_wallet_path, NULL); + if (!l_wallet) { + dap_json_compose_error_add(l_config->response_handler, DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_WALLET_NOT_FOUND, "Specified wallet not found"); + return s_compose_config_return_response_handler(l_config); + } -// srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value> -// int dap_tx_create_xchange_purchase_compose(int argc, char ** argv) { -// int arg_index = 1; -// const char * l_net_name = NULL; -// const char * l_wallet_name = NULL; -// const char * l_order_hash = NULL; -// const char * l_value = NULL; -// const char * l_fee = NULL; + uint256_t l_datoshi_fee = dap_chain_balance_scan(a_fee); + if (IS_ZERO_256(l_datoshi_fee)) { + dap_json_compose_error_add(l_config->response_handler, DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_FEE, "Fee must be greater than 0"); + return s_compose_config_return_response_handler(l_config); + } + dap_hash_fast_t l_tx_hash = {}; + dap_chain_hash_fast_from_str(a_order_hash, &l_tx_hash); + if (dap_hash_fast_is_blank(&l_tx_hash)) { + dap_json_compose_error_add(l_config->response_handler, DAP_TX_CREATE_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_HASH, "Invalid order hash"); + return s_compose_config_return_response_handler(l_config); + } + char *l_str_ret_hash = NULL; + dap_chain_datum_tx_t *l_tx = dap_chain_net_srv_xchange_purchase_compose(&l_tx_hash, l_datoshi_buy, l_datoshi_fee, + l_wallet, &l_str_ret_hash, l_config); + if (l_tx) { + dap_chain_net_tx_to_json(l_tx, l_config->response_handler); + DAP_DELETE(l_tx); + } + return s_compose_config_return_response_handler(l_config); +} -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-net", &l_net_name); -// if (!l_net_name) { -// printf("tx_create requires parameter '-net'"); -// return -1; -// } +typedef enum dap_chain_net_srv_xchange_purchase_compose_error { + DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NONE = 0, + DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_PARAMS, + DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE, + DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT, + DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_ITEMS_FOUND, + DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_COND_TX, + DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_TOKEN_TICKER, + DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_TIMESTAMP, + DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_PRICE_CREATE, + DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_TX_CREATE +} dap_chain_net_srv_xchange_purchase_compose_error_t; + +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_purchase_compose(dap_hash_fast_t *a_order_hash, uint256_t a_value, + uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out, compose_config_t *a_config){ + if (!a_config || !a_order_hash || !a_wallet || !a_hash_out) { + return NULL; + } -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-w", &l_wallet_name); -// if (!l_wallet_name) { -// printf("Error: Command 'purchase' requires parameter -w\n"); -// return -1; -// } -// dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path, NULL); -// if (!l_wallet) { -// printf("Error: Specified wallet not found\n"); -// return -2; -// } -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-order", &l_order_hash); -// if (!l_order_hash) { -// printf("Error: Command 'purchase' requires parameter -order\n"); -// return -3; -// } -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &l_value); -// if (!l_value) { -// printf("Error: Command 'purchase' requires parameter -value\n"); -// return -4; -// } -// uint256_t l_datoshi_buy = dap_chain_balance_scan(l_value); -// dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &l_fee); -// if (!l_fee) { -// printf("Error: Command 'purchase' requires parameter -fee\n"); -// return -5; -// } -// uint256_t l_datoshi_fee = dap_chain_balance_scan(l_fee); -// dap_hash_fast_t l_tx_hash = {}; -// dap_chain_hash_fast_from_str(l_order_hash, &l_tx_hash); -// char *l_str_ret_hash = NULL; -// int l_ret_code = dap_chain_net_srv_xchange_purchase_compose(l_net_name, &l_tx_hash, l_datoshi_buy, l_datoshi_fee, -// l_wallet, &l_str_ret_hash); -// switch (l_ret_code) { -// case XCHANGE_PURCHASE_ERROR_OK: { -// printf("Exchange transaction has done\n"); -// printf("hash: %s\n", l_str_ret_hash); -// DAP_DELETE(l_str_ret_hash); -// return 0; -// } -// case XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND: { -// printf("Error: Specified order not found\n"); -// return -6; -// } -// case XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE: { -// printf("Error: Can't create price from order\n"); -// return -7; -// } -// case XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX: { -// printf("Error: Exchange transaction error\n"); -// return -8; -// } -// default: { -// printf("Error: An error occurred with an unknown code: %d.\n", l_ret_code); -// return -9; -// } -// } -// return 0; -// } + dap_time_t ts_created = 0; + dap_chain_tx_out_cond_t *l_cond_tx = NULL; + char data[512]; + snprintf(data, sizeof(data), + "{\"method\": \"ledger\",\"params\": [\"ledger;info;-hash;%s;-net;%s\"],\"id\": \"1\"}", + dap_chain_hash_fast_to_str_static(a_order_hash), a_config->net_name); + + json_object *response = dap_request_command_to_rpc(data, a_config); + if (!response) { + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_REMOTE_NODE_UNREACHABLE, "Failed to get response from remote node"); + return NULL; + } + + const char *items_str = json_object_get_string(response); + json_object *l_response_array = json_object_array_get_idx(response, 0); + if (!l_response_array) { + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_INVALID_RESPONSE_FORMAT, "Can't get the first element from the response array"); + json_object_put(response); + return NULL; + } + json_object *items = json_object_object_get(l_response_array, "ITEMS"); + if (!items) { + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_ITEMS_FOUND, "No items found in response"); + return NULL; + } + uint32_t l_prev_cond_idx = 0; + int items_count = json_object_array_length(items); + for (int i = 0; i < items_count; i++) { + json_object *item = json_object_array_get_idx(items, i); + const char *item_type = json_object_get_string(json_object_object_get(item, "item type")); + if (dap_strcmp(item_type, "OUT COND") == 0) { + const char *subtype = json_object_get_string(json_object_object_get(item, "subtype")); + if (!dap_strcmp(subtype, "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE")) { + l_cond_tx = DAP_NEW_Z(dap_chain_tx_out_cond_t); + l_cond_tx->header.item_type = TX_ITEM_TYPE_OUT_COND; + l_cond_tx->header.value = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "value"))); + l_cond_tx->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; + l_cond_tx->header.srv_uid.uint64 = strtoull(json_object_get_string(json_object_object_get(item, "uid")), NULL, 16); + l_cond_tx->header.ts_expires = dap_time_from_str_rfc822(json_object_get_string(json_object_object_get(item, "ts_expires"))); + strncpy(l_cond_tx->subtype.srv_xchange.buy_token, json_object_get_string(json_object_object_get(item, "buy_token")), sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1); + l_cond_tx->subtype.srv_xchange.buy_token[sizeof(l_cond_tx->subtype.srv_xchange.buy_token) - 1] = '\0'; + l_cond_tx->subtype.srv_xchange.rate = dap_chain_balance_scan(json_object_get_string(json_object_object_get(item, "rate"))); + l_cond_tx->tsd_size = json_object_get_int(json_object_object_get(item, "tsd_size")); + break; + } + l_prev_cond_idx++; + } else if (dap_strcmp(item_type, "OUT") == 0 || dap_strcmp(item_type, "OUT EXT") == 0 || dap_strcmp(item_type, "OLD_OUT") == 0) { + l_prev_cond_idx++; + } + } + if (!l_cond_tx) { + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_COND_TX, "No transaction output condition found"); + return NULL; + } -// dap_chain_net_srv_xchange_purchase_error_t dap_chain_net_srv_xchange_purchase_compose(const char *a_net_name, dap_hash_fast_t *a_order_hash, uint256_t a_value, -// uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out){ -// if (!a_net_name || !a_order_hash || !a_wallet || !a_hash_out) { -// return XCHANGE_PURCHASE_ERROR_INVALID_ARGUMENT; -// } -// dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(a_net->pub.ledger, a_order_hash); -// if (l_cond_tx) { -// dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(a_net, l_cond_tx, a_order_hash, &a_fee, false); -// if(!l_price){ -// return XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE; -// } -// // Create conditional transaction -// char *l_ret = NULL; -// dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_exchange(l_price, a_wallet, a_value, a_fee); -// if (l_tx ) { -// l_ret = s_xchange_tx_put(l_tx, a_net); -// } -// DAP_DELETE(l_price); -// if (l_tx && l_ret){ -// *a_hash_out = l_ret; -// return XCHANGE_PURCHASE_ERROR_OK; -// } else -// return XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX; -// } else { -// return XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND; -// } -// } + const char *token_ticker = json_object_get_string(json_object_object_get(l_response_array, "Token_ticker")); + if (!token_ticker) { + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_TOKEN_TICKER, "Token_ticker not found in response"); + return NULL; + } + const char *ts_created_str = json_object_get_string(json_object_object_get(l_response_array, "TS_Created")); + if (ts_created_str) { + ts_created = dap_time_from_str_rfc822(ts_created_str); + } else { + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_NO_TIMESTAMP, "TS_Created not found in response"); + return NULL; + } + + dap_chain_net_srv_xchange_price_t *l_price = dap_chain_net_srv_xchange_price_from_order_compose(l_cond_tx, ts_created, token_ticker, a_order_hash, &a_fee, false, a_config); + if(!l_price){ + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_PRICE_CREATE, "Failed to create price from order"); + return NULL; + } + // Create conditional transaction + dap_chain_datum_tx_t *l_tx = dap_xchange_tx_create_exchange_compose(l_price, a_wallet, a_value, a_fee, l_cond_tx, l_prev_cond_idx, a_config); + DAP_DELETE(l_cond_tx); + if (!l_tx) { + dap_json_compose_error_add(a_config->response_handler, DAP_CHAIN_NET_SRV_XCHANGE_PURCHASE_COMPOSE_ERR_TX_CREATE, "Failed to create exchange transaction"); + DAP_DELETE(l_price); + return NULL; + } + return l_tx; +} + + +dap_chain_datum_tx_t *dap_xchange_tx_create_exchange_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, uint256_t a_datoshi_buy, + uint256_t a_datoshi_fee, dap_chain_tx_out_cond_t* a_cond_tx, uint32_t a_prev_cond_idx, compose_config_t *a_config) +{ + if (!a_price || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) { + return NULL; + } + const char *l_native_ticker = s_get_native_ticker(a_config->net_name); + const char *l_service_ticker = NULL; + // find the transactions from which to take away coins + uint256_t l_value_transfer, // how many coins to transfer + l_value_need = a_datoshi_buy, + l_net_fee = {}, + l_service_fee, + l_total_fee = a_datoshi_fee, + l_fee_transfer; + dap_chain_addr_t *l_net_fee_addr = NULL, *l_service_fee_addr = NULL; + dap_list_t *l_list_fee_out = NULL; + bool l_net_fee_used = dap_get_remote_net_fee_and_address(&l_net_fee, &l_net_fee_addr, a_config); + if (l_net_fee_used) + SUM_256_256(l_net_fee, a_price->fee, &l_total_fee); + uint16_t l_service_fee_type = 0; + // Doesn't implement service fee for now + // bool l_service_fee_used = dap_chain_net_srv_xchange_get_fee(a_price->net->pub.id, &l_service_fee, &l_service_fee_addr, &l_service_fee_type); + // if (l_service_fee_used) { + // switch (l_service_fee_type) { + // case SERIVCE_FEE_NATIVE_PERCENT: + // MULT_256_COIN(l_service_fee, a_datoshi_buy, &l_service_fee); + // case SERVICE_FEE_NATIVE_FIXED: + // SUM_256_256(l_total_fee, l_service_fee, &l_total_fee); + // l_service_ticker = l_native_ticker; + // break; + // case SERVICE_FEE_OWN_PERCENT: + // MULT_256_COIN(l_service_fee, a_datoshi_buy, &l_service_fee); + // case SERVICE_FEE_OWN_FIXED: + // SUM_256_256(l_value_need, l_service_fee, &l_value_need); + // l_service_ticker = a_price->token_buy; + // default: + // break; + // } + // } + + dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, s_get_net_id(a_config->net_name)); + dap_chain_addr_t l_buyer_addr = *l_wallet_addr; + DAP_DELETE(l_wallet_addr); + + json_object *l_outs = NULL; + int l_outputs_count = 0; + if (!dap_get_remote_wallet_outs_and_count(l_wallet_addr, a_price->token_sell, &l_outs, &l_outputs_count, a_config)) { + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Not enough funds to transfer"); + return NULL; + } + + dap_list_t *l_list_used_out = NULL; + l_list_used_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_value_need, + &l_value_transfer); + json_object_put(l_outs); + if (!l_list_used_out) { + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Not enough funds to transfer"); + return NULL; + } + + bool l_pay_with_native = !dap_strcmp(a_price->token_sell, l_native_ticker); + bool l_buy_with_native = !dap_strcmp(a_price->token_buy, l_native_ticker); + if (!l_pay_with_native) { + if (l_buy_with_native) + SUM_256_256(l_value_need, l_total_fee, &l_value_need); + else { + l_list_fee_out = dap_ledger_get_list_tx_outs_from_json(l_outs, l_outputs_count, + l_total_fee, + &l_fee_transfer); + if (!l_list_fee_out) { + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Not enough funds to pay fee"); + json_object_put(l_outs); + return NULL; + } + } + } + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + + // add 'in' items to sell + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + dap_list_free_full(l_list_used_out, NULL); + if (!EQUAL_256(l_value_to_items, l_value_transfer)) { + dap_list_free_full(l_list_fee_out, NULL); + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't compose the transaction input"); + return NULL; + } + if (!l_pay_with_native && !l_buy_with_native) { + // add 'in' items to fee + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + dap_list_free_full(l_list_fee_out, NULL); + if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FEE_ERROR, "Can't compose the transaction input"); + return NULL; + } + } + // add 'in' item to buy from conditional transaction + if (!a_cond_tx) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Requested conditional transaction not found"); + return NULL; + } + // int l_prev_cond_idx = 0; + // dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(a_cond_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, + // &l_prev_cond_idx); + // if (!l_tx_out_cond) { + // dap_chain_datum_tx_delete(l_tx); + // dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Requested transaction has no conditional output"); + // return NULL; + // } + + // if (dap_ledger_tx_hash_is_used_out_item(a_config->ledger, &a_price->tx_hash, l_prev_cond_idx, NULL)) { + // dap_chain_datum_tx_delete(l_tx); + // dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Requested conditional transaction is already used out"); + // return NULL; + // } + const dap_chain_addr_t *l_seller_addr = &a_cond_tx->subtype.srv_xchange.seller_addr; + if (1 != dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, a_prev_cond_idx, 0)) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add conditional input"); + return NULL; + } + + // add 'out' items + // transfer selling coins + uint256_t l_datoshi_sell, + l_datoshi_buy, + l_value_back; + if (!IS_ZERO_256(a_price->rate)) { + DIV_256_COIN(a_datoshi_buy, a_price->rate, &l_datoshi_sell); + if (compare256(a_cond_tx->header.value, l_datoshi_sell) < 0) { + l_datoshi_sell = a_cond_tx->header.value; + MULT_256_COIN(l_datoshi_sell, a_price->rate, &l_datoshi_buy); + uint256_t l_exceed = {}; // Correct requested transfer value + SUBTRACT_256_256(a_datoshi_buy, l_datoshi_buy, &l_exceed); + SUBTRACT_256_256(l_value_need, l_exceed, &l_value_need); + } else + l_datoshi_buy = a_datoshi_buy; + + uint256_t l_value_sell = l_datoshi_sell; + if (l_pay_with_native) { + if (compare256(l_datoshi_sell, l_total_fee) <= 0) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Fee is greater or equal than transfer value"); + return NULL; + } + SUBTRACT_256_256(l_datoshi_sell, l_total_fee, &l_value_sell); + } + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_buyer_addr, l_value_sell, a_price->token_sell) == -1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add selling coins output"); + return NULL; + } + } else { + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add selling coins output because price rate is 0"); + return NULL; + } + + if (compare256(a_cond_tx->header.value, l_datoshi_sell) == 1) { + SUBTRACT_256_256(a_cond_tx->header.value, l_datoshi_sell, &l_value_back); + + dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange( + c_dap_chain_net_srv_xchange_uid, s_get_net_id(a_config->net_name), l_value_back, + s_get_net_id(a_config->net_name), a_price->token_buy, a_price->rate, + l_seller_addr, NULL, 0); + if (!l_tx_out) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add selling coins back conditioned output (cond cashback)"); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); + DAP_DELETE(l_tx_out); + } + // transfer buying coins + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_datoshi_buy, a_price->token_buy) == -1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add buying coins output"); + return NULL; + } + + // transfer validator's fee + if (!IS_ZERO_256(a_datoshi_fee)) { + if (dap_chain_datum_tx_add_fee_item(&l_tx, a_datoshi_fee) == -1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add validator fee output"); + return NULL; + } + } + // transfer net fee + if (l_net_fee_used) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_net_fee_addr, l_net_fee, l_native_ticker) == -1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add net fee output"); + return NULL; + } + } + // transfer service fee + // if (l_service_fee_used) { + // if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_service_fee_addr, l_service_fee, l_service_ticker) == -1) { + // dap_chain_datum_tx_delete(l_tx); + // dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add net fee output"); + // return NULL; + // } + // } + // coin back + SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_buyer_addr, l_value_back, a_price->token_buy) == -1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add buying coins back output"); + return NULL; + } + } + // fee back + if (!l_pay_with_native && !l_buy_with_native) { + SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back); + if (!IS_ZERO_256(l_value_back)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_buyer_addr, l_value_back, l_native_ticker) == -1) { + dap_chain_datum_tx_delete(l_tx); + dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Can't add buying coins back output"); + return NULL; + } + } + } + + return l_tx; +} diff --git a/modules/compose/include/dap_chain_tx_compose.h b/modules/compose/include/dap_chain_tx_compose.h index e70baec8da..d070a12c64 100644 --- a/modules/compose/include/dap_chain_tx_compose.h +++ b/modules/compose/include/dap_chain_tx_compose.h @@ -140,9 +140,15 @@ dap_chain_datum_tx_t *dap_stake_tx_create_compose(dap_enc_key_t *a_key, dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax, dap_chain_datum_tx_t *a_prev_tx, dap_pkey_t *a_pkey, compose_config_t *a_config); - - - +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_purchase_compose(dap_hash_fast_t *a_order_hash, uint256_t a_value, + uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out, compose_config_t *a_config); +json_object *dap_tx_create_xchange_purchase_compose (const char *a_net_name, const char *a_order_hash, const char* a_value, + const char* a_fee, const char *a_wallet_name, const char *a_wallet_path, + const char *a_url_str, uint16_t a_port); +dap_chain_datum_tx_t* dap_chain_net_srv_xchange_purchase_compose(dap_hash_fast_t *a_order_hash, uint256_t a_value, + uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out, compose_config_t *a_config); +dap_chain_datum_tx_t *dap_xchange_tx_create_exchange_compose(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet, uint256_t a_datoshi_buy, + uint256_t a_datoshi_fee, dap_chain_tx_out_cond_t* a_cond_tx, uint32_t a_prev_cond_idx, compose_config_t *a_config); #ifdef __cplusplus } -- GitLab From 8ec224f74d43bea21eaee197050e1391ced11a03 Mon Sep 17 00:00:00 2001 From: konstantin <konstantin.kuharenko@demlabs.net> Date: Fri, 18 Apr 2025 09:34:07 +0300 Subject: [PATCH 53/53] [*] fix purchase --- modules/compose/dap_chain_tx_compose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/compose/dap_chain_tx_compose.c b/modules/compose/dap_chain_tx_compose.c index 56681e539e..44c64812f8 100644 --- a/modules/compose/dap_chain_tx_compose.c +++ b/modules/compose/dap_chain_tx_compose.c @@ -4653,7 +4653,7 @@ dap_chain_datum_tx_t *dap_xchange_tx_create_exchange_compose(dap_chain_net_srv_x json_object *l_outs = NULL; int l_outputs_count = 0; - if (!dap_get_remote_wallet_outs_and_count(l_wallet_addr, a_price->token_sell, &l_outs, &l_outputs_count, a_config)) { + if (!dap_get_remote_wallet_outs_and_count(&l_buyer_addr, a_price->token_sell, &l_outs, &l_outputs_count, a_config)) { dap_json_compose_error_add(a_config->response_handler, TX_CREATE_COMPOSE_FUNDS_ERROR, "Not enough funds to transfer"); return NULL; } -- GitLab