From 8be2cc083f57e62e57b34e79e1bdeab5d9ab1eab Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 8 Mar 2023 21:19:59 +0100 Subject: [PATCH] Implemented accept ionic swap proposal(partially) --- src/gui/qt-daemon/application/mainwindow.cpp | 7 ++ src/wallet/wallet2.cpp | 97 ++++++++++++++++++-- src/wallet/wallet2.h | 12 ++- src/wallet/wallets_manager.cpp | 22 +++++ src/wallet/wallets_manager.h | 3 +- 5 files changed, 130 insertions(+), 11 deletions(-) diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index 8cf48c4a..03261af2 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -2187,6 +2187,13 @@ QString get_ionic_swap_proposal_info(const QString& param) QString accept_ionic_swap_proposal(const QString& param) { + TRY_ENTRY(); + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::api_request_t, tx_raw_hex); + PREPARE_RESPONSE(view::api_response_t, ar); + ar.error_code = m_backend.accept_ionic_swap_proposal(tx_raw_hex.wallet_id, tx_raw_hex.req_data, ar.response_data); + return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::backup_wallet_keys(const QString& param) { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 7a5892d9..13db244b 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -907,7 +907,9 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept construct_tx_param construct_param = AUTO_VAL_INIT(construct_param); construct_param.fee = b_acceptance_fee; - currency::transaction tx = contr_it->second.proposal.tx_template; + mode_separate_context msc = AUTO_VAL_INIT(msc); + msc.tx_for_mode_separate = contr_it->second.proposal.tx_template; + currency::transaction& tx = msc.tx_for_mode_separate; crypto::secret_key one_time_key = contr_it->second.proposal.tx_onetime_secret_key; construct_param.crypt_address = m_account.get_public_address(); construct_param.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE; @@ -965,7 +967,7 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept //build transaction currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); ftp.tx_version = this->get_current_tx_version(); - prepare_transaction(construct_param, ftp, tx); + prepare_transaction(construct_param, ftp, msc); mark_transfers_as_spent(ftp.selected_transfers, std::string("contract <") + epee::string_tools::pod_to_hex(contract_id) + "> has been accepted with tx <" + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">"); try @@ -4626,7 +4628,7 @@ void wallet2::build_escrow_template(const bc_services::contract_private_details& currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); ftp.tx_version = this->get_current_tx_version(); - prepare_transaction(ctp, ftp, tx); + prepare_transaction(ctp, ftp); selected_transfers = ftp.selected_transfers; @@ -4895,6 +4897,13 @@ bool wallet2::build_ionic_swap_template(const view::ionic_swap_proposal_info& pr crypto::secret_key& one_time_key) { construct_tx_param ctp = get_default_construct_tx_param(); + + ctp.fake_outputs_count = proposal_detais.mixins; + ctp.fee = 0; + ctp.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE; + ctp.mark_tx_as_complete = false; + + etc_tx_details_expiration_time t = AUTO_VAL_INIT(t); t.v = proposal_detais.expiration_time; ctp.extra.push_back(t); @@ -4919,7 +4928,7 @@ bool wallet2::build_ionic_swap_template(const view::ionic_swap_proposal_info& pr currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); ftp.tx_version = this->get_current_tx_version(); - prepare_transaction(ctp, ftp, template_tx); + prepare_transaction(ctp, ftp); selected_transfers = ftp.selected_transfers; @@ -4929,12 +4938,16 @@ bool wallet2::build_ionic_swap_template(const view::ionic_swap_proposal_info& pr return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_ionic_swap_proposal_info(std::string&raw_tx_template, view::ionic_swap_proposal_info& proposal) +bool wallet2::get_ionic_swap_proposal_info(const std::string&raw_tx_template, view::ionic_swap_proposal_info& proposal) { currency::transaction tx; bool r = parse_and_validate_tx_from_blob(raw_tx_template, tx); THROW_IF_TRUE_WALLET_EX(!r, error::tx_parse_error, raw_tx_template); - + return get_ionic_swap_proposal_info(tx, proposal); +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::get_ionic_swap_proposal_info(const currency::transaction tx, view::ionic_swap_proposal_info& proposal) +{ crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); std::vector outs; uint64_t tx_money_got_in_outs = 0; @@ -4992,6 +5005,74 @@ bool wallet2::get_ionic_swap_proposal_info(std::string&raw_tx_template, view::io return true; } //---------------------------------------------------------------------------------------------------- +bool wallet2::accept_ionic_swap_proposal(std::string&raw_tx_template, currency::transaction& result_tx) +{ + mode_separate_context msc = AUTO_VAL_INIT(msc); + + currency::transaction& tx = msc.tx_for_mode_separate; + bool r = parse_and_validate_tx_from_blob(raw_tx_template, tx); + THROW_IF_TRUE_WALLET_EX(!r, error::tx_parse_error, raw_tx_template); + + r = get_ionic_swap_proposal_info(tx, msc.proposal); + THROW_IF_TRUE_WALLET_EX(!r, error::wallet_internal_error, "Failed to get info from proposal"); + + std::unordered_map balances; + uint64_t mined = 0; + this->balance(balances, mined); + //validate balances needed + uint64_t native_amount_required = 0; + for (const auto& item : msc.proposal.to) + { + if (balances[item.asset_id].unlocked < item.amount) + { + return false; + } + if (item.asset_id == currency::null_pkey) + { + native_amount_required = item.amount; + } + } + + // balances is ok, check if fee is added to tx + uint64_t additional_fee = 0; + if (msc.proposal.fee < m_core_runtime_config.tx_default_fee) + { + additional_fee = m_core_runtime_config.tx_default_fee - msc.proposal.fee; + if (balances[currency::null_pkey].unlocked < additional_fee + native_amount_required) + { + return false; + } + } + + //everything is seemed to be ok + + construct_tx_param construct_param = get_default_construct_tx_param(); + construct_param.fee = additional_fee; + //crypto::secret_key one_time_key = contr_it->second.proposal.tx_onetime_secret_key; + construct_param.crypt_address = m_account.get_public_address(); + construct_param.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE; + construct_param.mark_tx_as_complete = true; + + //build transaction + currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); + ftp.tx_version = this->get_current_tx_version(); + prepare_transaction(construct_param, ftp, msc); + mark_transfers_as_spent(ftp.selected_transfers, std::string("contract <") + epee::string_tools::pod_to_hex(contract_id) + "> has been accepted with tx <" + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">"); + + try + { + finalize_transaction(ftp, tx, one_time_key, true); + } + catch (...) + { + clear_transfers_from_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, std::string("exception in finalize_transaction, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(tx))); + throw; + } + + + return true; +} +//---------------------------------------------------------------------------------------------------- bool wallet2::prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake_outputs_count, std::vector& sources, std::vector& selected_indicies, uint64_t& found_money) { prepare_free_transfers_cache(fake_outputs_count); @@ -5966,10 +6047,10 @@ void wallet2::prepare_tx_destinations(uint64_t needed_money, } } //---------------------------------------------------------------------------------------------------- -void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const currency::transaction& tx_for_mode_separate /* = currency::transaction() */) +void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const mode_separate_context& mode_separatemode_separate) { TIME_MEASURE_START_MS(get_needed_money_time); - + const currency::transaction& tx_for_mode_separate = mode_separatemode_separate.tx_for_mode_separate; assets_selection_context needed_money_map = get_needed_money(ctp.fee, ctp.dsts); //@#@ need to do refactoring over this part to support hidden amounts and asset_id if (ctp.flags & TX_FLAG_SIGNATURE_MODE_SEPARATE && tx_for_mode_separate.vout.size() ) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 731d6737..49e430b7 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -297,6 +297,12 @@ namespace tools bool perform_packing = false; }; + struct mode_separate_context + { + currency::transaction tx_for_mode_separate; + view::ionic_swap_proposal_info proposal; + }; + struct selection_for_amount { @@ -884,7 +890,7 @@ namespace tools const std::list& get_expiration_entries() const { return m_money_expirations; }; bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const; - void prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const currency::transaction& tx_for_mode_separate = currency::transaction()); + void prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const mode_separate_context& emode_separate = mode_separate_context()); void finalize_transaction(const currency::finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx, bool store_tx_secret_key = true); void finalize_transaction(const currency::finalize_tx_param& ftp, currency::finalized_tx& result, bool broadcast_tx, bool store_tx_secret_key = true ); @@ -922,7 +928,9 @@ namespace tools currency::transaction& template_tx, std::vector& selected_transfers_for_template, crypto::secret_key& one_time_key); - bool get_ionic_swap_proposal_info(std::string& raw_tx_template, view::ionic_swap_proposal_info& proposal); + bool get_ionic_swap_proposal_info(const std::string&raw_tx_template, view::ionic_swap_proposal_info& proposal); + bool get_ionic_swap_proposal_info(const currency::transaction tx, view::ionic_swap_proposal_info& proposal); + bool accept_ionic_swap_proposal(std::string&raw_tx_template, currency::transaction& result_tx); private: // -------- t_transport_state_notifier ------------------------------------------------ diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index bec4cdea..21a7f8d0 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -906,6 +906,28 @@ std::string get_ionic_swap_proposal_info(uint64_t wallet_id, std::string&raw_tx_ return API_RETURN_CODE_OK; } +std::string wallets_manager::accept_ionic_swap_proposal(uint64_t wallet_id, std::string&raw_tx_template, currency::transaction& result_tx) +{ + GET_WALLET_OPT_BY_ID(wallet_id, wo); + try { + std::string raw_tx_template; + bool r = epee::string_tools::parse_hexstr_to_binbuff(raw_tx_template_hex, raw_tx_template); + if (!r) + { + return API_RETURN_CODE_BAD_ARG; + } + + if (!wo.w->get()->accept_ionic_swap_proposal(raw_tx_template, result_tx)) + { + return API_RETURN_CODE_FAIL; + } + } + catch (...) + { + return API_RETURN_CODE_FAIL; + } + return API_RETURN_CODE_OK; +} std::string wallets_manager::get_my_offers(const bc_services::core_offers_filter& filter, std::list& offers) { if (m_remote_node_mode) diff --git a/src/wallet/wallets_manager.h b/src/wallet/wallets_manager.h index e465f3cf..d17cb437 100644 --- a/src/wallet/wallets_manager.h +++ b/src/wallet/wallets_manager.h @@ -137,7 +137,8 @@ public: std::string reset_wallet_password(uint64_t wallet_id, const std::string& pass); std::string is_wallet_password_valid(uint64_t wallet_id, const std::string& pass); std::string create_ionic_swap_proposal(uint64_t wallet_id, const view::create_ionic_swap_proposal_request& proposal, std::string& result_proposal_hex); - std::string get_ionic_swap_proposal_info(uint64_t wallet_id, std::string&raw_tx_template, ionic_swap_proposal_info& proposal); + std::string get_ionic_swap_proposal_info(uint64_t wallet_id, std::string&raw_tx_template_hex, ionic_swap_proposal_info& proposal); + std::string accept_ionic_swap_proposal(uint64_t wallet_id, std::string&raw_tx_template_hex, currency::transaction& result_tx); std::string get_my_offers(const bc_services::core_offers_filter& filter, std::list& offers); std::string get_fav_offers(const std::list& hashes, const bc_services::core_offers_filter& filter, std::list& offers); std::string get_tx_pool_info(currency::COMMAND_RPC_GET_POOL_INFO::response& res);