refactor mnemonic to seed (breaking change)

This commit is contained in:
woodser
2023-07-24 17:46:42 -04:00
parent f08e57b20c
commit f4c27935fd
8 changed files with 111 additions and 182 deletions
+8 -8
View File
@@ -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");
}
/**
+30 -65
View File
@@ -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<epee::net_utils::http::http_client_factory> 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<epee::net_utils::http::http_client_factory> 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<tools::wallet2>(new tools::wallet2(static_cast<cryptonote::network_type>(config.m_network_type.get()), 1, true));
else wallet->m_w2 = std::unique_ptr<tools::wallet2>(new tools::wallet2(static_cast<cryptonote::network_type>(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<epee::net_utils::http::http_client_factory> http_client_factory) {
monero_wallet_full* monero_wallet_full::create_wallet_from_keys(monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> 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<tools::wallet2>(new tools::wallet2(static_cast<cryptonote::network_type>(config.m_network_type.get()), 1, true));
else wallet->m_w2 = std::unique_ptr<tools::wallet2>(new tools::wallet2(static_cast<cryptonote::network_type>(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<epee::net_utils::http::http_client_factory> http_client_factory) {
monero_wallet_full* monero_wallet_full::create_wallet_random(monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> 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<tools::wallet2>(new tools::wallet2(static_cast<cryptonote::network_type>(config.m_network_type.get()), 1, true));
else wallet->m_w2 = std::unique_ptr<tools::wallet2>(new tools::wallet2(static_cast<cryptonote::network_type>(config.m_network_type.get()), 1, true, std::move(http_client_factory)));
@@ -1214,53 +1220,12 @@ namespace monero {
return wallet;
}
std::vector<std::string> monero_wallet_full::get_mnemonic_languages() {
std::vector<std::string> monero_wallet_full::get_seed_languages() {
std::vector<std::string> 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<epee::net_utils::http::http_client_factory> 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<epee::net_utils::http::http_client_factory> 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<epee::net_utils::http::http_client_factory> 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<monero_network_type>(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();
}
+8 -55
View File
@@ -119,58 +119,11 @@ namespace monero {
static monero_wallet_full* create_wallet(const monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> 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<epee::net_utils::http::http_client_factory> 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<epee::net_utils::http::http_client_factory> 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<epee::net_utils::http::http_client_factory> 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<std::string> get_mnemonic_languages();
static std::vector<std::string> 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<wallet2_listener> m_w2_listener; // internal wallet implementation listener
std::set<monero_wallet_listener*> m_listeners; // external wallet listeners
static monero_wallet_full* create_wallet_from_mnemonic(const monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory);
static monero_wallet_full* create_wallet_from_keys(const monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory);
static monero_wallet_full* create_wallet_random(const monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory);
static monero_wallet_full* create_wallet_from_seed(monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory);
static monero_wallet_full* create_wallet_from_keys(monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory);
static monero_wallet_full* create_wallet_random(monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory);
void init_common();
std::vector<monero_subaddress> get_subaddresses_aux(uint32_t account_idx, const std::vector<uint32_t>& subaddress_indices, const std::vector<tools::wallet2::transfer_details>& transfers) const;
+39 -26
View File
@@ -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<const crypto::secret_key*>(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<cryptonote::network_type>(network_type), address)) throw std::runtime_error("failed to parse address");
if (!get_account_address_from_str(address_info, static_cast<cryptonote::network_type>(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<std::string> monero_wallet_keys::get_mnemonic_languages() {
std::vector<std::string> monero_wallet_keys::get_seed_languages() {
std::vector<std::string> languages;
crypto::ElectrumWords::get_language_list(languages, true); // TODO: support getting names in language
return languages;
+14 -20
View File
@@ -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<std::string> get_mnemonic_languages();
static std::vector<std::string> 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;
+6 -3
View File
@@ -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<bool>();
else if (key == std::string("accountLookahead")) config->m_account_lookahead = it->second.get_value<uint64_t>();
else if (key == std::string("subaddressLookahead")) config->m_subaddress_lookahead = it->second.get_value<uint64_t>();
else if (key == std::string("isMultisig")) config->m_is_multisig = it->second.get_value<bool>();
}
return config;
+2 -1
View File
@@ -71,7 +71,7 @@ namespace monero {
boost::optional<std::string> m_server_uri;
boost::optional<std::string> m_server_username;
boost::optional<std::string> m_server_password;
boost::optional<std::string> m_mnemonic;
boost::optional<std::string> m_seed;
boost::optional<std::string> m_seed_offset;
boost::optional<std::string> m_primary_address;
boost::optional<std::string> m_private_view_key;
@@ -81,6 +81,7 @@ namespace monero {
boost::optional<bool> m_save_current;
boost::optional<uint64_t> m_account_lookahead;
boost::optional<uint64_t> m_subaddress_lookahead;
boost::optional<bool> m_is_multisig;
monero_wallet_config() {}
monero_wallet_config(const monero_wallet_config& config);
+4 -4
View File
@@ -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<shared_ptr<monero_output_wallet>> 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();