From f4c27935fd1a8c5f85e99014a3c687968806149d Mon Sep 17 00:00:00 2001 From: woodser Date: Wed, 19 Jul 2023 20:06:45 -0400 Subject: [PATCH] refactor mnemonic to seed (breaking change) --- src/wallet/monero_wallet.h | 16 ++--- src/wallet/monero_wallet_full.cpp | 95 ++++++++++-------------------- src/wallet/monero_wallet_full.h | 63 +++----------------- src/wallet/monero_wallet_keys.cpp | 65 ++++++++++++-------- src/wallet/monero_wallet_keys.h | 34 +++++------ src/wallet/monero_wallet_model.cpp | 9 ++- src/wallet/monero_wallet_model.h | 3 +- test/sample_code.cpp | 8 +-- 8 files changed, 111 insertions(+), 182 deletions(-) diff --git a/src/wallet/monero_wallet.h b/src/wallet/monero_wallet.h index fad1ad3..9b0c12f 100644 --- a/src/wallet/monero_wallet.h +++ b/src/wallet/monero_wallet.h @@ -239,21 +239,21 @@ namespace monero { } /** - * Get the wallet's mnemonic phrase. + * Get the wallet's mnemonic phrase or seed. * - * @param mnemonic is assigned the wallet's mnemonic phrase + * @return the wallet's mnemonic phrase or seed. */ - virtual std::string get_mnemonic() const { - throw std::runtime_error("get_mnemonic() not supported"); + virtual std::string get_seed() const { + throw std::runtime_error("get_seed() not supported"); } /** - * Get the language of the wallet's mnemonic phrase. + * Get the language of the wallet's mnemonic phrase or seed. * - * @return the language of the wallet's mnemonic phrase + * @return the language of the wallet's mnemonic phrase or seed. */ - virtual std::string get_mnemonic_language() const { - throw std::runtime_error("get_mnemonic_language() not supported"); + virtual std::string get_seed_language() const { + throw std::runtime_error("get_seed_language() not supported"); } /** diff --git a/src/wallet/monero_wallet_full.cpp b/src/wallet/monero_wallet_full.cpp index 7f1bfe2..7339ddd 100644 --- a/src/wallet/monero_wallet_full.cpp +++ b/src/wallet/monero_wallet_full.cpp @@ -1078,42 +1078,36 @@ namespace monero { if (config.m_path == boost::none) config_normalized.m_path = std::string(""); if (config.m_password == boost::none) config_normalized.m_password = std::string(""); if (config.m_language == boost::none) config_normalized.m_language = std::string(""); - if (config.m_mnemonic == boost::none) config_normalized.m_mnemonic = std::string(""); + if (config.m_seed == boost::none) config_normalized.m_seed = std::string(""); if (config.m_primary_address == boost::none) config_normalized.m_primary_address = std::string(""); if (config.m_private_spend_key == boost::none) config_normalized.m_private_spend_key = std::string(""); if (config.m_private_view_key == boost::none) config_normalized.m_private_view_key = std::string(""); if (config.m_seed_offset == boost::none) config_normalized.m_seed_offset = std::string(""); + if (config.m_is_multisig == boost::none) config_normalized.m_is_multisig = false; if (config.m_account_lookahead != boost::none && config.m_subaddress_lookahead == boost::none) throw std::runtime_error("No subaddress lookahead provided with account lookahead"); if (config.m_account_lookahead == boost::none && config.m_subaddress_lookahead != boost::none) throw std::runtime_error("No account lookahead provided with subaddress lookahead"); + if (config_normalized.m_language.get().empty()) config_normalized.m_language = std::string("English"); + if (!monero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); + if (config.m_network_type == boost::none) throw std::runtime_error("Must provide wallet network type"); // create wallet - if (!config_normalized.m_mnemonic.get().empty()) { - if (config.m_restore_height == boost::none) config_normalized.m_restore_height = 0; - if (!config_normalized.m_language.get().empty()) throw std::runtime_error("Cannot specify language when creating wallet from mnemonic"); - return create_wallet_from_mnemonic(config_normalized, std::move(http_client_factory)); + if (!config_normalized.m_seed.get().empty()) { + return create_wallet_from_seed(config_normalized, std::move(http_client_factory)); } else if (!config_normalized.m_primary_address.get().empty() || !config_normalized.m_private_spend_key.get().empty() || !config_normalized.m_private_view_key.get().empty()) { - if (config.m_restore_height == boost::none) config_normalized.m_restore_height = 0; - if (!config_normalized.m_seed_offset.get().empty()) throw std::runtime_error("Cannot specify seed offset when creating wallet from keys"); - if (config_normalized.m_language.get().empty()) config_normalized.m_language = std::string("English"); - if (!monero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); return create_wallet_from_keys(config_normalized, std::move(http_client_factory)); } else { - if (!config_normalized.m_seed_offset.get().empty()) throw std::runtime_error("Cannot specify seed offset when creating random wallet"); - if (config_normalized.m_restore_height != boost::none) throw std::runtime_error("Cannot specify restore height when creating random wallet"); - if (config_normalized.m_language.get().empty()) config_normalized.m_language = std::string("English"); - if (!monero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); - return monero_wallet_full::create_wallet_random(config_normalized, std::move(http_client_factory)); + return create_wallet_random(config_normalized, std::move(http_client_factory)); } } - monero_wallet_full* monero_wallet_full::create_wallet_from_mnemonic(const monero_wallet_config& config, std::unique_ptr http_client_factory) { - MTRACE("create_wallet_from_mnemonic(...)"); - monero_wallet_full* wallet = new monero_wallet_full(); + monero_wallet_full* monero_wallet_full::create_wallet_from_seed(monero_wallet_config& config, std::unique_ptr http_client_factory) { + MTRACE("create_wallet_from_seed(...)"); + if (config.m_is_multisig.get()) throw std::runtime_error("Restoring from multisig seed not supported"); // validate mnemonic and get recovery key and language crypto::secret_key recovery_key; std::string language; - bool is_valid = crypto::ElectrumWords::words_to_bytes(config.m_mnemonic.get(), recovery_key, language); + bool is_valid = crypto::ElectrumWords::words_to_bytes(config.m_seed.get(), recovery_key, language); if (!is_valid) throw std::runtime_error("Invalid mnemonic"); if (language == crypto::ElectrumWords::old_language_name) language = Language::English().get_language_name(); @@ -1121,6 +1115,7 @@ namespace monero { if (!config.m_seed_offset.get().empty()) recovery_key = cryptonote::decrypt_key(recovery_key, config.m_seed_offset.get()); // initialize wallet + monero_wallet_full* wallet = new monero_wallet_full(); if (http_client_factory == nullptr) wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true)); else wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true, std::move(http_client_factory))); wallet->set_daemon_connection(config.get_server()); @@ -1132,9 +1127,12 @@ namespace monero { return wallet; } - monero_wallet_full* monero_wallet_full::create_wallet_from_keys(const monero_wallet_config& config, std::unique_ptr http_client_factory) { + monero_wallet_full* monero_wallet_full::create_wallet_from_keys(monero_wallet_config& config, std::unique_ptr http_client_factory) { MTRACE("create_wallet_from_keys(...)"); - monero_wallet_full* wallet = new monero_wallet_full(); + + // validate and normalize config + if (config.m_restore_height == boost::none) config.m_restore_height = 0; + if (!config.m_seed_offset.get().empty()) throw std::runtime_error("Cannot specify seed offset when creating wallet from keys"); // parse and validate private spend key crypto::secret_key spend_key_sk; @@ -1186,6 +1184,8 @@ namespace monero { if (!monero_utils::is_valid_language(config.m_language.get())) throw std::runtime_error("Unknown language: " + config.m_language.get()); // initialize wallet + // TODO: delete wallet pointer if exception + monero_wallet_full* wallet = new monero_wallet_full(); if (http_client_factory == nullptr) wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true)); else wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true, std::move(http_client_factory))); if (config.m_account_lookahead != boost::none) wallet->m_w2->set_subaddress_lookahead(config.m_account_lookahead.get(), config.m_subaddress_lookahead.get()); @@ -1199,8 +1199,14 @@ namespace monero { return wallet; } - monero_wallet_full* monero_wallet_full::create_wallet_random(const monero_wallet_config& config, std::unique_ptr http_client_factory) { + monero_wallet_full* monero_wallet_full::create_wallet_random(monero_wallet_config& config, std::unique_ptr http_client_factory) { MTRACE("create_wallet_random(...)"); + + // validate config + if (!config.m_seed_offset.get().empty()) throw std::runtime_error("Cannot specify seed offset when creating random wallet"); + if (config.m_restore_height != boost::none) throw std::runtime_error("Cannot specify restore height when creating random wallet"); + + // initialize wallet monero_wallet_full* wallet = new monero_wallet_full(); if (http_client_factory == nullptr) wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true)); else wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true, std::move(http_client_factory))); @@ -1214,53 +1220,12 @@ namespace monero { return wallet; } - std::vector monero_wallet_full::get_mnemonic_languages() { + std::vector monero_wallet_full::get_seed_languages() { std::vector languages; crypto::ElectrumWords::get_language_list(languages, true); return languages; } - // ------------------------------- Deprecated ------------------------------- - - monero_wallet_full* monero_wallet_full::create_wallet_random(const std::string& path, const std::string& password, const monero_network_type network_type, const monero_rpc_connection& daemon_connection, const std::string& language, std::unique_ptr http_client_factory) { - std::cout << "Warning: monero_wallet_full::create_wallet_random() is deprecated and will be removed soon. Use monero_wallet_full::create_wallet(config) instead" << std::endl; - monero_wallet_config config; - config.m_path = path; - config.m_password = password; - config.m_network_type = network_type; - config.set_server(daemon_connection); - config.m_language = language; - return create_wallet(config, std::move(http_client_factory)); - } - - monero_wallet_full* monero_wallet_full::create_wallet_from_mnemonic(const std::string& path, const std::string& password, const monero_network_type network_type, const std::string& mnemonic, const monero_rpc_connection& daemon_connection, uint64_t restore_height, const std::string& seed_offset, std::unique_ptr http_client_factory) { - std::cout << "Warning: monero_wallet_full::create_wallet_from_mnemonic() is deprecated and will be removed soon. Use monero_wallet_full::create_wallet(config) instead" << std::endl; - monero_wallet_config config; - config.m_path = path; - config.m_password = password; - config.m_network_type = network_type; - config.m_mnemonic = mnemonic; - config.set_server(daemon_connection); - config.m_restore_height = restore_height; - config.m_seed_offset = seed_offset; - return create_wallet(config, std::move(http_client_factory)); - } - - monero_wallet_full* monero_wallet_full::create_wallet_from_keys(const std::string& path, const std::string& password, const monero_network_type network_type, const std::string& address, const std::string& view_key, const std::string& spend_key, const monero_rpc_connection& daemon_connection, uint64_t restore_height, const std::string& language, std::unique_ptr http_client_factory) { - std::cout << "Warning: monero_wallet_full::create_wallet_from_keys() is deprecated and will be removed soon. Use monero_wallet_full::create_wallet(config) instead" << std::endl; - monero_wallet_config config; - config.m_path = path; - config.m_password = password; - config.m_network_type = network_type; - config.m_primary_address = address; - config.m_private_view_key = view_key; - config.m_private_spend_key = spend_key; - config.set_server(daemon_connection); - config.m_restore_height = restore_height; - config.m_language = language; - return create_wallet(config, std::move(http_client_factory)); - } - // ----------------------------- WALLET METHODS ----------------------------- monero_wallet_full::~monero_wallet_full() { @@ -1351,7 +1316,7 @@ namespace monero { return static_cast(m_w2->nettype()); } - std::string monero_wallet_full::get_mnemonic() const { + std::string monero_wallet_full::get_seed() const { epee::wipeable_string seed; bool ready; if (m_w2->multisig(&ready)) { @@ -1365,7 +1330,7 @@ namespace monero { return std::string(seed.data(), seed.size()); } - std::string monero_wallet_full::get_mnemonic_language() const { + std::string monero_wallet_full::get_seed_language() const { if (m_w2->watch_only()) return ""; return m_w2->get_seed_language(); } diff --git a/src/wallet/monero_wallet_full.h b/src/wallet/monero_wallet_full.h index dbbd4d3..fdad1ad 100644 --- a/src/wallet/monero_wallet_full.h +++ b/src/wallet/monero_wallet_full.h @@ -119,58 +119,11 @@ namespace monero { static monero_wallet_full* create_wallet(const monero_wallet_config& config, std::unique_ptr http_client_factory = nullptr); /** - * Create a new wallet with a randomly generated seed. + * Get a list of available languages for the wallet's seed. * - * @param path is the path to create the wallet ("" for an in-memory wallet) - * @param password is the password encrypt the wallet - * @param network_type is the wallet's network type's - * @param daemon_connection is connection information to a daemon (defaults to an unconnected wallet) - * @param language is the wallet and mnemonic's language (defaults to "English") - * @param http_client_factory allows use of custom http clients - * @return a pointer to the wallet instance + * @return the available languages for the wallet's seed */ - [[deprecated("monero_wallet_full::create_wallet_random() is deprecated and will be removed soon. Use monero_wallet_full::create_wallet(config) instead")]] - static monero_wallet_full* create_wallet_random(const std::string& path, const std::string& password, const monero_network_type network_type, const monero_rpc_connection& daemon_connection = monero_rpc_connection(), const std::string& language = "English", std::unique_ptr http_client_factory = nullptr); - - /** - * Create a wallet from an existing mnemonic phrase. - * - * @param path is the path to create the wallet ("" for an in-memory wallet) - * @param password is the password encrypt the wallet * @param network_type is the wallet's network type - * @param mnemonic is the mnemonic of the wallet to construct - * @param daemon_connection is connection information to a daemon (defaults to an unconnected wallet) - * @param restore_height is the block height to restore from (default = 0) - * @param seed_offset is the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase (default = "") - * @param http_client_factory allows use of custom http clients - * @return a pointer to the wallet instance - */ - [[deprecated("monero_wallet_full::create_wallet_from_mnemonic() is deprecated and will be removed soon. Use monero_wallet_full::create_wallet(config) instead")]] - static monero_wallet_full* create_wallet_from_mnemonic(const std::string& path, const std::string& password, const monero_network_type network_type, const std::string& mnemonic, const monero_rpc_connection& daemon_connection = monero_rpc_connection(), uint64_t restore_height = 0, const std::string& seed_offset = "", std::unique_ptr http_client_factory = nullptr); - - /** - * Create a wallet from an address, view key, and spend key. - * - * @param path is the path to create the wallet ("" for an in-memory wallet) - * @param password is the password encrypt the wallet (defaults to in-memory wallet with password "") - * @param network_type is the wallet's network type - * @param address is the address of the wallet to construct - * @param view_key is the private view key of the wallet to construct - * @param spend_key is the private spend key of the wallet to construct - * @param daemon_connection is connection information to a daemon (defaults to an unconnected wallet) - * @param restore_height is the block height to restore (i.e. scan the chain) from (default = 0) - * @param language is the wallet and mnemonic's language (defaults to "English") - * @param http_client_factory allows use of custom http clients - * @return a pointer to the wallet instance - */ - [[deprecated("monero_wallet_full::create_wallet_from_keys() is deprecated and will be removed soon. Use monero_wallet_full::create_wallet(config) instead")]] - static monero_wallet_full* create_wallet_from_keys(const std::string& path, const std::string& password, const monero_network_type network_type, const std::string& address, const std::string& view_key, const std::string& spend_key, const monero_rpc_connection& daemon_connection = monero_rpc_connection(), uint64_t restore_height = 0, const std::string& language = "English", std::unique_ptr http_client_factory = nullptr); - - /** - * Get a list of available languages for the wallet's mnemonic phrase. - * - * @return the available languages for the wallet's mnemonic phrase - */ - static std::vector get_mnemonic_languages(); + static std::vector get_seed_languages(); // ----------------------------- WALLET METHODS ----------------------------- @@ -194,8 +147,8 @@ namespace monero { monero_version get_version() const override; std::string get_path() const override; monero_network_type get_network_type() const override; - std::string get_mnemonic() const override; - std::string get_mnemonic_language() const override; + std::string get_seed() const override; + std::string get_seed_language() const override; std::string get_public_view_key() const override; std::string get_private_view_key() const override; std::string get_public_spend_key() const override; @@ -308,9 +261,9 @@ namespace monero { std::unique_ptr m_w2_listener; // internal wallet implementation listener std::set m_listeners; // external wallet listeners - static monero_wallet_full* create_wallet_from_mnemonic(const monero_wallet_config& config, std::unique_ptr http_client_factory); - static monero_wallet_full* create_wallet_from_keys(const monero_wallet_config& config, std::unique_ptr http_client_factory); - static monero_wallet_full* create_wallet_random(const monero_wallet_config& config, std::unique_ptr http_client_factory); + static monero_wallet_full* create_wallet_from_seed(monero_wallet_config& config, std::unique_ptr http_client_factory); + static monero_wallet_full* create_wallet_from_keys(monero_wallet_config& config, std::unique_ptr http_client_factory); + static monero_wallet_full* create_wallet_random(monero_wallet_config& config, std::unique_ptr http_client_factory); void init_common(); std::vector get_subaddresses_aux(uint32_t account_idx, const std::vector& subaddress_indices, const std::vector& transfers) const; diff --git a/src/wallet/monero_wallet_keys.cpp b/src/wallet/monero_wallet_keys.cpp index c433f86..8b369b0 100644 --- a/src/wallet/monero_wallet_keys.cpp +++ b/src/wallet/monero_wallet_keys.cpp @@ -73,39 +73,47 @@ namespace monero { // ---------------------------- WALLET MANAGEMENT --------------------------- - monero_wallet_keys* monero_wallet_keys::create_wallet_random(const monero_network_type network_type, const std::string& language) { + monero_wallet_keys* monero_wallet_keys::create_wallet_random(const monero_wallet_config& config) { - // validate language - if (!monero_utils::is_valid_language(language)) throw std::runtime_error("Unknown language: " + language); + // validate and normalize config + monero_wallet_config config_normalized = config.copy(); + if (config_normalized.m_network_type == boost::none) throw std::runtime_error("Must provide wallet network type"); + if (config_normalized.m_language == boost::none || config_normalized.m_language.get().empty()) config_normalized.m_language = "English"; + if (!monero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); // initialize random wallet account monero_wallet_keys* wallet = new monero_wallet_keys(); crypto::secret_key spend_key_sk = wallet->m_account.generate(); // initialize remaining wallet - wallet->m_network_type = network_type; - wallet->m_language = language; + wallet->m_network_type = config_normalized.m_network_type.get(); + wallet->m_language = config_normalized.m_language.get(); epee::wipeable_string wipeable_mnemonic; if (!crypto::ElectrumWords::bytes_to_words(spend_key_sk, wipeable_mnemonic, wallet->m_language)) { throw std::runtime_error("Failed to create mnemonic from private spend key for language: " + std::string(wallet->m_language)); } - wallet->m_mnemonic = std::string(wipeable_mnemonic.data(), wipeable_mnemonic.size()); + wallet->m_seed = std::string(wipeable_mnemonic.data(), wipeable_mnemonic.size()); wallet->init_common(); return wallet; } - monero_wallet_keys* monero_wallet_keys::create_wallet_from_mnemonic(const monero_network_type network_type, const std::string& mnemonic, const std::string& seed_offset) { + monero_wallet_keys* monero_wallet_keys::create_wallet_from_seed(const monero_wallet_config& config) { + + // validate config + if (config.m_is_multisig != boost::none && config.m_is_multisig.get()) throw std::runtime_error("Restoring from multisig seed not supported"); + if (config.m_network_type == boost::none) throw std::runtime_error("Must provide wallet network type"); + if (config.m_seed == boost::none || config.m_seed.get().empty()) throw std::runtime_error("Must provide wallet seed"); // validate mnemonic and get recovery key and language crypto::secret_key spend_key_sk; std::string language; - bool is_valid = crypto::ElectrumWords::words_to_bytes(mnemonic, spend_key_sk, language); + bool is_valid = crypto::ElectrumWords::words_to_bytes(config.m_seed.get(), spend_key_sk, language); if (!is_valid) throw std::runtime_error("Invalid mnemonic"); if (language == crypto::ElectrumWords::old_language_name) language = Language::English().get_language_name(); // apply offset if given - if (!seed_offset.empty()) spend_key_sk = cryptonote::decrypt_key(spend_key_sk, seed_offset); + if (config.m_seed_offset != boost::none && !config.m_seed_offset.get().empty()) spend_key_sk = cryptonote::decrypt_key(spend_key_sk, config.m_seed_offset.get()); // initialize wallet account monero_wallet_keys* wallet = new monero_wallet_keys(); @@ -113,26 +121,34 @@ namespace monero { wallet->m_account.generate(spend_key_sk, true, false); // initialize remaining wallet - wallet->m_network_type = network_type; + wallet->m_network_type = config.m_network_type.get(); wallet->m_language = language; epee::wipeable_string wipeable_mnemonic; if (!crypto::ElectrumWords::bytes_to_words(spend_key_sk, wipeable_mnemonic, wallet->m_language)) { throw std::runtime_error("Failed to create mnemonic from private spend key for language: " + std::string(wallet->m_language)); } - wallet->m_mnemonic = std::string(wipeable_mnemonic.data(), wipeable_mnemonic.size()); + wallet->m_seed = std::string(wipeable_mnemonic.data(), wipeable_mnemonic.size()); wallet->init_common(); return wallet; } - monero_wallet_keys* monero_wallet_keys::create_wallet_from_keys(const monero_network_type network_type, const std::string& address, const std::string& view_key, const std::string& spend_key, const std::string& language) { + monero_wallet_keys* monero_wallet_keys::create_wallet_from_keys(const monero_wallet_config& config) { + + // validate and normalize config + monero_wallet_config config_normalized = config.copy(); + if (config.m_network_type == boost::none) throw std::runtime_error("Must provide wallet network type"); + if (config.m_language == boost::none || config_normalized.m_language.get().empty()) config_normalized.m_language = "English"; + if (config.m_private_spend_key == boost::none) config_normalized.m_private_spend_key = std::string(""); + if (config.m_private_view_key == boost::none) config_normalized.m_private_view_key = std::string(""); + if (!monero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); // parse and validate private spend key crypto::secret_key spend_key_sk; bool has_spend_key = false; - if (!spend_key.empty()) { + if (!config_normalized.m_private_spend_key.get().empty()) { cryptonote::blobdata spend_key_data; - if (!epee::string_tools::parse_hexstr_to_binbuff(spend_key, spend_key_data) || spend_key_data.size() != sizeof(crypto::secret_key)) { + if (!epee::string_tools::parse_hexstr_to_binbuff(config.m_private_spend_key.get(), spend_key_data) || spend_key_data.size() != sizeof(crypto::secret_key)) { throw std::runtime_error("failed to parse secret spend key"); } has_spend_key = true; @@ -142,13 +158,13 @@ namespace monero { // parse and validate private view key bool has_view_key = true; crypto::secret_key view_key_sk; - if (view_key.empty()) { + if (config_normalized.m_private_view_key.get().empty()) { if (has_spend_key) has_view_key = false; else throw std::runtime_error("Neither spend key nor view key supplied"); } if (has_view_key) { cryptonote::blobdata view_key_data; - if (!epee::string_tools::parse_hexstr_to_binbuff(view_key, view_key_data) || view_key_data.size() != sizeof(crypto::secret_key)) { + if (!epee::string_tools::parse_hexstr_to_binbuff(config_normalized.m_private_view_key.get(), view_key_data) || view_key_data.size() != sizeof(crypto::secret_key)) { throw std::runtime_error("failed to parse secret view key"); } view_key_sk = *reinterpret_cast(view_key_data.data()); @@ -156,10 +172,10 @@ namespace monero { // parse and validate address cryptonote::address_parse_info address_info; - if (address.empty()) { + if (config_normalized.m_primary_address.get().empty()) { if (has_view_key) throw std::runtime_error("must provide address if providing private view key"); } else { - if (!get_account_address_from_str(address_info, static_cast(network_type), address)) throw std::runtime_error("failed to parse address"); + if (!get_account_address_from_str(address_info, static_cast(config_normalized.m_network_type.get()), config_normalized.m_primary_address.get())) throw std::runtime_error("failed to parse address"); // check the spend and view keys match the given address crypto::public_key pkey; @@ -173,9 +189,6 @@ namespace monero { } } - // validate language - if (!monero_utils::is_valid_language(language)) throw std::runtime_error("Unknown language: " + language); - // initialize wallet account monero_wallet_keys* wallet = new monero_wallet_keys(); if (has_spend_key && has_view_key) { @@ -188,21 +201,21 @@ namespace monero { // initialize remaining wallet wallet->m_is_view_only = !has_spend_key; - wallet->m_network_type = network_type; - if (!spend_key.empty()) { - wallet->m_language = language; + wallet->m_network_type = config_normalized.m_network_type.get(); + if (!config_normalized.m_private_spend_key.get().empty()) { + wallet->m_language = config_normalized.m_language.get(); epee::wipeable_string wipeable_mnemonic; if (!crypto::ElectrumWords::bytes_to_words(spend_key_sk, wipeable_mnemonic, wallet->m_language)) { throw std::runtime_error("Failed to create mnemonic from private spend key for language: " + std::string(wallet->m_language)); } - wallet->m_mnemonic = std::string(wipeable_mnemonic.data(), wipeable_mnemonic.size()); + wallet->m_seed = std::string(wipeable_mnemonic.data(), wipeable_mnemonic.size()); } wallet->init_common(); return wallet; } - std::vector monero_wallet_keys::get_mnemonic_languages() { + std::vector monero_wallet_keys::get_seed_languages() { std::vector languages; crypto::ElectrumWords::get_language_list(languages, true); // TODO: support getting names in language return languages; diff --git a/src/wallet/monero_wallet_keys.h b/src/wallet/monero_wallet_keys.h index cb3b989..f4d3ae9 100644 --- a/src/wallet/monero_wallet_keys.h +++ b/src/wallet/monero_wallet_keys.h @@ -74,36 +74,30 @@ namespace monero { /** * Create a new wallet with a randomly generated seed. * - * @param network_type is the wallet's network type (default = monero_network_type.MAINNET) - * @param language is the wallet and mnemonic's language (default = "English") + * @param config is the wallet configuration (network type and language) */ - static monero_wallet_keys* create_wallet_random(const monero_network_type network_type, const std::string& language = "English"); + static monero_wallet_keys* create_wallet_random(const monero_wallet_config& config); /** - * Create a wallet from an existing mnemonic phrase. + * Create a wallet from an existing mnemonic phrase or seed. * - * @param network_type is the wallet's network type - * @param mnemonic is the mnemonic of the wallet to construct + * @param config is the wallet configuration (network type, seed, seed offset, isMultisig) */ - static monero_wallet_keys* create_wallet_from_mnemonic(const monero_network_type network_type, const std::string& mnemonic, const std::string& seed_offset); + static monero_wallet_keys* create_wallet_from_seed(const monero_wallet_config& config); /** * Create a wallet from an address, view key, and spend key. - * - * @param network_type is the wallet's network type - * @param address is the address of the wallet to construct - * @param view_key is the private view key of the wallet to construct - * @param spend_key is the private spend key of the wallet to construct - * @param language is the wallet and mnemonic's language (default = "English") + * + * @param config is the wallet configuration (network type, address, view key, spend key, language) */ - static monero_wallet_keys* create_wallet_from_keys(const monero_network_type network_type, const std::string& address, const std::string& view_key, const std::string& spend_key, const std::string& language = "English"); + static monero_wallet_keys* create_wallet_from_keys(const monero_wallet_config& config); /** - * Get a list of available languages for the wallet's mnemonic phrase. + * Get a list of available languages for the wallet's seed. * - * @return the available languages for the wallet's mnemonic phrase + * @return the available languages for the wallet's seed */ - static std::vector get_mnemonic_languages(); + static std::vector get_seed_languages(); // ----------------------------- WALLET METHODS ----------------------------- @@ -118,8 +112,8 @@ namespace monero { bool is_view_only() const override { return m_is_view_only; } monero_version get_version() const override; monero_network_type get_network_type() const override { return m_network_type; } - std::string get_mnemonic() const override { return m_mnemonic; } - std::string get_mnemonic_language() const override { return m_language; } + std::string get_seed() const override { return m_seed; } + std::string get_seed_language() const override { return m_language; } std::string get_private_view_key() const override { return m_prv_view_key; } std::string get_private_spend_key() const override { return m_prv_spend_key; } std::string get_public_view_key() const override { return m_pub_view_key; } @@ -140,7 +134,7 @@ namespace monero { bool m_is_view_only; monero_network_type m_network_type; cryptonote::account_base m_account; - std::string m_mnemonic; + std::string m_seed; std::string m_language; std::string m_pub_view_key; std::string m_prv_view_key; diff --git a/src/wallet/monero_wallet_model.cpp b/src/wallet/monero_wallet_model.cpp index b9f0dd4..c2d24a6 100644 --- a/src/wallet/monero_wallet_model.cpp +++ b/src/wallet/monero_wallet_model.cpp @@ -99,7 +99,7 @@ namespace monero { m_server_uri = config.m_server_uri; m_server_username = config.m_server_username; m_server_password = config.m_server_password; - m_mnemonic = config.m_mnemonic; + m_seed = config.m_seed; m_seed_offset = config.m_seed_offset; m_primary_address = config.m_primary_address; m_private_view_key = config.m_private_view_key; @@ -109,6 +109,7 @@ namespace monero { m_save_current = config.m_save_current; m_account_lookahead = config.m_account_lookahead; m_subaddress_lookahead = config.m_subaddress_lookahead; + m_is_multisig = config.m_is_multisig; } monero_wallet_config monero_wallet_config::copy() const { @@ -134,7 +135,7 @@ namespace monero { if (m_server_uri != boost::none) monero_utils::add_json_member("serverUri", m_server_uri.get(), allocator, root, value_str); if (m_server_username != boost::none) monero_utils::add_json_member("serverUsername", m_server_username.get(), allocator, root, value_str); if (m_server_password != boost::none) monero_utils::add_json_member("serverPassword", m_server_password.get(), allocator, root, value_str); - if (m_mnemonic != boost::none) monero_utils::add_json_member("mnemonic", m_mnemonic.get(), allocator, root, value_str); + if (m_seed != boost::none) monero_utils::add_json_member("seed", m_seed.get(), allocator, root, value_str); if (m_seed_offset != boost::none) monero_utils::add_json_member("seedOffset", m_seed_offset.get(), allocator, root, value_str); if (m_primary_address != boost::none) monero_utils::add_json_member("primaryAddress", m_primary_address.get(), allocator, root, value_str); if (m_private_view_key != boost::none) monero_utils::add_json_member("privateViewKey", m_private_view_key.get(), allocator, root, value_str); @@ -145,6 +146,7 @@ namespace monero { // set bool values if (m_save_current != boost::none) monero_utils::add_json_member("saveCurrent", m_save_current.get(), allocator, root); + if (m_is_multisig != boost::none) monero_utils::add_json_member("isMultisig", m_is_multisig.get(), allocator, root); // return root return root; @@ -173,7 +175,7 @@ namespace monero { else if (key == std::string("serverUri")) config->m_server_uri = it->second.data(); else if (key == std::string("serverUsername")) config->m_server_username = it->second.data(); else if (key == std::string("serverPassword")) config->m_server_password = it->second.data(); - else if (key == std::string("mnemonic")) config->m_mnemonic = it->second.data(); + else if (key == std::string("seed")) config->m_seed = it->second.data(); else if (key == std::string("seedOffset")) config->m_seed_offset = it->second.data(); else if (key == std::string("primaryAddress")) config->m_primary_address = it->second.data(); else if (key == std::string("privateViewKey")) config->m_private_view_key = it->second.data(); @@ -183,6 +185,7 @@ namespace monero { else if (key == std::string("saveCurrent")) config->m_save_current = it->second.get_value(); else if (key == std::string("accountLookahead")) config->m_account_lookahead = it->second.get_value(); else if (key == std::string("subaddressLookahead")) config->m_subaddress_lookahead = it->second.get_value(); + else if (key == std::string("isMultisig")) config->m_is_multisig = it->second.get_value(); } return config; diff --git a/src/wallet/monero_wallet_model.h b/src/wallet/monero_wallet_model.h index d95b887..7646490 100644 --- a/src/wallet/monero_wallet_model.h +++ b/src/wallet/monero_wallet_model.h @@ -71,7 +71,7 @@ namespace monero { boost::optional m_server_uri; boost::optional m_server_username; boost::optional m_server_password; - boost::optional m_mnemonic; + boost::optional m_seed; boost::optional m_seed_offset; boost::optional m_primary_address; boost::optional m_private_view_key; @@ -81,6 +81,7 @@ namespace monero { boost::optional m_save_current; boost::optional m_account_lookahead; boost::optional m_subaddress_lookahead; + boost::optional m_is_multisig; monero_wallet_config() {} monero_wallet_config(const monero_wallet_config& config); diff --git a/test/sample_code.cpp b/test/sample_code.cpp index 4f3914c..8648bcf 100644 --- a/test/sample_code.cpp +++ b/test/sample_code.cpp @@ -19,9 +19,9 @@ int main(int argc, const char* argv[]) { // mlog_configure("log_cpp_sample_code.txt", true); // mlog_set_log_level(1); - // create a wallet from a mnemonic phrase + // create a wallet from a seed phrase monero_wallet_config wallet_config; - wallet_config.m_mnemonic = "hefty value later extra artistic firm radar yodel talent future fungal nutshell because sanity awesome nail unjustly rage unafraid cedar delayed thumbs comb custom sanity"; + wallet_config.m_seed = "hefty value later extra artistic firm radar yodel talent future fungal nutshell because sanity awesome nail unjustly rage unafraid cedar delayed thumbs comb custom sanity"; wallet_config.m_path = "MyWalletRestored"; wallet_config.m_password = "supersecretpassword123"; wallet_config.m_network_type = monero_network_type::STAGENET; @@ -70,7 +70,7 @@ int main(int argc, const char* argv[]) { output_query.m_is_spent = false; vector> outputs = wallet_restored->get_outputs(output_query); - // create and sync a new wallet with a random mnemonic phrase + // create and sync a new wallet with a random seed wallet_config = monero_wallet_config(); wallet_config.m_path = "MyWalletRandom"; wallet_config.m_password = "supersecretpassword123"; @@ -86,7 +86,7 @@ int main(int argc, const char* argv[]) { wallet_random->start_syncing(5000); // get wallet info - string random_mnemonic = wallet_random->get_mnemonic(); + string random_seed = wallet_random->get_seed(); string random_primary = wallet_random->get_primary_address(); uint64_t random_height = wallet_random->get_height(); bool random_is_synced = wallet_random->is_synced();