diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 118768f40..54b917ff9 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -34,16 +34,60 @@ #include "wallet.h" #include "crypto/hash.h" +#include "cryptonote_basic/cryptonote_format_utils.h" #include "wallet/wallet2.h" #include #include +#include +#include using namespace epee; namespace Monero { +namespace { + +std::string to_hex_or_empty(const crypto::public_key &key) +{ + if (key == crypto::null_pkey) + return {}; + return string_tools::pod_to_hex(key); +} + +std::vector extract_return_addresses(const cryptonote::transaction_prefix &tx) +{ + std::vector addresses; + if (tx.type == cryptonote::transaction_type::STAKE) + { + auto hex = to_hex_or_empty(tx.protocol_tx_data.return_address); + if (hex.empty()) + hex = to_hex_or_empty(tx.return_address); + if (!hex.empty()) + addresses.push_back(hex); + return addresses; + } + if (tx.type != cryptonote::transaction_type::PROTOCOL) + return addresses; + + std::unordered_set seen; + for (const auto &out : tx.vout) + { + crypto::public_key output_key = crypto::null_pkey; + if (!cryptonote::get_output_public_key(out, output_key)) + continue; + auto hex = to_hex_or_empty(output_key); + if (hex.empty()) + continue; + if (seen.emplace(hex).second) + addresses.push_back(hex); + } + return addresses; +} + +} // namespace + TransactionHistory::~TransactionHistory() {} @@ -130,6 +174,7 @@ void TransactionHistoryImpl::refresh() std::list> in_payments; m_wallet->m_wallet->get_payments(in_payments, min_height, max_height); + std::unordered_map protocol_by_hash; for (std::list>::const_iterator i = in_payments.begin(); i != in_payments.end(); ++i) { const tools::wallet2::payment_details &pd = i->second; std::string payment_id = string_tools::pod_to_hex(i->first); @@ -152,6 +197,8 @@ void TransactionHistoryImpl::refresh() ti->m_unlock_time = pd.m_unlock_time; ti->m_type = static_cast(static_cast(pd.m_tx_type)); ti->m_asset = pd.m_asset_type; + if (pd.m_tx_type == cryptonote::transaction_type::PROTOCOL) + protocol_by_hash.emplace(pd.m_tx_hash, ti); m_history.push_back(ti); } @@ -204,6 +251,7 @@ void TransactionHistoryImpl::refresh() ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0; ti->m_type = static_cast(static_cast(pd.m_tx.type)); ti->m_asset = pd.m_tx.source_asset_type; + ti->m_return_addresses = extract_return_addresses(pd.m_tx); // single output transaction might contain multiple transfers for (const auto &d: pd.m_dests) { @@ -251,6 +299,7 @@ void TransactionHistoryImpl::refresh() ti->m_confirmations = 0; ti->m_type = static_cast(static_cast(pd.m_tx.type)); ti->m_asset = pd.m_tx.source_asset_type; + ti->m_return_addresses = extract_return_addresses(pd.m_tx); for (const auto &d : pd.m_dests) { ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id), d.asset_type}); @@ -282,11 +331,23 @@ void TransactionHistoryImpl::refresh() ti->m_confirmations = 0; ti->m_type = static_cast(static_cast(pd.m_tx_type)); ti->m_asset = pd.m_asset_type; + if (pd.m_tx_type == cryptonote::transaction_type::PROTOCOL) + protocol_by_hash.emplace(pd.m_tx_hash, ti); m_history.push_back(ti); LOG_PRINT_L1(__FUNCTION__ << ": Unconfirmed payment found " << pd.m_amount); } - + + std::list> confirmed_protocol_payments; + m_wallet->m_wallet->get_payments_out(confirmed_protocol_payments, min_height, max_height); + for (const auto &entry : confirmed_protocol_payments) + { + const auto it = protocol_by_hash.find(entry.first); + if (it == protocol_by_hash.end()) + continue; + it->second->m_return_addresses = extract_return_addresses(entry.second.m_tx); + } + } } // namespace diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index da3711637..b3c56d9a3 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -134,6 +134,11 @@ string TransactionInfoImpl::paymentId() const return m_paymentid; } +const std::vector &TransactionInfoImpl::returnAddresses() const +{ + return m_return_addresses; +} + const std::vector &TransactionInfoImpl::transfers() const { return m_transfers; diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 40f52e36a..16c8bebe6 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -60,6 +60,7 @@ public: virtual std::string hash() const override; virtual std::time_t timestamp() const override; virtual std::string paymentId() const override; + virtual const std::vector &returnAddresses() const override; virtual const std::vector &transfers() const override; virtual uint64_t confirmations() const override; virtual uint64_t unlockTime() const override; @@ -81,6 +82,7 @@ private: std::string m_hash; std::time_t m_timestamp; std::string m_paymentid; + std::vector m_return_addresses; std::vector m_transfers; uint64_t m_confirmations; uint64_t m_unlock_time; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index ae59d3654..6a650a69a 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -806,6 +806,64 @@ std::string WalletImpl::seed(const std::string& seed_offset) const return std::string(seed.data(), seed.size()); // TODO } +void WalletImpl::setStoreTxInfo(bool store) +{ + m_wallet->store_tx_info(store); +} + +bool WalletImpl::storeTxInfo() const +{ + return m_wallet->store_tx_info(); +} + +bool WalletImpl::getPolyseed(std::string &seed_words, std::string &passphrase) const +{ + epee::wipeable_string seed_words_epee(seed_words.c_str(), seed_words.size()); + epee::wipeable_string passphrase_epee(passphrase.c_str(), passphrase.size()); + clearStatus(); + + if (!m_wallet) { + return false; + } + + bool result = m_wallet->get_polyseed(seed_words_epee, passphrase_epee); + + seed_words.assign(seed_words_epee.data(), seed_words_epee.size()); + passphrase.assign(passphrase_epee.data(), passphrase_epee.size()); + + return result; +} + +std::vector> Wallet::getPolyseedLanguages() + { + std::vector> languages; + + auto langs = polyseed::get_langs(); + for (const auto &lang : langs) { + languages.emplace_back(std::pair(lang.name_en(), lang.name())); + } + + return languages; +} + +bool Wallet::createPolyseed(std::string &seed_words, std::string &err, const std::string &language) +{ + epee::wipeable_string seed_words_epee(seed_words.c_str(), seed_words.size()); + + try { + polyseed::data polyseed(POLYSEED_COIN); + polyseed.create(0); + polyseed.encode(polyseed::get_lang_by_name(language), seed_words_epee); + + seed_words.assign(seed_words_epee.data(), seed_words_epee.size()); + } + catch (const std::exception &e) { + err = e.what(); + return false; + } + + return true; +} std::string WalletImpl::getSeedLanguage() const { return m_wallet->get_seed_language(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 7a8063478..50d6841c0 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -83,6 +83,9 @@ public: Device getDeviceType() const override; bool close(bool store = true); std::string seed(const std::string& seed_offset = "") const override; + bool getPolyseed(std::string &seed_words, std::string &passphrase) const override; + void setStoreTxInfo(bool store) override; + bool storeTxInfo() const override; std::string getSeedLanguage() const override; void setSeedLanguage(const std::string &arg) override; // void setListener(Listener *) {} diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 954bded71..5c96acf28 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -236,6 +236,7 @@ struct TransactionInfo virtual std::string hash() const = 0; virtual std::time_t timestamp() const = 0; virtual std::string paymentId() const = 0; + virtual const std::vector & returnAddresses() const = 0; //! only applicable for output transactions virtual const std::vector & transfers() const = 0; virtual Monero::transaction_type type() const = 0; @@ -503,6 +504,8 @@ struct Wallet virtual ~Wallet() = 0; virtual std::string seed(const std::string& seed_offset = "") const = 0; + virtual void setStoreTxInfo(bool store) = 0; + virtual bool storeTxInfo() const = 0; virtual std::string getSeedLanguage() const = 0; virtual void setSeedLanguage(const std::string &arg) = 0; //! returns wallet status (Status_Ok | Status_Error)