forked from lthn/blockchain
Merge commit 'e58b20ae5b62745513b8451af1ae195c9c6a8e20' into release
This commit is contained in:
commit
0a055e892c
20 changed files with 1021 additions and 16 deletions
|
|
@ -25,6 +25,8 @@
|
|||
//
|
||||
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <optional>
|
||||
#include "misc_language.h"
|
||||
namespace epee
|
||||
{
|
||||
|
|
@ -51,24 +53,73 @@ namespace epee
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_std_optional : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_std_optional<std::optional<T>> : std::true_type {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_std_optional<boost::optional<T>> : std::true_type {};
|
||||
|
||||
|
||||
//basic helpers for pod-to-hex serialization
|
||||
template<class t_pod_type>
|
||||
std::string transform_t_pod_to_str_internal(const t_pod_type& a)
|
||||
{
|
||||
return epee::string_tools::pod_to_hex(a);
|
||||
}
|
||||
|
||||
template<class t_pod_type>
|
||||
std::string transform_t_pod_to_str_internal(const std::optional<t_pod_type>& a)
|
||||
{
|
||||
if (a.has_value())
|
||||
return epee::string_tools::pod_to_hex(*a);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
template<class t_pod_type>
|
||||
std::string transform_t_pod_to_str_internal(const boost::optional<t_pod_type>& a)
|
||||
{
|
||||
if (a.has_value())
|
||||
return epee::string_tools::pod_to_hex(*a);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
//basic helpers for pod-to-hex serialization
|
||||
template<class t_pod_type>
|
||||
std::string transform_t_pod_to_str(const t_pod_type & a)
|
||||
{
|
||||
return epee::string_tools::pod_to_hex(a);
|
||||
return transform_t_pod_to_str_internal(a);
|
||||
}
|
||||
template<class t_pod_type>
|
||||
|
||||
|
||||
|
||||
template<class t_pod_type>
|
||||
t_pod_type transform_str_to_t_pod(const std::string& a)
|
||||
{
|
||||
t_pod_type res = AUTO_VAL_INIT(res);
|
||||
t_pod_type res = AUTO_VAL_INIT(res);
|
||||
if (a.empty())
|
||||
return res;
|
||||
if constexpr (is_std_optional<t_pod_type>::value)
|
||||
{
|
||||
typename t_pod_type::value_type v = AUTO_VAL_INIT(v);
|
||||
if (!epee::string_tools::hex_to_pod(a, v))
|
||||
throw std::runtime_error(std::string("Unable to transform \"") + a + "\" to pod type " + typeid(typename t_pod_type::value_type).name());
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
if (!epee::string_tools::hex_to_pod(a, res))
|
||||
throw std::runtime_error(std::string("Unable to transform \"") + a + "\" to pod type " + typeid(t_pod_type).name());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//basic helpers for blob-to-hex serialization
|
||||
|
||||
inline std::string transform_binbuf_to_hexstr(const std::string& a)
|
||||
|
|
|
|||
|
|
@ -157,6 +157,10 @@ namespace crypto
|
|||
{
|
||||
return o << epee::string_tools::pod_to_hex(v);
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& o, const eth_signature& v)
|
||||
{
|
||||
return o << epee::string_tools::pod_to_hex(v);
|
||||
}
|
||||
|
||||
|
||||
} // namespace crypto
|
||||
|
|
|
|||
|
|
@ -62,5 +62,6 @@ namespace crypto
|
|||
|
||||
std::ostream& operator<<(std::ostream& o, const eth_secret_key& v);
|
||||
std::ostream& operator<<(std::ostream& o, const eth_public_key& v);
|
||||
std::ostream& operator<<(std::ostream& o, const eth_signature& v);
|
||||
|
||||
} // namespace crypto
|
||||
|
|
|
|||
|
|
@ -4116,7 +4116,15 @@ bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& a
|
|||
asset_operation_ownership_proof_eth aoop_eth{};
|
||||
r = get_type_in_variant_container(avc.tx.proofs, aoop_eth);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Ownership validation failed: asset_operation_ownership_proof_eth is missing");
|
||||
return crypto::verify_eth_signature(avc.tx_id, last_ado.descriptor.owner_eth_pub_key.value(), aoop_eth.eth_sig);
|
||||
if (!crypto::verify_eth_signature(avc.tx_id, last_ado.descriptor.owner_eth_pub_key.value(), aoop_eth.eth_sig))
|
||||
{
|
||||
LOG_ERROR("Failed to validate secp256k1 signature for hash: " << avc.tx_id << ", signature: " << aoop_eth.eth_sig);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// owner_eth_pub_key has no value -- fallback to default
|
||||
}
|
||||
|
|
|
|||
|
|
@ -749,7 +749,7 @@ namespace currency
|
|||
KV_SERIALIZE(meta_info) DOC_DSCR("Any other information associated with the asset in free form.") DOC_EXMP("Stable and private") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(owner) DOC_DSCR("Owner's key, used only for EMIT and UPDATE validation, can be changed by transferring asset ownership.") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE(hidden_supply) DOC_DSCR("This field is reserved for future use and will be documented later.") DOC_END
|
||||
KV_SERIALIZE(owner_eth_pub_key) DOC_DSCR("[Optional] Owner's key in the case when ETH signature is used.") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(owner_eth_pub_key) DOC_DSCR("[Optional] Owner's key in the case when ETH signature is used.") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 6d212d4eefaf6d13c72799cb89be2c80b1813d38
|
||||
Subproject commit 5c878005ace55484eafe2985d204cd51e90b203b
|
||||
|
|
@ -8,6 +8,6 @@
|
|||
#define PROJECT_REVISION "1"
|
||||
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
|
||||
|
||||
#define PROJECT_VERSION_BUILD_NO 348
|
||||
#define PROJECT_VERSION_BUILD_NO 349
|
||||
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
|
||||
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ const crypto::public_key& wallet2::out_get_pub_key(const currency::tx_out_v& out
|
|||
void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_operation& ado, process_transaction_context& ptc)
|
||||
{
|
||||
auto print_ado_owner = [ado](std::ostream& o){
|
||||
ado.descriptor.owner_eth_pub_key.has_value() ? o << ado.descriptor.owner_eth_pub_key.get() << " (ETH)" : o << ado.descriptor.owner;
|
||||
ado.descriptor.owner_eth_pub_key.has_value() ? o << ado.descriptor.owner_eth_pub_key.value() << " (ETH)" : o << ado.descriptor.owner;
|
||||
};
|
||||
|
||||
do
|
||||
|
|
@ -3754,13 +3754,10 @@ bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asse
|
|||
for (const auto& emp_entry : utx.second.employed_entries.receive)
|
||||
{
|
||||
auto it_employed_entry = subtransfers_by_assets_map.find(emp_entry.asset_id);
|
||||
if (it_employed_entry == subtransfers_by_assets_map.end())
|
||||
{
|
||||
LOG_ERROR("Intenral error, check the wallet code at give location");
|
||||
continue;
|
||||
}
|
||||
if (!(it_employed_entry->second)) // if is_incoming == false, then we need to check for change and add it to total
|
||||
if (it_employed_entry == subtransfers_by_assets_map.end() || !(it_employed_entry->second)) // if is_incoming == false, then we need to check for change and add it to total
|
||||
{
|
||||
//it_employed_entry == subtransfers_by_assets_map.end() is a case when amount sent exactly equal amount received (someone producing more outputs for example)
|
||||
//still need to add to total as it is a change
|
||||
wallet_public::asset_balance_entry_base& e = balances[emp_entry.asset_id];
|
||||
e.total += emp_entry.amount;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1433,7 +1433,7 @@ namespace tools
|
|||
res.status = e.what();
|
||||
return true;
|
||||
}
|
||||
|
||||
res.status = API_RETURN_CODE_OK;
|
||||
return true;
|
||||
WALLET_RPC_CATCH_TRY_ENTRY();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1296,6 +1296,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY_HF(asset_operation_and_hardfork_checks, "4-*");
|
||||
GENERATE_AND_PLAY_HF(eth_signed_asset_basics, "5-*"); // TODO: make HF4 version
|
||||
GENERATE_AND_PLAY_HF(eth_signed_asset_via_rpc, "5-*"); // TODO: make HF4 version
|
||||
//GENERATE_AND_PLAY_HF(asset_current_and_total_supplies_comparative_constraints, "4-*"); <-- temporary disabled, waiting for Stepan's fix -- sowle
|
||||
|
||||
GENERATE_AND_PLAY_HF(pos_fuse_test, "4-*");
|
||||
|
||||
|
|
|
|||
|
|
@ -1952,3 +1952,369 @@ bool eth_signed_asset_via_rpc::c1(currency::core& c, size_t ev_index, const std:
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
asset_current_and_total_supplies_comparative_constraints::asset_current_and_total_supplies_comparative_constraints()
|
||||
{
|
||||
{
|
||||
auto& adb{m_adbs.at(asset_position::alpha)};
|
||||
|
||||
adb.full_name = "Alpha";
|
||||
adb.ticker = "ALPH";
|
||||
adb.current_supply = 1;
|
||||
adb.total_max_supply = 0;
|
||||
}
|
||||
|
||||
{
|
||||
auto& adb{m_adbs.at(asset_position::beta)};
|
||||
|
||||
adb.full_name = "Beta";
|
||||
adb.ticker = "BETA";
|
||||
adb.current_supply = adb.total_max_supply = 1;
|
||||
}
|
||||
|
||||
{
|
||||
auto &adb{m_adbs.at(asset_position::gamma)};
|
||||
|
||||
adb.full_name = "Gamma";
|
||||
adb.ticker = "GAMM";
|
||||
adb.current_supply = adb.total_max_supply = 0;
|
||||
}
|
||||
|
||||
m_ados_register.at(asset_position::alpha).operation_type = m_ados_register.at(asset_position::beta).operation_type = m_ados_register.at(asset_position::gamma).operation_type =
|
||||
ASSET_DESCRIPTOR_OPERATION_REGISTER;
|
||||
|
||||
m_ado_emit.operation_type = ASSET_DESCRIPTOR_OPERATION_EMIT;
|
||||
|
||||
REGISTER_CALLBACK_METHOD(asset_current_and_total_supplies_comparative_constraints, assert_asset_gamma_registered);
|
||||
REGISTER_CALLBACK_METHOD(asset_current_and_total_supplies_comparative_constraints, assert_asset_alpha_not_registered);
|
||||
REGISTER_CALLBACK_METHOD(asset_current_and_total_supplies_comparative_constraints, assert_asset_beta_registered);
|
||||
REGISTER_CALLBACK_METHOD(asset_current_and_total_supplies_comparative_constraints, emit_asset_beta_with_incorrect_supply);
|
||||
REGISTER_CALLBACK_METHOD(asset_current_and_total_supplies_comparative_constraints, assert_asset_beta_not_emitted);
|
||||
REGISTER_CALLBACK_METHOD(asset_current_and_total_supplies_comparative_constraints, public_burn_asset_beta_with_incorrect_supply);
|
||||
}
|
||||
|
||||
bool asset_current_and_total_supplies_comparative_constraints::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
/* Test ideas:
|
||||
* ensure that it's possible to register asset with .current_supply = .total_max_supply = 0;
|
||||
* ensure that asset operations in which .current_supply is greater than .total_max_supply are not performed. */
|
||||
|
||||
bool success{};
|
||||
GENERATE_ACCOUNT(miner);
|
||||
GENERATE_ACCOUNT(alice);
|
||||
transaction tx_0{}, tx_1{}, tx_2{}, tx_3{}, tx_4{};
|
||||
|
||||
m_accounts.push_back(miner);
|
||||
m_accounts.push_back(alice);
|
||||
m_adbs.at(asset_position::alpha).owner = m_adbs.at(asset_position::beta).owner = m_adbs.at(asset_position::gamma).owner = alice.get_public_address().spend_public_key;
|
||||
m_ados_register.at(asset_position::alpha).descriptor = m_adbs.at(asset_position::alpha);
|
||||
m_ados_register.at(asset_position::beta).descriptor = m_ado_emit.descriptor = m_adbs.at(asset_position::beta);
|
||||
m_ados_register.at(asset_position::gamma).descriptor = m_adbs.at(asset_position::gamma);
|
||||
CHECK_AND_ASSERT(m_ado_emit.descriptor.current_supply <= m_ado_emit.descriptor.total_max_supply, false);
|
||||
++m_ado_emit.descriptor.current_supply;
|
||||
CHECK_AND_ASSERT(m_ado_emit.descriptor.current_supply > m_ado_emit.descriptor.total_max_supply, false);
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time());
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
{
|
||||
const auto& top{blk_0r};
|
||||
std::vector<tx_source_entry> sources{};
|
||||
std::vector<tx_destination_entry> destinations{};
|
||||
|
||||
success = fill_tx_sources_and_destinations(events, top, miner.get_keys(), alice.get_public_address(), MK_TEST_COINS(8), TESTS_DEFAULT_FEE, 0, sources, destinations);
|
||||
CHECK_AND_ASSERT_EQ(success, true);
|
||||
success = construct_tx(miner.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version(get_block_height(top), m_hardforks), 0);
|
||||
CHECK_AND_ASSERT_EQ(success, true);
|
||||
}
|
||||
|
||||
ADD_CUSTOM_EVENT(events, tx_0);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner, tx_0);
|
||||
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// Alice registers the asset GAMM with .current_supply = 0, .total_max_supply = 0.
|
||||
{
|
||||
const auto& top{blk_1r};
|
||||
std::vector<tx_source_entry> sources{};
|
||||
std::vector<tx_destination_entry> destinations{};
|
||||
const auto& ado{m_ados_register.at(asset_position::gamma)};
|
||||
crypto::secret_key one_time{};
|
||||
|
||||
success = fill_tx_sources_and_destinations(events, top, alice.get_keys(), alice.get_public_address(), MK_TEST_COINS(2), TESTS_DEFAULT_FEE, 0, sources, destinations);
|
||||
CHECK_AND_ASSERT_EQ(success, true);
|
||||
destinations.emplace_back(ado.descriptor.current_supply, alice.get_public_address(), null_pkey);
|
||||
CHECK_AND_ASSERT_EQ(ado.descriptor.total_max_supply, 0);
|
||||
CHECK_AND_ASSERT_EQ(ado.descriptor.total_max_supply, ado.descriptor.current_supply);
|
||||
success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_1, get_tx_version(get_block_height(top), m_hardforks), one_time, 0);
|
||||
CHECK_AND_ASSERT_EQ(success, true);
|
||||
}
|
||||
|
||||
// tx_1 is valid and must be accepted.
|
||||
ADD_CUSTOM_EVENT(events, tx_1);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, alice, tx_1);
|
||||
REWIND_BLOCKS_N(events, blk_2r, blk_2, alice, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
DO_CALLBACK(events, "assert_asset_gamma_registered");
|
||||
|
||||
// Alice registers asset ALPH. Transaction is invalid, because .current_supply > .total_max_supply in the asset base descriptor.
|
||||
{
|
||||
const auto& top{blk_2r};
|
||||
std::vector<tx_source_entry> sources{};
|
||||
std::vector<tx_destination_entry> destinations{};
|
||||
crypto::secret_key one_time{};
|
||||
const auto& ado{m_ados_register.at(asset_position::alpha)};
|
||||
|
||||
success = fill_tx_sources_and_destinations(events, top, alice.get_keys(), alice.get_public_address(), MK_TEST_COINS(2), TESTS_DEFAULT_FEE, 0, sources, destinations);
|
||||
CHECK_AND_ASSERT_EQ(success, true);
|
||||
destinations.emplace_back(ado.descriptor.current_supply, alice.get_public_address(), null_pkey);
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.current_supply > ado.descriptor.total_max_supply, false, "current_supply <= total_max_supply");
|
||||
success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_2, get_tx_version(get_block_height(top), m_hardforks), one_time, 0);
|
||||
CHECK_AND_ASSERT_EQ(success, true);
|
||||
}
|
||||
|
||||
/* TODO: tx_1 is invalid and mustn't be accepted.
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx_2);
|
||||
DO_CALLBACK(events, "assert_asset_alpha_not_registered"); */
|
||||
|
||||
// Alice registers asset BETA. In the asset base descriptor .current_supply <= .total_max_supply.
|
||||
{
|
||||
const auto& top{blk_2r};
|
||||
|
||||
std::vector<tx_source_entry> sources{};
|
||||
std::vector<tx_destination_entry> destinations{};
|
||||
crypto::secret_key one_time{};
|
||||
const auto& ado{m_ados_register.at(asset_position::beta)};
|
||||
|
||||
success = fill_tx_sources_and_destinations(events, top, alice.get_keys(), alice.get_public_address(), MK_TEST_COINS(2), TESTS_DEFAULT_FEE, 0, sources, destinations);
|
||||
CHECK_AND_ASSERT_EQ(success, true);
|
||||
destinations.emplace_back(ado.descriptor.current_supply, alice.get_public_address(), null_pkey);
|
||||
CHECK_AND_ASSERT(ado.descriptor.current_supply <= ado.descriptor.total_max_supply, false);
|
||||
success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_3, get_tx_version(get_block_height(top), m_hardforks), one_time, 0);
|
||||
CHECK_AND_ASSERT_EQ(success, true);
|
||||
}
|
||||
|
||||
// tx_3 is valid and must be accepted.
|
||||
ADD_CUSTOM_EVENT(events, tx_3);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2r, alice, tx_3);
|
||||
REWIND_BLOCKS_N(events, blk_3r, blk_3, alice, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
DO_CALLBACK(events, "assert_asset_beta_registered");
|
||||
|
||||
{
|
||||
crypto::public_key beta_asset_id{};
|
||||
crypto::point_t point_beta_asset_id{};
|
||||
|
||||
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(m_ados_register.at(asset_position::beta), &point_beta_asset_id, &beta_asset_id), false, "failed to calculate asset id");
|
||||
m_ado_emit.opt_asset_id = beta_asset_id;
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_GREATER(m_ado_emit.descriptor.current_supply, m_ado_emit.descriptor.total_max_supply);
|
||||
// Alice emits asset BETA. The emission is performed through the wallet object. There is no emission, because .current_supply > .total_max_supply in the asset base descriptor.
|
||||
DO_CALLBACK(events, "emit_asset_beta_with_incorrect_supply");
|
||||
|
||||
/* Alice emits asset BETA. A transaction is constructed through finalize_tx_param object. This is low-level transaction construction. Transaction muse be rejected by the core, because
|
||||
.current_supply > .total_max_supply in the asset base descriptor. */
|
||||
{
|
||||
const auto& top{blk_3r};
|
||||
const auto& ado_register{m_ados_register.at(asset_position::beta)};
|
||||
std::vector<tx_source_entry> sources{};
|
||||
std::vector<tx_destination_entry> destinations{};
|
||||
crypto::secret_key one_time{};
|
||||
tx_source_entry source{};
|
||||
finalize_tx_param ftp{};
|
||||
finalized_tx ftx{};
|
||||
|
||||
success = fill_tx_sources_and_destinations(events, top, alice.get_keys(), alice.get_public_address(), MK_TEST_COINS(2), TESTS_DEFAULT_FEE, 0, sources, destinations);
|
||||
CHECK_AND_ASSERT_EQ(success, true);
|
||||
CHECK_AND_ASSERT_GREATER(m_ado_emit.descriptor.current_supply, ado_register.descriptor.current_supply);
|
||||
destinations.emplace_back(m_ado_emit.descriptor.current_supply - ado_register.descriptor.current_supply, alice.get_public_address(), null_pkey);
|
||||
|
||||
ftp.sources = sources;
|
||||
ftp.prepared_destinations = destinations;
|
||||
ftp.tx_version = get_tx_version(get_block_height(top), m_hardforks);
|
||||
ftp.extra = {m_ado_emit};
|
||||
ftp.shuffle = true;
|
||||
CHECK_AND_ASSERT_GREATER(m_ado_emit.descriptor.current_supply, m_ado_emit.descriptor.total_max_supply);
|
||||
success = construct_tx(alice.get_keys(), ftp, ftx);
|
||||
CHECK_AND_ASSERT_EQ(success, true);
|
||||
tx_4 = ftx.tx;
|
||||
}
|
||||
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx_4);
|
||||
DO_CALLBACK(events, "assert_asset_beta_not_emitted");
|
||||
// Alice burns asset BETA. The public burn is performed through the wallet object. Burn mustn't be performed, because .current_supply > .total_max_supply in the asset base descriptor.
|
||||
DO_CALLBACK(events, "public_burn_asset_beta_with_incorrect_supply");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asset_current_and_total_supplies_comparative_constraints::assert_asset_alpha_not_registered(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const
|
||||
{
|
||||
const std::shared_ptr alice_wallet{init_playtime_test_wallet_t<tools::wallet2>(events, c, ALICE_ACC_IDX)};
|
||||
crypto::public_key alpha_asset_id{};
|
||||
const std::string ticker{m_ados_register.at(asset_position::alpha).descriptor.ticker};
|
||||
|
||||
alice_wallet->refresh();
|
||||
|
||||
{
|
||||
crypto::point_t point_alpha_asset_id{};
|
||||
|
||||
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(m_ados_register.at(asset_position::alpha), &point_alpha_asset_id, &alpha_asset_id), false, "failed to calculate asset " + ticker + " id");
|
||||
}
|
||||
|
||||
{
|
||||
asset_descriptor_base alpha_adb{};
|
||||
|
||||
CHECK_AND_ASSERT_MES(!c.get_blockchain_storage().get_asset_info(alpha_asset_id, alpha_adb), false, "the asset " + ticker + " must not be registered");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asset_current_and_total_supplies_comparative_constraints::assert_asset_beta_registered(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const
|
||||
{
|
||||
const std::shared_ptr alice_wallet{init_playtime_test_wallet_t<tools::wallet2>(events, c, ALICE_ACC_IDX)};
|
||||
crypto::public_key key_beta_asset_id{};
|
||||
const std::string ticker{m_ados_register.at(asset_position::beta).descriptor.ticker};
|
||||
|
||||
alice_wallet->refresh();
|
||||
|
||||
{
|
||||
crypto::point_t point_beta_asset_id{};
|
||||
|
||||
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(m_ados_register.at(asset_position::beta), &point_beta_asset_id, &key_beta_asset_id), false, "failed to calculate asset id");
|
||||
}
|
||||
|
||||
{
|
||||
asset_descriptor_base beta_adb{};
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_blockchain_storage().get_asset_info(key_beta_asset_id, beta_adb), false, "the asset " + ticker + " must not be registered");
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(alice_wallet->balance(key_beta_asset_id) == 1, false, "Alice has got not exactly 1 " + ticker);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asset_current_and_total_supplies_comparative_constraints::emit_asset_beta_with_incorrect_supply(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const
|
||||
{
|
||||
const std::shared_ptr alice_wallet{init_playtime_test_wallet_t<tools::wallet2>(events, c, ALICE_ACC_IDX)};
|
||||
std::vector<tx_destination_entry> destinations{};
|
||||
crypto::public_key beta_asset_id{};
|
||||
|
||||
{
|
||||
asset_descriptor_base adb{};
|
||||
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_asset_info(*m_ado_emit.opt_asset_id, adb), true);
|
||||
}
|
||||
|
||||
{
|
||||
crypto::point_t point_beta_asset_id{};
|
||||
|
||||
CHECK_AND_ASSERT_EQ(get_or_calculate_asset_id(m_ado_emit, &point_beta_asset_id, &beta_asset_id), true);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_EQ(*m_ado_emit.opt_asset_id, beta_asset_id);
|
||||
alice_wallet->refresh();
|
||||
|
||||
{
|
||||
const auto& ado_register{m_ados_register.at(asset_position::beta)};
|
||||
|
||||
CHECK_AND_ASSERT_GREATER(m_ado_emit.descriptor.current_supply, ado_register.descriptor.current_supply);
|
||||
destinations.emplace_back(m_ado_emit.descriptor.current_supply - ado_register.descriptor.current_supply, alice_wallet->get_account().get_public_address(), beta_asset_id);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_GREATER(m_ado_emit.descriptor.current_supply, m_ado_emit.descriptor.total_max_supply);
|
||||
|
||||
try
|
||||
{
|
||||
transaction tx{};
|
||||
|
||||
alice_wallet->emit_asset(beta_asset_id, destinations, tx);
|
||||
}
|
||||
catch (const tools::error::tx_rejected&)
|
||||
{
|
||||
CHECK_AND_ASSERT_EQ(c.get_pool_transactions_count(), 0);
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asset_current_and_total_supplies_comparative_constraints::assert_asset_beta_not_emitted(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const
|
||||
{
|
||||
const std::shared_ptr alice_wallet{init_playtime_test_wallet_t<tools::wallet2>(events, c, ALICE_ACC_IDX)};
|
||||
crypto::public_key beta_asset_id{};
|
||||
const auto& register_ado{m_ados_register.at(asset_position::beta)};
|
||||
|
||||
alice_wallet->refresh();
|
||||
|
||||
{
|
||||
crypto::point_t point_beta_asset_id{};
|
||||
|
||||
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(register_ado, &point_beta_asset_id, &beta_asset_id), false, "failed to calculate asset id");
|
||||
}
|
||||
|
||||
{
|
||||
const uint64_t& current_supply{register_ado.descriptor.current_supply};
|
||||
|
||||
CHECK_AND_ASSERT_MES(alice_wallet->balance(beta_asset_id) == current_supply, false, "Alice has got not exactly " + std::to_string(current_supply) + ' ' + register_ado.descriptor.ticker);
|
||||
}
|
||||
}
|
||||
|
||||
bool asset_current_and_total_supplies_comparative_constraints::public_burn_asset_beta_with_incorrect_supply(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const
|
||||
{
|
||||
const std::shared_ptr alice_wallet{init_playtime_test_wallet_t<tools::wallet2>(events, c, ALICE_ACC_IDX)};
|
||||
crypto::public_key beta_asset_id{};
|
||||
|
||||
alice_wallet->refresh();
|
||||
|
||||
{
|
||||
crypto::point_t point_beta_asset_id{};
|
||||
|
||||
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(m_ados_register.at(asset_position::beta), &point_beta_asset_id, &beta_asset_id), false, "failed to calculate asset id");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
transaction tx{};
|
||||
|
||||
alice_wallet->burn_asset(beta_asset_id, m_ado_emit.descriptor.current_supply, tx);
|
||||
}
|
||||
catch (const std::runtime_error&)
|
||||
{
|
||||
CHECK_AND_ASSERT_EQ(c.get_pool_transactions_count(), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asset_current_and_total_supplies_comparative_constraints::assert_asset_gamma_registered(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const
|
||||
{
|
||||
const std::shared_ptr alice_wallet{init_playtime_test_wallet_t<tools::wallet2>(events, c, ALICE_ACC_IDX)};
|
||||
crypto::public_key key_gamma_asset_id{};
|
||||
const std::string ticker{m_ados_register.at(asset_position::gamma).descriptor.ticker};
|
||||
|
||||
alice_wallet->refresh();
|
||||
|
||||
{
|
||||
crypto::point_t point_gamma_asset_id{};
|
||||
|
||||
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(m_ados_register.at(asset_position::gamma), &point_gamma_asset_id, &key_gamma_asset_id), false, "failed to calculate asset " + ticker + " id");
|
||||
}
|
||||
|
||||
{
|
||||
asset_descriptor_base gamma_adb{};
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_blockchain_storage().get_asset_info(key_gamma_asset_id, gamma_adb), false, "the asset " + ticker + " must be registered");
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_EQ(alice_wallet->balance(key_gamma_asset_id), m_ados_register.at(asset_position::gamma).descriptor.current_supply);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,3 +95,22 @@ struct eth_signed_asset_via_rpc : public wallet_test
|
|||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
};
|
||||
|
||||
struct asset_current_and_total_supplies_comparative_constraints : public wallet_test
|
||||
{
|
||||
public:
|
||||
asset_current_and_total_supplies_comparative_constraints();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool assert_asset_alpha_not_registered(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const;
|
||||
bool assert_asset_beta_registered(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const;
|
||||
bool emit_asset_beta_with_incorrect_supply(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const;
|
||||
bool assert_asset_beta_not_emitted(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const;
|
||||
bool public_burn_asset_beta_with_incorrect_supply(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const;
|
||||
bool assert_asset_gamma_registered(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const;
|
||||
|
||||
private:
|
||||
enum asset_position { alpha = 0, beta = 1, gamma = 2 };
|
||||
mutable std::array<currency::asset_descriptor_base, 3> m_adbs{};
|
||||
mutable std::array<currency::asset_descriptor_operation, 3> m_ados_register{};
|
||||
mutable currency::asset_descriptor_operation m_ado_emit{};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#include "offers_tests_common.h"
|
||||
#include "tx_builder.h"
|
||||
#include "chaingen_helpers.h"
|
||||
#include "..\..\src\currency_core\tx_semantic_validation.h"
|
||||
#include "../../src/currency_core/tx_semantic_validation.h"
|
||||
|
||||
using namespace epee;
|
||||
using namespace crypto;
|
||||
|
|
|
|||
2
utils/JS/.gitignore
vendored
Normal file
2
utils/JS/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/node_modules*
|
||||
.vscode
|
||||
77
utils/JS/decrypt_response.json
Normal file
77
utils/JS/decrypt_response.json
Normal file
File diff suppressed because one or more lines are too long
25
utils/JS/emmit_response.json
Normal file
25
utils/JS/emmit_response.json
Normal file
File diff suppressed because one or more lines are too long
192
utils/JS/package-lock.json
generated
Normal file
192
utils/JS/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
{
|
||||
"name": "JS",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"ethers": "^6.13.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@adraffy/ens-normalize": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
|
||||
"integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw=="
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
|
||||
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
|
||||
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.15.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz",
|
||||
"integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q=="
|
||||
},
|
||||
"node_modules/aes-js": {
|
||||
"version": "4.0.0-beta.5",
|
||||
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
|
||||
"integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q=="
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
|
||||
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ethers": {
|
||||
"version": "6.13.2",
|
||||
"resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.2.tgz",
|
||||
"integrity": "sha512-9VkriTTed+/27BGuY1s0hf441kqwHJ1wtN2edksEtiRvXx+soxRX3iSXTfFqq2+YwrOqbDoTHjIhQnjJRlzKmg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/ethers-io/"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@adraffy/ens-normalize": "1.10.1",
|
||||
"@noble/curves": "1.2.0",
|
||||
"@noble/hashes": "1.3.2",
|
||||
"@types/node": "18.15.13",
|
||||
"aes-js": "4.0.0-beta.5",
|
||||
"tslib": "2.4.0",
|
||||
"ws": "8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
utils/JS/package.json
Normal file
6
utils/JS/package.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"ethers": "^6.13.2"
|
||||
}
|
||||
}
|
||||
8
utils/JS/sign_response.json
Normal file
8
utils/JS/sign_response.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"id": 0,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"status": "",
|
||||
"transfers_were_unlocked": false
|
||||
}
|
||||
}
|
||||
248
utils/JS/test_eth_sig.js
Normal file
248
utils/JS/test_eth_sig.js
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
|
||||
|
||||
const axios = require('axios');
|
||||
const { ethers } = require("ethers");
|
||||
const { exit } = require('process');
|
||||
const fs = require('fs');
|
||||
|
||||
/// Define an async function that takes method name and parameters
|
||||
async function callJsonRpc(requestData, port = 22222) {
|
||||
try {
|
||||
const response = await axios.post('http://127.0.0.1:' + port +'/json_rpc', requestData, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Return the result from the JSON-RPC response
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
throw error; // Optionally rethrow the error to handle it in the calling function
|
||||
}
|
||||
}
|
||||
|
||||
function reverseHexBytes(hexString) {
|
||||
// Ensure the hex string length is even
|
||||
if (hexString.length % 2 !== 0) {
|
||||
throw new Error("Invalid hex string length");
|
||||
}
|
||||
|
||||
// Split the hex string into chunks of 2 characters (1 byte)
|
||||
const bytes = hexString.match(/.{1,2}/g);
|
||||
|
||||
// Reverse the array of bytes and join them back into a string
|
||||
const reversedHex = bytes.reverse().join('');
|
||||
|
||||
return reversedHex;
|
||||
}
|
||||
|
||||
async function deploy_asset()
|
||||
{
|
||||
try {
|
||||
//Generated Private Key: 0x17a938099954cee510d7fc9eb2366f0762b093d9be547acabf8be85f774ef154
|
||||
//Generated Address: 0x0886bA9F5b117D2A3C1ce18106F2Ce759f5D34C8
|
||||
|
||||
const loadedWallet = new ethers.Wallet("0x17a938099954cee510d7fc9eb2366f0762b093d9be547acabf8be85f774ef154");
|
||||
console.log("Loaded Address:", loadedWallet.address);
|
||||
console.log("Public key:", loadedWallet.signingKey.compressedPublicKey);
|
||||
const owner_eth_pub_key = loadedWallet.signingKey.compressedPublicKey.substring(2);
|
||||
console.log("Generated Public key HEX:", owner_eth_pub_key);
|
||||
const jsonObject = {
|
||||
id: 0,
|
||||
jsonrpc: "2.0",
|
||||
method: "deploy_asset",
|
||||
params: {
|
||||
asset_descriptor: {
|
||||
//current_supply: 1000000000000000,
|
||||
decimal_point: 12,
|
||||
full_name: "Zano wrapped ABC",
|
||||
hidden_supply: false,
|
||||
meta_info: "Stable and private",
|
||||
owner: "",
|
||||
ticker: "ZABC",
|
||||
total_max_supply: 1000000000000000000,
|
||||
owner_eth_pub_key: owner_eth_pub_key
|
||||
},
|
||||
destinations: [
|
||||
{
|
||||
address: "ZxC1U6hoCRM9PBSwrBTrWD8XgcHqLNJN9NWqXs9o994eZuHHBvSAyBpQ4TbWSNoabUDPdD8iEM5ZjPoMM7jE48mp2iKcVHLSK",
|
||||
amount: 1000000000000000,
|
||||
asset_id: ""
|
||||
},
|
||||
{
|
||||
address: "ZxC1U6hoCRM9PBSwrBTrWD8XgcHqLNJN9NWqXs9o994eZuHHBvSAyBpQ4TbWSNoabUDPdD8iEM5ZjPoMM7jE48mp2iKcVHLSK",
|
||||
amount: 1000000000000000,
|
||||
asset_id: ""
|
||||
}
|
||||
],
|
||||
do_not_split_destinations: false
|
||||
}
|
||||
};
|
||||
|
||||
const res = await callJsonRpc(jsonObject);
|
||||
console.log("deploy_asset response: " + JSON.stringify(res, null, 2));
|
||||
/*
|
||||
deploy_asset response:
|
||||
{
|
||||
"id": 0,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"new_asset_id": "7d51ecaad2e3458e0d62b146f33079c6ea307841b09a44b777e0c01eb11b98bf",
|
||||
"tx_id": "73ff52bf4d85153f2b25033dd76e9e92e63214ed983682182e6e2b2ce0ecf46c"
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
catch (error) {
|
||||
console.error('Error occurred:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function emmit_asset()
|
||||
{
|
||||
try {
|
||||
|
||||
//Generated Private Key: 0x17a938099954cee510d7fc9eb2366f0762b093d9be547acabf8be85f774ef154
|
||||
//Generated Address: 0x0886bA9F5b117D2A3C1ce18106F2Ce759f5D34C8
|
||||
// asset_id 7d51ecaad2e3458e0d62b146f33079c6ea307841b09a44b777e0c01eb11b98bf
|
||||
|
||||
//var use_pregenerated_files = false;
|
||||
|
||||
const loadedWallet = new ethers.Wallet("0x17a938099954cee510d7fc9eb2366f0762b093d9be547acabf8be85f774ef154");
|
||||
|
||||
console.log("Loaded Address:", loadedWallet.address);
|
||||
console.log("Public key:", loadedWallet.signingKey.compressedPublicKey);
|
||||
const owner_eth_pub_key = loadedWallet.signingKey.compressedPublicKey.substring(2);
|
||||
console.log("Generated Public key HEX:", owner_eth_pub_key);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//this part is performed on coordinator node:
|
||||
|
||||
var res_emmit;
|
||||
//if(!use_pregenerated_files)
|
||||
//{
|
||||
const requestDataEmit = {
|
||||
id: 0,
|
||||
jsonrpc: "2.0",
|
||||
method: "emit_asset",
|
||||
params: {
|
||||
asset_id: "7d51ecaad2e3458e0d62b146f33079c6ea307841b09a44b777e0c01eb11b98bf",
|
||||
destinations: [{
|
||||
address: "ZxC1U6hoCRM9PBSwrBTrWD8XgcHqLNJN9NWqXs9o994eZuHHBvSAyBpQ4TbWSNoabUDPdD8iEM5ZjPoMM7jE48mp2iKcVHLSK",
|
||||
amount: 100000000000,
|
||||
asset_id: ""
|
||||
}],
|
||||
do_not_split_destinations: false
|
||||
}
|
||||
};
|
||||
|
||||
res_emmit = await callJsonRpc(requestDataEmit);
|
||||
fs.writeFileSync('emmit_response.json', JSON.stringify(res_emmit, null, 2));
|
||||
console.log("emmit_response response: " + JSON.stringify(res_emmit, null, 2));
|
||||
//}else
|
||||
//{
|
||||
// const data = fs.readFileSync('emmit_response.json', 'utf8');
|
||||
// res_emmit = JSON.parse(data);
|
||||
//}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//this part is performed on validator node:
|
||||
|
||||
|
||||
var res_decrypt;
|
||||
//if(!use_pregenerated_files)
|
||||
//{
|
||||
const requestDataDecrypt = {
|
||||
id: 0,
|
||||
jsonrpc: "2.0",
|
||||
method: "decrypt_tx_details",
|
||||
params: {
|
||||
outputs_addresses: res_emmit.result.data_for_external_signing.outputs_addresses,
|
||||
tx_blob: res_emmit.result.data_for_external_signing.unsigned_tx,
|
||||
tx_id: "",
|
||||
tx_secret_key: res_emmit.result.data_for_external_signing.tx_secret_key
|
||||
}
|
||||
};
|
||||
|
||||
res_decrypt = await callJsonRpc(requestDataDecrypt, 12111); //request to daemon
|
||||
fs.writeFileSync('decrypt_response.json', JSON.stringify(res_decrypt, null, 2));
|
||||
console.log("decrypt_response : " + JSON.stringify(res_decrypt, null, 2));
|
||||
|
||||
//TODO: response holds all information about what this transaction actually transfer and to what addresses
|
||||
|
||||
//}else
|
||||
//{
|
||||
// const data = fs.readFileSync('decrypt_response.json', 'utf8');
|
||||
// res_decrypt = JSON.parse(data);
|
||||
//}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//this part is performed with TSS scheme:
|
||||
const bytesToSign = ethers.getBytes('0x' + res_decrypt.result.verified_tx_id);
|
||||
const signature = loadedWallet.signingKey.sign(bytesToSign).serialized;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//this part is performed on coordinator node with given signature:
|
||||
|
||||
const signature_without_0x = signature.substring(2);
|
||||
console.log("Generated signature: " + signature_without_0x);
|
||||
// Strip the last byte (recovery parameter) to get 64 bytes
|
||||
const strippedSignature = signature_without_0x.slice(0, -2); // Remove the last byte (2 hex chars)
|
||||
|
||||
const requestSendSigned = {
|
||||
id: 0,
|
||||
jsonrpc: "2.0",
|
||||
method: "send_ext_signed_asset_tx",
|
||||
params: {
|
||||
eth_sig: strippedSignature,
|
||||
expected_tx_id: res_decrypt.result.verified_tx_id,
|
||||
finalized_tx: res_emmit.result.data_for_external_signing.finalized_tx,
|
||||
unlock_transfers_on_fail: false,
|
||||
unsigned_tx: res_emmit.result.data_for_external_signing.unsigned_tx
|
||||
}
|
||||
}
|
||||
|
||||
const res_sign = await callJsonRpc(requestSendSigned);
|
||||
fs.writeFileSync('sign_response.json', JSON.stringify(res_sign, null, 2));
|
||||
console.log("sign_response response: " + JSON.stringify(res_sign, null, 2));
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error occurred:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function main()
|
||||
{
|
||||
try {
|
||||
|
||||
/*
|
||||
await deploy_asset();
|
||||
TODO: wait for 10 confirmations
|
||||
//wait for 10 confirmations
|
||||
|
||||
//asset id 7d51ecaad2e3458e0d62b146f33079c6ea307841b09a44b777e0c01eb11b98bf
|
||||
*/
|
||||
await emmit_asset();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error occurred:', error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
main();
|
||||
Loading…
Add table
Reference in a new issue