31#include <boost/format.hpp>
32#include <boost/asio/ip/address.hpp>
33#include <boost/filesystem/operations.hpp>
34#include <boost/algorithm/string.hpp>
35#include <boost/preprocessor/stringize.hpp>
58#undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
59#define ELECTRONEUM_DEFAULT_LOG_CATEGORY "wallet.rpc"
61#define DEFAULT_AUTO_REFRESH_PERIOD 20
73 constexpr const char default_rpc_username[] =
"electroneum";
75 boost::optional<tools::password_container> password_prompter(
const char *prompt,
bool verify)
80 MERROR(
"failed to read wallet password");
87 if (entry.
height >= blockchain_height || (entry.
height == 0 && (!strcmp(entry.
type.c_str(),
"pending") || !strcmp(entry.
type.c_str(),
"pool"))))
92 if (block_reward == 0)
94 else if (entry.
type ==
"migration" || entry.
type ==
"sc-migration")
128 if (m_auto_refresh_period == 0)
130 if (boost::posix_time::microsec_clock::universal_time() < m_last_auto_refresh_time + boost::posix_time::seconds(m_auto_refresh_period))
133 if (m_wallet) m_wallet->refresh(m_wallet->is_trusted_daemon());
134 }
catch (
const std::exception& ex) {
135 LOG_ERROR(
"Exception at while refreshing, what=" << ex.what());
137 m_last_auto_refresh_time = boost::posix_time::microsec_clock::universal_time();
141 if (m_stop.load(std::memory_order_relaxed))
174 boost::optional<epee::net_utils::http::login> http_login{};
187#define MKDIR(path, mode) mkdir(path)
189#define MKDIR(path, mode) mkdir(path, mode)
191 if (!m_wallet_dir.empty() &&
MKDIR(m_wallet_dir.c_str(), 0700) < 0 && errno != EEXIST)
194 LOG_ERROR(
tr(
"Failed to create directory ") + m_wallet_dir);
196 LOG_ERROR((boost::format(
tr(
"Failed to create directory %s: %s")) % m_wallet_dir % strerror(errno)).str());
204 if (rpc_config->login)
213 if (!rpc_config->login)
215 std::array<std::uint8_t, 16> rand_128bit{{}};
218 default_rpc_username,
222 std::string temp =
"electroneum-wallet-rpc." + bind_port +
".login";
224 if (!rpc_login_file.handle())
226 LOG_ERROR(
tr(
"Failed to create file ") << temp <<
tr(
". Check permissions or remove file"));
229 std::fputs(http_login->username.c_str(), rpc_login_file.handle());
230 std::fputc(
':', rpc_login_file.handle());
232 std::fwrite(password.
data(), 1, password.
size(), rpc_login_file.handle());
233 std::fflush(rpc_login_file.handle());
234 if (std::ferror(rpc_login_file.handle()))
239 LOG_PRINT_L0(
tr(
"RPC username/password is stored in file ") << temp);
244 std::move(rpc_config->login->username), std::move(rpc_config->login->password).password()
247 assert(
bool(http_login));
251 m_last_auto_refresh_time = boost::posix_time::min_date_time;
253 check_background_mining();
258 rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login),
259 std::move(rpc_config->ssl_options)
263 void wallet_rpc_server::check_background_mining()
277 MDEBUG(
"Using an untrusted daemon, skipping background mining check");
283 bool r = m_wallet->invoke_http_json(
"/mining_status", req,
res);
286 MERROR(
"Failed to query mining status: " << (r ?
res.status :
"No connection to daemon"));
289 if (
res.active ||
res.is_background_mining_enabled)
303 req2.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
304 req2.threads_count = 1;
305 req2.do_background_mining =
true;
306 req2.ignore_battery =
false;
307 r = m_wallet->invoke_http_json(
"/start_mining", req2,
res);
317 bool wallet_rpc_server::not_open(epee::json_rpc::error& er)
324 void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry,
const crypto::hash &txid,
const crypto::hash &payment_id,
const tools::wallet2::payment_details &pd)
328 if (entry.
payment_id.substr(16).find_first_not_of(
'0') == std::string::npos)
340 set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward());
343 void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry,
const crypto::hash &txid,
const tools::wallet2::confirmed_transfer_details &pd)
347 if (entry.
payment_id.substr(16).find_first_not_of(
'0') == std::string::npos)
355 entry.
note = m_wallet->get_tx_note(txid);
358 for (
const auto &d: pd.
m_dests) {
359 entry.
destinations.push_back(wallet_rpc::transfer_destination());
360 wallet_rpc::transfer_destination &td = entry.
destinations.back();
361 td.amount = d.amount;
371 set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward());
374 void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry,
const crypto::hash &txid,
const tools::wallet2::unconfirmed_transfer_details &pd)
380 if (entry.
payment_id.substr(16).find_first_not_of(
'0') == std::string::npos)
387 entry.
note = m_wallet->get_tx_note(txid);
389 for (
const auto &d: pd.
m_dests) {
390 entry.
destinations.push_back(wallet_rpc::transfer_destination());
391 wallet_rpc::transfer_destination &td = entry.
destinations.back();
392 td.amount = d.amount;
396 entry.
type = is_failed ?
"failed" :
"pending";
401 set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward());
404 void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry,
const crypto::hash &payment_id,
const tools::wallet2::pool_payment_details &ppd)
406 const tools::wallet2::payment_details &pd = ppd.
m_pd;
409 if (entry.
payment_id.substr(16).find_first_not_of(
'0') == std::string::npos)
423 set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward());
428 if (!m_wallet)
return not_open(er);
431 bool syncedV10 = m_wallet->synced_to_v10();
432 res.balance = req.all_accounts ? m_wallet->balance_all(syncedV10) : m_wallet->balance(req.account_index, syncedV10);
433 res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(syncedV10, &
res.blocks_to_unlock) : m_wallet->unlocked_balance(req.account_index, syncedV10, &
res.blocks_to_unlock);
434 res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images();
435 std::map<uint32_t, std::map<uint32_t, uint64_t>> balance_per_subaddress_per_account;
436 std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress_per_account;
437 if (req.all_accounts)
439 for (
uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index)
441 balance_per_subaddress_per_account[account_index] = m_wallet->balance_per_subaddress(account_index, syncedV10);
442 unlocked_balance_per_subaddress_per_account[account_index] = m_wallet->unlocked_balance_per_subaddress(account_index, syncedV10);
447 balance_per_subaddress_per_account[req.account_index] = m_wallet->balance_per_subaddress(req.account_index, syncedV10);
448 unlocked_balance_per_subaddress_per_account[req.account_index] = m_wallet->unlocked_balance_per_subaddress(req.account_index, syncedV10);
450 std::vector<tools::wallet2::transfer_details> transfers;
451 m_wallet->get_transfers(transfers);
452 for (
const auto& p : balance_per_subaddress_per_account)
455 std::map<uint32_t, uint64_t> balance_per_subaddress = p.second;
456 std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = unlocked_balance_per_subaddress_per_account[account_index];
457 std::set<uint32_t> address_indices;
458 if (!req.all_accounts && !req.address_indices.empty())
460 address_indices = req.address_indices;
464 for (
const auto& i : balance_per_subaddress)
465 address_indices.insert(i.first);
469 wallet_rpc::COMMAND_RPC_GET_BALANCE::per_subaddress_info
info;
470 info.account_index = account_index;
471 info.address_index = i;
472 cryptonote::subaddress_index index = {
info.account_index,
info.address_index};
473 info.address = m_wallet->get_subaddress_as_str(index);
474 info.balance = balance_per_subaddress[i];
475 info.unlocked_balance = unlocked_balance_per_subaddress[i].first;
476 info.blocks_to_unlock = unlocked_balance_per_subaddress[i].second;
477 info.label = m_wallet->get_subaddress_label(index);
478 info.num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&](
const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == index && (syncedV10 ? td.m_tx.version > 1 : true); });
479 res.per_subaddress.emplace_back(std::move(
info));
483 catch (
const std::exception& e)
493 if (!m_wallet)
return not_open(er);
496 THROW_WALLET_EXCEPTION_IF(req.account_index >= m_wallet->get_num_subaddress_accounts(), error::account_index_outofbound);
497 res.addresses.clear();
498 std::vector<uint32_t> req_address_index;
499 if (req.address_index.empty())
501 for (
uint32_t i = 0; i < m_wallet->get_num_subaddresses(req.account_index); ++i)
502 req_address_index.push_back(i);
506 req_address_index = req.address_index;
509 m_wallet->get_transfers(transfers);
510 for (
uint32_t i : req_address_index)
513 res.addresses.resize(
res.addresses.size() + 1);
514 auto&
info =
res.addresses.back();
515 const cryptonote::subaddress_index index = {req.account_index, i};
516 info.address = m_wallet->get_subaddress_as_str(index);
517 info.label = m_wallet->get_subaddress_label(index);
519 info.used = std::find_if(transfers.begin(), transfers.end(), [&](
const tools::wallet2::transfer_details& td) { return td.m_subaddr_index == index; }) != transfers.end();
521 res.address = m_wallet->get_subaddress_as_str({req.account_index, 0});
523 catch (
const std::exception& e)
533 if (!m_wallet)
return not_open(er);
534 cryptonote::address_parse_info
info;
538 er.
message =
"Invalid address";
541 auto index = m_wallet->get_subaddress_index(
info.address);
545 er.
message =
"Address doesn't belong to the wallet";
554 if (!m_wallet)
return not_open(er);
557 m_wallet->add_subaddress(req.account_index, req.label);
558 res.address_index = m_wallet->get_num_subaddresses(req.account_index) - 1;
559 res.address = m_wallet->get_subaddress_as_str({req.account_index,
res.address_index});
561 catch (
const std::exception& e)
571 if (!m_wallet)
return not_open(er);
574 m_wallet->set_subaddress_label(req.index, req.label);
576 catch (
const std::exception& e)
586 if (!m_wallet)
return not_open(er);
587 bool syncedV10 = m_wallet->synced_to_v10();
590 res.total_balance = 0;
591 res.total_unlocked_balance = 0;
592 cryptonote::subaddress_index subaddr_index = {0,0};
594 uint64_t acc_major_offset = m_wallet->account_major_offset();
597 if(!req.account_index.empty()) {
598 subaddr_index.
major =
static_cast<uint32_t>(std::stoul(req.account_index));
600 wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::subaddress_account_info
info;
601 info.account_index = subaddr_index.
major;
602 info.base_address = m_wallet->get_subaddress_as_str(subaddr_index);
603 info.balance = m_wallet->balance(subaddr_index.
major, syncedV10);
604 info.unlocked_balance = m_wallet->unlocked_balance(subaddr_index.
major, syncedV10);
605 info.label = m_wallet->get_subaddress_label(subaddr_index);
606 res.subaddress_accounts.push_back(
info);
607 res.total_balance +=
info.balance;
608 res.total_unlocked_balance +=
info.unlocked_balance;
609 res.account_major_offset = acc_major_offset;
614 const std::pair<std::map<std::string, std::string>, std::vector<std::string>> account_tags = m_wallet->get_account_tags();
615 if (!req.tag.empty() && account_tags.first.count(req.tag) == 0)
618 er.
message = (boost::format(
tr(
"Tag %s is unregistered.")) % req.tag).str();
621 for (; subaddr_index.
major < m_wallet->get_num_subaddress_accounts(); ++subaddr_index.
major)
623 if (!req.tag.empty() && req.tag != account_tags.second[subaddr_index.
major])
625 wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::subaddress_account_info
info;
626 info.account_index = subaddr_index.
major;
627 info.base_address = m_wallet->get_subaddress_as_str(subaddr_index);
628 info.balance = m_wallet->balance(subaddr_index.
major, syncedV10);
629 info.unlocked_balance = m_wallet->unlocked_balance(subaddr_index.
major, syncedV10);
630 info.label = m_wallet->get_subaddress_label(subaddr_index);
631 info.tag = account_tags.second[subaddr_index.
major];
632 res.subaddress_accounts.push_back(
info);
633 res.total_balance +=
info.balance;
634 res.total_unlocked_balance +=
info.unlocked_balance;
635 res.account_major_offset = acc_major_offset;
638 catch (
const std::exception& e)
648 if (!m_wallet)
return not_open(er);
651 m_wallet->add_subaddress_account(req.label);
652 res.account_index = m_wallet->get_num_subaddress_accounts() - 1;
653 res.address = m_wallet->get_subaddress_as_str({
res.account_index, 0});
655 catch (
const std::exception& e)
665 if (!m_wallet)
return not_open(er);
668 m_wallet->set_subaddress_label({req.account_index, 0}, req.label);
670 catch (
const std::exception& e)
680 if (!m_wallet)
return not_open(er);
681 const std::pair<std::map<std::string, std::string>, std::vector<std::string>> account_tags = m_wallet->get_account_tags();
682 for (
const std::pair<std::string, std::string>& p : account_tags.first)
684 res.account_tags.resize(
res.account_tags.size() + 1);
685 auto&
info =
res.account_tags.back();
687 info.label = p.second;
688 for (
size_t i = 0; i < account_tags.second.size(); ++i)
690 if (account_tags.second[i] ==
info.tag)
691 info.accounts.push_back(i);
699 if (!m_wallet)
return not_open(er);
702 m_wallet->set_account_tag(req.accounts, req.tag);
704 catch (
const std::exception& e)
714 if (!m_wallet)
return not_open(er);
717 m_wallet->set_account_tag(req.accounts,
"");
719 catch (
const std::exception& e)
729 if (!m_wallet)
return not_open(er);
732 m_wallet->set_account_tag_description(req.tag, req.description);
734 catch (
const std::exception& e)
744 if (!m_wallet)
return not_open(er);
747 res.height = m_wallet->get_blockchain_current_height();
749 catch (
const std::exception& e)
757 bool wallet_rpc_server::validate_transfer(
const std::list<wallet_rpc::transfer_destination>& destinations,
const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra,
bool at_least_one_destination, epee::json_rpc::error& er)
760 std::string extra_nonce;
761 for (
auto it = destinations.begin(); it != destinations.end(); it++)
763 cryptonote::address_parse_info
info;
764 cryptonote::tx_destination_entry de;
767 [&er](
const std::string &url,
const std::vector<std::string> &addresses,
bool dnssec_valid)->std::string {
770 er.message = std::string(
"Invalid DNSSEC for ") + url;
773 if (addresses.empty())
775 er.message = std::string(
"No Electroneum address found at ") + url;
783 er.
message = std::string(
"WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + it->address;
794 if (
info.has_payment_id)
796 if (!payment_id.empty() || integrated_payment_id != crypto::null_hash8)
799 er.
message =
"A single payment id is allowed per transaction";
804 memcpy(payment_id.data,
info.payment_id.data, 8);
805 memset(payment_id.data + 8, 0, 24);
812 er.
message =
"Something went wrong with integrated payment_id.";
818 if (at_least_one_destination && dsts.empty())
821 er.
message =
"No destinations for this transfer";
825 if (!payment_id.empty())
829 const std::string& payment_id_str = payment_id;
835 if (wallet2::parse_long_payment_id(payment_id_str, long_payment_id)) {
840 er.
message =
"Payment id has invalid format: \"" + payment_id_str +
"\", expected 64 character string";
847 er.
message =
"Something went wrong with payment_id. Please check its format: \"" + payment_id_str +
"\", expected 64-character string";
857 std::ostringstream oss;
870 template<
typename T>
static bool is_error_value(
const T &val) {
return false; }
871 static bool is_error_value(
const std::string &s) {
return s.empty(); }
873 template<
typename T,
typename V>
874 static bool fill(
T &where, V s)
876 if (is_error_value(s))
return false;
877 where = std::move(s);
881 template<
typename T,
typename V>
882 static bool fill(std::list<T> &where, V s)
884 if (is_error_value(s))
return false;
885 where.emplace_back(std::move(s));
896 template<
typename Ts,
typename Tu>
897 bool wallet_rpc_server::fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector,
898 bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, std::string &multisig_txset, std::string &unsigned_txset,
bool do_not_relay,
899 Ts &tx_hash,
bool get_tx_hex, Ts &tx_blob,
bool get_tx_metadata, Ts &tx_metadata,
epee::json_rpc::error &er)
901 for (
const auto & ptx : ptx_vector)
908 fill(tx_key, std::string(s.
data(), s.
size()));
911 fill(amount, total_amount(ptx));
915 if (m_wallet->multisig())
918 if (multisig_txset.empty())
921 er.
message =
"Failed to save multisig tx set after creation";
927 if (m_wallet->watch_only()){
929 if (unsigned_txset.empty())
932 er.
message =
"Failed to save unsigned tx set after creation";
936 else if (!do_not_relay)
937 m_wallet->commit_tx(ptx_vector);
940 for (
auto & ptx : ptx_vector)
944 r = r && (!get_tx_metadata || fill(tx_metadata, ptx_to_string(ptx)));
948 er.
message =
"Failed to save tx info";
956 bool wallet_rpc_server::on_transfer(
const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
959 std::vector<cryptonote::tx_destination_entry> dsts;
960 std::vector<uint8_t> extra;
963 if (!m_wallet)
return not_open(er);
967 er.
message =
"Command unavailable in restricted mode.";
972 if (!validate_transfer(req.destinations, req.payment_id, dsts, extra,
true, er))
979 uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
980 uint32_t priority = m_wallet->adjust_priority(req.priority);
981 std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
983 if (ptx_vector.empty())
986 er.
message =
"No transaction created";
991 if (ptx_vector.size() != 1)
994 er.
message =
"Transaction would be too large. try /transfer_split.";
998 return fill_response(ptx_vector, req.get_tx_key,
res.tx_key,
res.amount,
res.fee,
res.multisig_txset,
res.unsigned_txset, req.do_not_relay,
999 res.tx_hash, req.get_tx_hex,
res.tx_blob, req.get_tx_metadata,
res.tx_metadata, er);
1001 catch (
const std::exception& e)
1009 bool wallet_rpc_server::on_transfer_split(
const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1012 std::vector<cryptonote::tx_destination_entry> dsts;
1013 std::vector<uint8_t> extra;
1015 if (!m_wallet)
return not_open(er);
1019 er.
message =
"Command unavailable in restricted mode.";
1024 if (!validate_transfer(req.destinations, req.payment_id, dsts, extra,
true, er))
1031 uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
1032 uint32_t priority = m_wallet->adjust_priority(req.priority);
1033 LOG_PRINT_L2(
"on_transfer_split calling create_transactions_2");
1034 std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
1035 LOG_PRINT_L2(
"on_transfer_split called create_transactions_2");
1037 return fill_response(ptx_vector, req.get_tx_keys,
res.tx_key_list,
res.amount_list,
res.fee_list,
res.multisig_txset,
res.unsigned_txset, req.do_not_relay,
1038 res.tx_hash_list, req.get_tx_hex,
res.tx_blob_list, req.get_tx_metadata,
res.tx_metadata_list, er);
1040 catch (
const std::exception& e)
1048 bool wallet_rpc_server::on_sign_transfer(
const wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1050 if (!m_wallet)
return not_open(er);
1054 er.
message =
"Command unavailable in restricted mode.";
1057 if (m_wallet->key_on_device())
1060 er.
message =
"command not supported by HW wallet";
1063 if(m_wallet->watch_only())
1066 er.
message =
"command not supported by watch-only wallet";
1074 er.
message =
"Failed to parse hex.";
1079 if(!m_wallet->parse_unsigned_tx_from_str(blob, exported_txs))
1082 er.
message =
"cannot load unsigned_txset";
1086 std::vector<tools::wallet2::pending_tx> ptxs;
1090 std::string ciphertext = m_wallet->sign_tx_dump_to_str(exported_txs, ptxs, signed_txs);
1091 if (ciphertext.empty())
1094 er.
message =
"Failed to sign unsigned tx";
1100 catch (
const std::exception &e)
1103 er.
message = std::string(
"Failed to sign unsigned tx: ") + e.what();
1107 for (
auto &ptx: ptxs)
1110 if (req.get_tx_keys)
1120 for (
auto &ptx: ptxs)
1129 bool wallet_rpc_server::on_describe_transfer(
const wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1131 if (!m_wallet)
return not_open(er);
1135 er.
message =
"Command unavailable in restricted mode.";
1138 if (m_wallet->key_on_device())
1141 er.
message =
"command not supported by HW wallet";
1144 if(m_wallet->watch_only())
1147 er.
message =
"command not supported by watch-only wallet";
1150 if(req.unsigned_txset.empty() && req.multisig_txset.empty())
1153 er.
message =
"no txset provided";
1157 std::vector <wallet2::tx_construction_data> tx_constructions;
1158 if (!req.unsigned_txset.empty()) {
1164 er.
message =
"Failed to parse hex.";
1167 if (!m_wallet->parse_unsigned_tx_from_str(blob, exported_txs)) {
1169 er.
message =
"cannot load unsigned_txset";
1172 tx_constructions = exported_txs.
txes;
1174 catch (
const std::exception &e) {
1176 er.
message =
"failed to parse unsigned transfers: " + std::string(e.what());
1179 }
else if (!req.multisig_txset.empty()) {
1185 er.
message =
"Failed to parse hex.";
1188 if (!m_wallet->parse_multisig_tx_from_str(blob, exported_txs)) {
1190 er.
message =
"cannot load multisig_txset";
1194 for (
size_t n = 0; n < exported_txs.
m_ptx.size(); ++n) {
1195 tx_constructions.push_back(exported_txs.
m_ptx[n].construction_data);
1198 catch (
const std::exception &e) {
1200 er.
message =
"failed to parse multisig transfers: " + std::string(e.what());
1205 std::vector<tools::wallet2::pending_tx> ptx;
1209 std::unordered_map<cryptonote::account_public_address, std::pair<std::string, uint64_t>> dests;
1210 int first_known_non_zero_change_index = -1;
1211 for (
size_t n = 0; n < tx_constructions.size(); ++n)
1214 res.desc.push_back({0, 0, std::numeric_limits<uint32_t>::max(), 0, {},
"", 0,
"", 0, 0,
""});
1215 wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::transfer_description &desc =
res.desc.back();
1217 std::vector<cryptonote::tx_extra_field> tx_extra_fields;
1218 bool has_encrypted_payment_id =
false;
1229 memcpy(payment_id.data, payment_id8.data, 8);
1230 memset(payment_id.data + 8, 0, 24);
1241 for (
size_t s = 0; s < cd.
sources.size(); ++s)
1243 desc.amount_in += cd.
sources[s].amount;
1244 size_t ring_size = cd.
sources[s].outputs.size();
1245 if (ring_size < desc.ring_size)
1246 desc.ring_size = ring_size;
1254 auto i = dests.find(entry.
addr);
1255 if (i == dests.end())
1256 dests.insert(std::make_pair(entry.
addr, std::make_pair(
address, entry.
amount)));
1258 i->second.second += entry.
amount;
1259 desc.amount_out += entry.
amount;
1264 if (it == dests.end())
1267 er.
message =
"Claimed change does not go to a paid address";
1273 er.
message =
"Claimed change is larger than payment to the change address";
1278 if (first_known_non_zero_change_index == -1)
1279 first_known_non_zero_change_index = n;
1284 er.
message =
"Change goes to more than one address";
1290 if (it->second.second == 0)
1294 size_t n_dummy_outputs = 0;
1295 for (
auto i = dests.begin(); i != dests.end(); )
1297 if (i->second.second > 0)
1299 desc.recipients.push_back({i->second.first, i->second.second});
1302 ++desc.dummy_outputs;
1306 if (desc.change_amount > 0)
1312 desc.fee = desc.amount_in - desc.amount_out;
1317 catch (
const std::exception &e)
1320 er.
message =
"failed to parse unsigned transfers";
1327 bool wallet_rpc_server::on_submit_transfer(
const wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1329 if (!m_wallet)
return not_open(er);
1333 er.
message =
"Command unavailable in restricted mode.";
1336 if (m_wallet->key_on_device())
1339 er.
message =
"command not supported by HW wallet";
1347 er.
message =
"Failed to parse hex.";
1351 std::vector<tools::wallet2::pending_tx> ptx_vector;
1354 bool r = m_wallet->parse_tx_from_str(blob, ptx_vector, NULL);
1358 er.
message =
"Failed to parse signed tx data.";
1362 catch (
const std::exception &e)
1365 er.
message = std::string(
"Failed to parse signed tx: ") + e.what();
1371 for (
auto &ptx: ptx_vector)
1373 m_wallet->commit_tx(ptx);
1377 catch (
const std::exception &e)
1380 er.
message = std::string(
"Failed to submit signed tx: ") + e.what();
1387 bool wallet_rpc_server::on_sweep_dust(
const wallet_rpc::COMMAND_RPC_SWEEP_DUST::request& req, wallet_rpc::COMMAND_RPC_SWEEP_DUST::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1389 if (!m_wallet)
return not_open(er);
1393 er.
message =
"Command unavailable in restricted mode.";
1399 std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions();
1401 return fill_response(ptx_vector, req.get_tx_keys,
res.tx_key_list,
res.amount_list,
res.fee_list,
res.multisig_txset,
res.unsigned_txset, req.do_not_relay,
1402 res.tx_hash_list, req.get_tx_hex,
res.tx_blob_list, req.get_tx_metadata,
res.tx_metadata_list, er);
1404 catch (
const std::exception& e)
1412 bool wallet_rpc_server::on_sweep_all(
const wallet_rpc::COMMAND_RPC_SWEEP_ALL::request& req, wallet_rpc::COMMAND_RPC_SWEEP_ALL::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1414 std::vector<cryptonote::tx_destination_entry> dsts;
1415 std::vector<uint8_t> extra;
1417 if (!m_wallet)
return not_open(er);
1421 er.
message =
"Command unavailable in restricted mode.";
1426 std::list<wallet_rpc::transfer_destination> destination;
1427 destination.push_back(wallet_rpc::transfer_destination());
1428 destination.back().amount = 0;
1429 destination.back().address = req.address;
1430 if (!validate_transfer(destination, req.payment_id, dsts, extra,
true, er))
1435 if (req.outputs < 1)
1438 er.
message =
"Amount of outputs should be greater than 0.";
1442 std::set<uint32_t> subaddr_indices;
1443 if (req.subaddr_indices_all)
1445 for (
uint32_t i = 0; i < m_wallet->get_num_subaddresses(req.account_index); ++i)
1446 subaddr_indices.insert(i);
1450 subaddr_indices= req.subaddr_indices;
1455 uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
1456 uint32_t priority = m_wallet->adjust_priority(req.priority);
1457 std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra, req.account_index, subaddr_indices);
1459 return fill_response(ptx_vector, req.get_tx_keys,
res.tx_key_list,
res.amount_list,
res.fee_list,
res.multisig_txset,
res.unsigned_txset, req.do_not_relay,
1460 res.tx_hash_list, req.get_tx_hex,
res.tx_blob_list, req.get_tx_metadata,
res.tx_metadata_list, er);
1462 catch (
const std::exception& e)
1470 bool wallet_rpc_server::on_sweep_single(
const wallet_rpc::COMMAND_RPC_SWEEP_SINGLE::request& req, wallet_rpc::COMMAND_RPC_SWEEP_SINGLE::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1472 std::vector<cryptonote::tx_destination_entry> dsts;
1473 std::vector<uint8_t> extra;
1475 if (!m_wallet)
return not_open(er);
1479 er.
message =
"Command unavailable in restricted mode.";
1483 if (req.outputs < 1)
1486 er.
message =
"Amount of outputs should be greater than 0.";
1491 std::list<wallet_rpc::transfer_destination> destination;
1492 destination.push_back(wallet_rpc::transfer_destination());
1493 destination.back().amount = 0;
1494 destination.back().address = req.address;
1495 if (!validate_transfer(destination, req.payment_id, dsts, extra,
true, er))
1504 er.
message =
"failed to parse key image";
1510 uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
1511 uint32_t priority = m_wallet->adjust_priority(req.priority);
1512 std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra);
1514 if (ptx_vector.empty())
1517 er.
message =
"No outputs found";
1520 if (ptx_vector.size() > 1)
1523 er.
message =
"Multiple transactions are created, which is not supposed to happen";
1526 const wallet2::pending_tx &ptx = ptx_vector[0];
1527 if (ptx.selected_transfers.size() > 1)
1530 er.
message =
"The transaction uses multiple inputs, which is not supposed to happen";
1534 return fill_response(ptx_vector, req.get_tx_key,
res.tx_key,
res.amount,
res.fee,
res.multisig_txset,
res.unsigned_txset, req.do_not_relay,
1535 res.tx_hash, req.get_tx_hex,
res.tx_blob, req.get_tx_metadata,
res.tx_metadata, er);
1537 catch (
const std::exception& e)
1545 er.
message =
"WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
1551 bool wallet_rpc_server::on_relay_tx(
const wallet_rpc::COMMAND_RPC_RELAY_TX::request& req, wallet_rpc::COMMAND_RPC_RELAY_TX::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1553 if (!m_wallet)
return not_open(er);
1559 er.
message =
"Failed to parse hex.";
1566 std::istringstream iss(blob);
1573 er.
message =
"Failed to parse tx metadata.";
1579 m_wallet->commit_tx(ptx);
1581 catch(
const std::exception &e)
1584 er.
message =
"Failed to commit tx.";
1593 bool wallet_rpc_server::on_make_integrated_address(
const wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1595 if (!m_wallet)
return not_open(er);
1599 if (req.payment_id.empty())
1608 er.
message =
"Invalid payment ID";
1613 if (req.standard_address.empty())
1615 res.integrated_address = m_wallet->get_integrated_address_as_str(payment_id);
1623 er.
message =
"Invalid address";
1626 if (
info.is_subaddress)
1629 er.
message =
"Subaddress shouldn't be used";
1632 if (
info.has_payment_id)
1635 er.
message =
"Already integrated address";
1638 if (req.payment_id.empty())
1641 er.
message =
"Payment ID shouldn't be left unspecified";
1649 catch (
const std::exception& e)
1657 bool wallet_rpc_server::on_split_integrated_address(
const wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1659 if (!m_wallet)
return not_open(er);
1667 er.
message =
"Invalid address";
1670 if(!
info.has_payment_id)
1673 er.
message =
"Address is not an integrated address";
1680 catch (
const std::exception& e)
1688 bool wallet_rpc_server::on_store(
const wallet_rpc::COMMAND_RPC_STORE::request& req, wallet_rpc::COMMAND_RPC_STORE::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1690 if (!m_wallet)
return not_open(er);
1694 er.
message =
"Command unavailable in restricted mode.";
1702 catch (
const std::exception& e)
1710 bool wallet_rpc_server::on_get_payments(
const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1712 if (!m_wallet)
return not_open(er);
1719 er.
message =
"Payment ID has invalid format";
1723 if(
sizeof(payment_id) == payment_id_blob.size())
1725 payment_id = *
reinterpret_cast<const crypto::hash*
>(payment_id_blob.data());
1727 else if(
sizeof(payment_id8) == payment_id_blob.size())
1729 payment_id8 = *
reinterpret_cast<const crypto::hash8*
>(payment_id_blob.data());
1730 memcpy(payment_id.data, payment_id8.data, 8);
1731 memset(payment_id.data + 8, 0, 24);
1736 er.
message =
"Payment ID has invalid size: " + req.payment_id;
1740 res.payments.clear();
1741 std::list<wallet2::payment_details> payment_list;
1742 m_wallet->get_payments(payment_id, payment_list);
1743 for (
auto & payment : payment_list)
1745 wallet_rpc::payment_details rpc_payment;
1746 rpc_payment.payment_id = req.payment_id;
1748 rpc_payment.amount = payment.m_amount;
1749 rpc_payment.block_height = payment.m_block_height;
1750 rpc_payment.unlock_time = payment.m_unlock_time;
1751 rpc_payment.subaddr_index = payment.m_subaddr_index;
1752 rpc_payment.address = m_wallet->get_subaddress_as_str(payment.m_subaddr_index);
1753 res.payments.push_back(rpc_payment);
1759 bool wallet_rpc_server::on_get_bulk_payments(
const wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1761 res.payments.clear();
1762 if (!m_wallet)
return not_open(er);
1765 if (req.payment_ids.empty())
1767 std::list<std::pair<crypto::hash,wallet2::payment_details>> payment_list;
1768 m_wallet->get_payments(payment_list, req.min_block_height);
1770 for (
auto & payment : payment_list)
1772 wallet_rpc::payment_details rpc_payment;
1775 rpc_payment.amount = payment.second.m_amount;
1776 rpc_payment.block_height = payment.second.m_block_height;
1777 rpc_payment.unlock_time = payment.second.m_unlock_time;
1778 rpc_payment.subaddr_index = payment.second.m_subaddr_index;
1779 rpc_payment.address = m_wallet->get_subaddress_as_str(payment.second.m_subaddr_index);
1780 res.payments.push_back(std::move(rpc_payment));
1786 for (
auto & payment_id_str : req.payment_ids)
1794 if (payment_id_str.size() == 2 *
sizeof(payment_id))
1798 else if (payment_id_str.size() == 2 *
sizeof(payment_id8))
1803 memcpy(payment_id.data, payment_id8.data, 8);
1804 memset(payment_id.data + 8, 0, 24);
1810 er.
message =
"Payment ID has invalid size: " + payment_id_str;
1817 er.
message =
"Payment ID has invalid format: " + payment_id_str;
1821 std::list<wallet2::payment_details> payment_list;
1822 m_wallet->get_payments(payment_id, payment_list, req.min_block_height);
1824 for (
auto & payment : payment_list)
1826 wallet_rpc::payment_details rpc_payment;
1827 rpc_payment.payment_id = payment_id_str;
1829 rpc_payment.amount = payment.m_amount;
1830 rpc_payment.block_height = payment.m_block_height;
1831 rpc_payment.unlock_time = payment.m_unlock_time;
1832 rpc_payment.subaddr_index = payment.m_subaddr_index;
1833 rpc_payment.address = m_wallet->get_subaddress_as_str(payment.m_subaddr_index);
1834 res.payments.push_back(std::move(rpc_payment));
1841 bool wallet_rpc_server::on_incoming_transfers(
const wallet_rpc::COMMAND_RPC_INCOMING_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_INCOMING_TRANSFERS::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1843 if (!m_wallet)
return not_open(er);
1844 if(req.transfer_type.compare(
"all") != 0 && req.transfer_type.compare(
"available") != 0 && req.transfer_type.compare(
"unavailable") != 0)
1847 er.
message =
"Transfer type must be one of: all, available, or unavailable";
1851 bool filter =
false;
1852 bool available =
false;
1853 if (req.transfer_type.compare(
"available") == 0)
1858 else if (req.transfer_type.compare(
"unavailable") == 0)
1864 wallet2::transfer_container transfers;
1865 m_wallet->get_transfers(transfers);
1867 bool transfers_found =
false;
1868 for (
const auto& td : transfers)
1870 if (!filter || available != td.m_spent)
1872 if (req.account_index != td.m_subaddr_index.major || (!req.subaddr_indices.empty() && req.subaddr_indices.count(td.m_subaddr_index.minor) == 0))
1874 transfers_found =
true;
1875 wallet_rpc::transfer_details rpc_transfers;
1876 rpc_transfers.amount = td.amount();
1877 rpc_transfers.spent = td.m_spent;
1878 rpc_transfers.global_index = td.m_global_output_index;
1880 rpc_transfers.subaddr_index = {td.m_subaddr_index.major, td.m_subaddr_index.minor};
1882 rpc_transfers.block_height = td.m_block_height;
1883 rpc_transfers.frozen = td.m_frozen;
1884 rpc_transfers.unlocked = m_wallet->is_transfer_unlocked(td);
1885 res.transfers.push_back(rpc_transfers);
1892 bool wallet_rpc_server::on_query_key(
const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1894 if (!m_wallet)
return not_open(er);
1898 er.
message =
"Command unavailable in restricted mode.";
1902 if (req.key_type.compare(
"mnemonic") == 0)
1906 if (m_wallet->multisig(&ready))
1911 er.
message =
"This wallet is multisig, but not yet finalized";
1914 if (!m_wallet->get_multisig_seed(seed))
1917 er.
message =
"Failed to get multisig seed.";
1923 if (m_wallet->watch_only())
1926 er.
message =
"The wallet is watch-only. Cannot retrieve seed.";
1929 if (!m_wallet->is_deterministic())
1932 er.
message =
"The wallet is non-deterministic. Cannot display seed.";
1935 if (!m_wallet->get_seed(seed))
1938 er.
message =
"Failed to get seed.";
1944 else if(req.key_type.compare(
"view_key") == 0)
1947 res.key = std::string(
key.data(),
key.size());
1949 else if(req.key_type.compare(
"spend_key") == 0)
1951 if (m_wallet->watch_only())
1954 er.
message =
"The wallet is watch-only. Cannot retrieve spend key.";
1958 res.key = std::string(
key.data(),
key.size());
1962 er.
message =
"key_type " + req.key_type +
" not found";
1969 bool wallet_rpc_server::on_rescan_blockchain(
const wallet_rpc::COMMAND_RPC_RESCAN_BLOCKCHAIN::request& req, wallet_rpc::COMMAND_RPC_RESCAN_BLOCKCHAIN::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1971 if (!m_wallet)
return not_open(er);
1975 er.
message =
"Command unavailable in restricted mode.";
1981 m_wallet->rescan_blockchain(req.hard);
1983 catch (
const std::exception& e)
1991 bool wallet_rpc_server::on_sign(
const wallet_rpc::COMMAND_RPC_SIGN::request& req, wallet_rpc::COMMAND_RPC_SIGN::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
1993 if (!m_wallet)
return not_open(er);
1997 er.
message =
"Command unavailable in restricted mode.";
2001 res.signature = m_wallet->sign(req.data);
2005 bool wallet_rpc_server::on_verify(
const wallet_rpc::COMMAND_RPC_VERIFY::request& req, wallet_rpc::COMMAND_RPC_VERIFY::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2007 if (!m_wallet)
return not_open(er);
2011 er.
message =
"Command unavailable in restricted mode.";
2018 [&er](
const std::string &url,
const std::vector<std::string> &addresses,
bool dnssec_valid)->std::string {
2021 er.message = std::string(
"Invalid DNSSEC for ") + url;
2024 if (addresses.empty())
2026 er.message = std::string(
"No ETN address found at ") + url;
2029 return addresses[0];
2036 res.good = m_wallet->verify(req.data,
info.address, req.signature);
2040 bool wallet_rpc_server::on_stop_wallet(
const wallet_rpc::COMMAND_RPC_STOP_WALLET::request& req, wallet_rpc::COMMAND_RPC_STOP_WALLET::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2042 if (!m_wallet)
return not_open(er);
2046 er.
message =
"Command unavailable in restricted mode.";
2053 m_stop.store(
true, std::memory_order_relaxed);
2055 catch (
const std::exception& e)
2063 bool wallet_rpc_server::on_set_tx_notes(
const wallet_rpc::COMMAND_RPC_SET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_SET_TX_NOTES::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2065 if (!m_wallet)
return not_open(er);
2069 er.
message =
"Command unavailable in restricted mode.";
2073 if (req.txids.size() != req.notes.size())
2076 er.
message =
"Different amount of txids and notes";
2080 std::list<crypto::hash> txids;
2081 std::list<std::string>::const_iterator i = req.txids.begin();
2082 while (i != req.txids.end())
2088 er.
message =
"TX ID has invalid format";
2093 txids.push_back(txid);
2096 std::list<crypto::hash>::const_iterator il = txids.begin();
2097 std::list<std::string>::const_iterator
in = req.notes.begin();
2098 while (il != txids.end())
2100 m_wallet->set_tx_note(*il++, *in++);
2106 bool wallet_rpc_server::on_get_tx_notes(
const wallet_rpc::COMMAND_RPC_GET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_GET_TX_NOTES::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2109 if (!m_wallet)
return not_open(er);
2111 std::list<crypto::hash> txids;
2112 std::list<std::string>::const_iterator i = req.txids.begin();
2113 while (i != req.txids.end())
2119 er.
message =
"TX ID has invalid format";
2124 txids.push_back(txid);
2127 std::list<crypto::hash>::const_iterator il = txids.begin();
2128 while (il != txids.end())
2130 res.notes.push_back(m_wallet->get_tx_note(*il++));
2135 bool wallet_rpc_server::on_set_attribute(
const wallet_rpc::COMMAND_RPC_SET_ATTRIBUTE::request& req, wallet_rpc::COMMAND_RPC_SET_ATTRIBUTE::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2137 if (!m_wallet)
return not_open(er);
2141 er.
message =
"Command unavailable in restricted mode.";
2145 m_wallet->set_attribute(req.key, req.value);
2150 bool wallet_rpc_server::on_get_attribute(
const wallet_rpc::COMMAND_RPC_GET_ATTRIBUTE::request& req, wallet_rpc::COMMAND_RPC_GET_ATTRIBUTE::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2152 if (!m_wallet)
return not_open(er);
2156 er.
message =
"Command unavailable in restricted mode.";
2160 res.value = m_wallet->get_attribute(req.key);
2163 bool wallet_rpc_server::on_get_tx_key(
const wallet_rpc::COMMAND_RPC_GET_TX_KEY::request& req, wallet_rpc::COMMAND_RPC_GET_TX_KEY::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2165 if (!m_wallet)
return not_open(er);
2171 er.
message =
"TX ID has invalid format";
2176 std::vector<crypto::secret_key> additional_tx_keys;
2177 if (!m_wallet->get_tx_key(txid, tx_key, additional_tx_keys))
2180 er.
message =
"No tx secret key is stored for this tx";
2186 for (
size_t i = 0; i < additional_tx_keys.size(); ++i)
2192 bool wallet_rpc_server::on_check_tx_key(
const wallet_rpc::COMMAND_RPC_CHECK_TX_KEY::request& req, wallet_rpc::COMMAND_RPC_CHECK_TX_KEY::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2194 if (!m_wallet)
return not_open(er);
2200 er.
message =
"TX ID has invalid format";
2205 if (tx_key_str.
size() < 64 || tx_key_str.
size() % 64)
2208 er.
message =
"Tx key has invalid format";
2211 const char *data = tx_key_str.
data();
2216 er.
message =
"Tx key has invalid format";
2220 std::vector<crypto::secret_key> additional_tx_keys;
2221 while (offset < tx_key_str.
size())
2223 additional_tx_keys.resize(additional_tx_keys.size() + 1);
2227 er.
message =
"Tx key has invalid format";
2237 er.
message =
"Invalid address";
2243 m_wallet->check_tx_key(txid, tx_key, additional_tx_keys,
info.address,
res.received,
res.in_pool,
res.confirmations);
2245 catch (
const std::exception &e)
2254 bool wallet_rpc_server::on_get_tx_proof(
const wallet_rpc::COMMAND_RPC_GET_TX_PROOF::request& req, wallet_rpc::COMMAND_RPC_GET_TX_PROOF::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2256 if (!m_wallet)
return not_open(er);
2262 er.
message =
"TX ID has invalid format";
2270 er.
message =
"Invalid address";
2276 res.signature = m_wallet->get_tx_proof(txid,
info.address,
info.is_subaddress, req.message);
2278 catch (
const std::exception &e)
2287 bool wallet_rpc_server::on_check_tx_proof(
const wallet_rpc::COMMAND_RPC_CHECK_TX_PROOF::request& req, wallet_rpc::COMMAND_RPC_CHECK_TX_PROOF::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2289 if (!m_wallet)
return not_open(er);
2295 er.
message =
"TX ID has invalid format";
2303 er.
message =
"Invalid address";
2309 res.good = m_wallet->check_tx_proof(txid,
info.address,
info.is_subaddress, req.message, req.signature,
res.received,
res.in_pool,
res.confirmations);
2311 catch (
const std::exception &e)
2320 bool wallet_rpc_server::on_get_spend_proof(
const wallet_rpc::COMMAND_RPC_GET_SPEND_PROOF::request& req, wallet_rpc::COMMAND_RPC_GET_SPEND_PROOF::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2322 if (!m_wallet)
return not_open(er);
2328 er.
message =
"TX ID has invalid format";
2334 res.signature = m_wallet->get_spend_proof(txid, req.message);
2336 catch (
const std::exception &e)
2345 bool wallet_rpc_server::on_check_spend_proof(
const wallet_rpc::COMMAND_RPC_CHECK_SPEND_PROOF::request& req, wallet_rpc::COMMAND_RPC_CHECK_SPEND_PROOF::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2347 if (!m_wallet)
return not_open(er);
2353 er.
message =
"TX ID has invalid format";
2359 res.good = m_wallet->check_spend_proof(txid, req.message, req.signature);
2361 catch (
const std::exception &e)
2370 bool wallet_rpc_server::on_get_reserve_proof(
const wallet_rpc::COMMAND_RPC_GET_RESERVE_PROOF::request& req, wallet_rpc::COMMAND_RPC_GET_RESERVE_PROOF::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2372 if (!m_wallet)
return not_open(er);
2374 boost::optional<std::pair<uint32_t, uint64_t>> account_minreserve;
2377 if (req.account_index >= m_wallet->get_num_subaddress_accounts())
2380 er.
message =
"Account index is out of bound";
2383 account_minreserve = std::make_pair(req.account_index, req.amount);
2388 res.signature = m_wallet->get_reserve_proof(account_minreserve, req.message);
2390 catch (
const std::exception &e)
2399 bool wallet_rpc_server::on_check_reserve_proof(
const wallet_rpc::COMMAND_RPC_CHECK_RESERVE_PROOF::request& req, wallet_rpc::COMMAND_RPC_CHECK_RESERVE_PROOF::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2401 if (!m_wallet)
return not_open(er);
2407 er.
message =
"Invalid address";
2410 if (
info.is_subaddress)
2413 er.
message =
"Address must not be a subaddress";
2419 res.good = m_wallet->check_reserve_proof(
info.address, req.message, req.signature,
res.total,
res.spent);
2421 catch (
const std::exception &e)
2430 bool wallet_rpc_server::on_get_transfers(
const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2432 if (!m_wallet)
return not_open(er);
2436 er.
message =
"Command unavailable in restricted mode.";
2441 if (req.filter_by_height)
2443 min_height = req.min_height;
2444 max_height = req.max_height <= max_height ? req.max_height : max_height;
2447 boost::optional<uint32_t> account_index = req.account_index;
2448 std::set<uint32_t> subaddr_indices = req.subaddr_indices;
2449 if (req.all_accounts)
2451 account_index = boost::none;
2452 subaddr_indices.clear();
2457 std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
2458 m_wallet->get_payments(payments, min_height, max_height, account_index, subaddr_indices);
2459 for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
2460 res.in.push_back(wallet_rpc::transfer_entry());
2461 fill_transfer_entry(
res.in.back(), i->second.m_tx_hash, i->first, i->second);
2467 std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> payments;
2468 m_wallet->get_payments_out(payments, min_height, max_height, account_index, subaddr_indices);
2469 for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
2470 res.out.push_back(wallet_rpc::transfer_entry());
2471 fill_transfer_entry(
res.out.back(), i->first, i->second);
2477 std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> payments;
2478 m_wallet->get_payments_out_migration(payments, min_height, max_height, account_index, subaddr_indices);
2479 for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
2480 res.migration.push_back(wallet_rpc::transfer_entry());
2481 fill_transfer_entry(
res.migration.back(), i->first, i->second);
2485 if (req.sc_migration)
2487 std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> payments;
2488 m_wallet->get_payments_out_sc_migration(payments, min_height, max_height, account_index, subaddr_indices);
2489 for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
2490 res.sc_migration.push_back(wallet_rpc::transfer_entry());
2491 fill_transfer_entry(
res.sc_migration.back(), i->first, i->second);
2495 if (req.pending || req.failed) {
2496 std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>> upayments;
2497 m_wallet->get_unconfirmed_payments_out(upayments, account_index, subaddr_indices);
2498 for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
2501 if (!((req.failed && is_failed) || (!is_failed && req.pending)))
2503 std::list<wallet_rpc::transfer_entry> &entries = is_failed ?
res.failed :
res.pending;
2504 entries.push_back(wallet_rpc::transfer_entry());
2505 fill_transfer_entry(entries.back(), i->first, i->second);
2511 m_wallet->update_pool_state();
2513 std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> payments;
2514 m_wallet->get_unconfirmed_payments(payments, account_index, subaddr_indices);
2515 for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
2516 res.pool.push_back(wallet_rpc::transfer_entry());
2517 fill_transfer_entry(
res.pool.back(), i->first, i->second);
2524 bool wallet_rpc_server::on_get_transfer_by_txid(
const wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2526 if (!m_wallet)
return not_open(er);
2530 er.
message =
"Command unavailable in restricted mode.";
2539 er.
message =
"Transaction ID has invalid format";
2543 if(
sizeof(txid) == txid_blob.size())
2545 txid = *
reinterpret_cast<const crypto::hash*
>(txid_blob.data());
2550 er.
message =
"Transaction ID has invalid size: " + req.txid;
2554 if (req.account_index >= m_wallet->get_num_subaddress_accounts())
2557 er.
message =
"Account index is out of bound";
2561 std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
2562 m_wallet->get_payments(payments, 0, (
uint64_t)-1, req.account_index);
2563 for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
2564 if (i->second.m_tx_hash == txid)
2566 res.transfers.resize(
res.transfers.size() + 1);
2567 fill_transfer_entry(
res.transfers.back(), i->second.m_tx_hash, i->first, i->second);
2571 std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> payments_out;
2572 m_wallet->get_payments_out(payments_out, 0, (
uint64_t)-1, req.account_index);
2573 for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = payments_out.begin(); i != payments_out.end(); ++i) {
2574 if (i->first == txid)
2576 res.transfers.resize(
res.transfers.size() + 1);
2577 fill_transfer_entry(
res.transfers.back(), i->first, i->second);
2581 std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> migrations;
2582 m_wallet->get_payments_out_migration(migrations, 0, (
uint64_t)-1, req.account_index);
2583 for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = migrations.begin(); i != migrations.end(); ++i) {
2584 if (i->first == txid)
2586 res.transfers.resize(
res.transfers.size() + 1);
2587 fill_transfer_entry(
res.transfers.back(), i->first, i->second);
2591 std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> sc_migrations;
2592 m_wallet->get_payments_out_sc_migration(sc_migrations, 0, (
uint64_t)-1, req.account_index);
2593 for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = sc_migrations.begin(); i != sc_migrations.end(); ++i) {
2594 if (i->first == txid)
2596 res.transfers.resize(
res.transfers.size() + 1);
2597 fill_transfer_entry(
res.transfers.back(), i->first, i->second);
2601 std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>> upayments;
2602 m_wallet->get_unconfirmed_payments_out(upayments, req.account_index);
2603 for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
2604 if (i->first == txid)
2606 res.transfers.resize(
res.transfers.size() + 1);
2607 fill_transfer_entry(
res.transfers.back(), i->first, i->second);
2611 m_wallet->update_pool_state();
2613 std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> pool_payments;
2614 m_wallet->get_unconfirmed_payments(pool_payments, req.account_index);
2615 for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) {
2616 if (i->second.m_pd.m_tx_hash == txid)
2618 res.transfers.resize(
res.transfers.size() + 1);
2619 fill_transfer_entry(
res.transfers.back(), i->first, i->second);
2623 if (!
res.transfers.empty())
2625 res.transfer =
res.transfers.front();
2630 er.
message =
"Transaction not found.";
2634 bool wallet_rpc_server::on_export_outputs(
const wallet_rpc::COMMAND_RPC_EXPORT_OUTPUTS::request& req, wallet_rpc::COMMAND_RPC_EXPORT_OUTPUTS::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2636 if (!m_wallet)
return not_open(er);
2640 er.
message =
"Command unavailable in restricted mode.";
2643 if (m_wallet->key_on_device())
2646 er.
message =
"command not supported by HW wallet";
2654 catch (
const std::exception &e)
2663 bool wallet_rpc_server::on_import_outputs(
const wallet_rpc::COMMAND_RPC_IMPORT_OUTPUTS::request& req, wallet_rpc::COMMAND_RPC_IMPORT_OUTPUTS::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2665 if (!m_wallet)
return not_open(er);
2669 er.
message =
"Command unavailable in restricted mode.";
2672 if (m_wallet->key_on_device())
2675 er.
message =
"command not supported by HW wallet";
2683 er.
message =
"Failed to parse hex.";
2689 res.num_imported = m_wallet->import_outputs_from_str(blob);
2691 catch (
const std::exception &e)
2700 bool wallet_rpc_server::on_export_key_images(
const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2702 if (!m_wallet)
return not_open(er);
2705 std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images(req.all);
2706 res.offset = ski.first;
2707 res.signed_key_images.resize(ski.second.size());
2708 for (
size_t n = 0; n < ski.second.size(); ++n)
2715 catch (
const std::exception& e)
2724 bool wallet_rpc_server::on_import_key_images(
const wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2726 if (!m_wallet)
return not_open(er);
2730 er.
message =
"Command unavailable in restricted mode.";
2733 if (!m_wallet->is_trusted_daemon())
2736 er.
message =
"This command requires a trusted daemon.";
2741 std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
2742 ski.resize(req.signed_key_images.size());
2743 for (
size_t n = 0; n < ski.size(); ++n)
2748 er.
message =
"failed to parse key image";
2755 er.
message =
"failed to parse signature";
2760 uint64_t height = m_wallet->import_key_images(ski, req.offset, spent, unspent);
2762 res.unspent = unspent;
2766 catch (
const std::exception& e)
2775 bool wallet_rpc_server::on_make_uri(
const wallet_rpc::COMMAND_RPC_MAKE_URI::request& req, wallet_rpc::COMMAND_RPC_MAKE_URI::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2777 if (!m_wallet)
return not_open(er);
2779 std::string uri = m_wallet->make_uri(req.address, req.payment_id, req.amount, req.tx_description, req.recipient_name, error);
2783 er.
message = std::string(
"Cannot make URI from supplied parameters: ") +
error;
2791 bool wallet_rpc_server::on_parse_uri(
const wallet_rpc::COMMAND_RPC_PARSE_URI::request& req, wallet_rpc::COMMAND_RPC_PARSE_URI::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2793 if (!m_wallet)
return not_open(er);
2795 if (!m_wallet->parse_uri(req.uri,
res.uri.address,
res.uri.payment_id,
res.uri.amount,
res.uri.tx_description,
res.uri.recipient_name,
res.unknown_parameters, error))
2804 bool wallet_rpc_server::on_get_address_book(
const wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2806 if (!m_wallet)
return not_open(er);
2807 const auto ab = m_wallet->get_address_book();
2808 if (req.entries.empty())
2811 for (
const auto &entry: ab)
2818 if (idx >= ab.size())
2821 er.
message =
"Index out of range: " + std::to_string(idx);
2824 const auto &entry = ab[idx];
2831 bool wallet_rpc_server::on_add_address_book(
const wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2833 if (!m_wallet)
return not_open(er);
2837 er.
message =
"Command unavailable in restricted mode.";
2845 [&er](
const std::string &url,
const std::vector<std::string> &addresses,
bool dnssec_valid)->std::string {
2848 er.message = std::string(
"Invalid DNSSEC for ") + url;
2851 if (addresses.empty())
2853 er.message = std::string(
"No ETN address found at ") + url;
2856 return addresses[0];
2861 er.
message = std::string(
"WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + req.address;
2864 if (
info.has_payment_id)
2866 memcpy(payment_id.data,
info.payment_id.data, 8);
2867 memset(payment_id.data + 8, 0, 24);
2869 if (!req.payment_id.empty())
2871 if (
info.has_payment_id)
2874 er.
message =
"Separate payment ID given with integrated address";
2880 if (!wallet2::parse_long_payment_id(req.payment_id, payment_id))
2882 if (!wallet2::parse_short_payment_id(req.payment_id,
info.payment_id))
2885 er.
message =
"Payment id has invalid format: \"" + req.payment_id +
"\", expected 64 character string";
2891 er.
message =
"Payment id has invalid format: standalone short payment IDs are forbidden, they must be part of an integrated address";
2896 if (!m_wallet->add_address_book_row(
info.address, payment_id, req.description,
info.is_subaddress))
2899 er.
message =
"Failed to add address book entry";
2902 res.index = m_wallet->get_address_book().size() - 1;
2906 bool wallet_rpc_server::on_delete_address_book(
const wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2908 if (!m_wallet)
return not_open(er);
2912 er.
message =
"Command unavailable in restricted mode.";
2916 const auto ab = m_wallet->get_address_book();
2917 if (req.index >= ab.size())
2920 er.
message =
"Index out of range: " + std::to_string(req.index);
2923 if (!m_wallet->delete_address_book_row(req.index))
2926 er.
message =
"Failed to delete address book entry";
2932 bool wallet_rpc_server::on_refresh(
const wallet_rpc::COMMAND_RPC_REFRESH::request& req, wallet_rpc::COMMAND_RPC_REFRESH::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2934 if (!m_wallet)
return not_open(er);
2938 er.
message =
"Command unavailable in restricted mode.";
2943 m_wallet->refresh(m_wallet->is_trusted_daemon(), req.start_height,
res.blocks_fetched,
res.received_etn);
2946 catch (
const std::exception& e)
2954 bool wallet_rpc_server::on_auto_refresh(
const wallet_rpc::COMMAND_RPC_AUTO_REFRESH::request& req, wallet_rpc::COMMAND_RPC_AUTO_REFRESH::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2959 er.
message =
"Command unavailable in restricted mode.";
2965 MINFO(
"Auto refresh now " << (m_auto_refresh_period ? std::to_string(m_auto_refresh_period) +
" seconds" : std::string(
"disabled")));
2968 catch (
const std::exception& e)
2976 bool wallet_rpc_server::on_rescan_spent(
const wallet_rpc::COMMAND_RPC_RESCAN_SPENT::request& req, wallet_rpc::COMMAND_RPC_RESCAN_SPENT::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
2978 if (!m_wallet)
return not_open(er);
2982 er.
message =
"Command unavailable in restricted mode.";
2987 m_wallet->rescan_spent();
2990 catch (
const std::exception& e)
2998 bool wallet_rpc_server::on_start_mining(
const wallet_rpc::COMMAND_RPC_START_MINING::request& req, wallet_rpc::COMMAND_RPC_START_MINING::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3000 if (!m_wallet)
return not_open(er);
3001 if (!m_wallet->is_trusted_daemon())
3004 er.
message =
"This command requires a trusted daemon.";
3009 if (req.threads_count < 1 || max_mining_threads_count < req.threads_count)
3012 er.
message =
"The specified number of threads is inappropriate.";
3017 daemon_req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
3018 daemon_req.threads_count = req.threads_count;
3019 daemon_req.do_background_mining = req.do_background_mining;
3020 daemon_req.ignore_battery = req.ignore_battery;
3023 bool r = m_wallet->invoke_http_json(
"/start_mining", daemon_req, daemon_res);
3027 er.
message =
"Couldn't start mining due to unknown error.";
3033 bool wallet_rpc_server::on_stop_mining(
const wallet_rpc::COMMAND_RPC_STOP_MINING::request& req, wallet_rpc::COMMAND_RPC_STOP_MINING::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3035 if (!m_wallet)
return not_open(er);
3038 bool r = m_wallet->invoke_http_json(
"/stop_mining", daemon_req, daemon_res);
3042 er.
message =
"Couldn't stop mining due to unknown error.";
3048 bool wallet_rpc_server::on_get_languages(
const wallet_rpc::COMMAND_RPC_GET_LANGUAGES::request& req, wallet_rpc::COMMAND_RPC_GET_LANGUAGES::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3055 bool wallet_rpc_server::on_create_wallet(
const wallet_rpc::COMMAND_RPC_CREATE_WALLET::request& req, wallet_rpc::COMMAND_RPC_CREATE_WALLET::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3057 if (m_wallet_dir.empty())
3060 er.
message =
"No wallet dir configured";
3064 namespace po = boost::program_options;
3065 po::variables_map vm2;
3066 const char *ptr = strchr(req.filename.c_str(),
'/');
3069 ptr = strchr(req.filename.c_str(),
'\\');
3071 ptr = strchr(req.filename.c_str(),
':');
3076 er.
message =
"Invalid filename";
3079 std::string wallet_file = req.filename.empty() ?
"" : (m_wallet_dir +
"/" + req.filename);
3081 std::vector<std::string> languages;
3083 std::vector<std::string>::iterator it;
3085 it = std::find(languages.begin(), languages.end(), req.language);
3086 if (it == languages.end())
3089 it = std::find(languages.begin(), languages.end(), req.language);
3091 if (it == languages.end())
3094 er.
message =
"Unknown language: " + req.language;
3099 po::options_description desc(
"dummy");
3101 const char *argv[4];
3103 argv[0] =
"wallet-rpc";
3104 argv[1] =
"--password";
3105 argv[2] = req.password.c_str();
3109 po::store(po::parse_command_line(argc, argv, desc), vm2);
3115 er.
message =
"Failed to create wallet";
3118 wal->set_seed_language(req.language);
3122 bool r = wal->invoke_http_json(
"/getheight", hreq, hres);
3124 wal->set_refresh_from_block_height(hres.height);
3127 wal->generate(wallet_file, req.password, dummy_key,
false,
false);
3129 catch (
const std::exception& e)
3137 er.
message =
"Failed to generate wallet";
3147 catch (
const std::exception& e)
3154 m_wallet = wal.release();
3158 bool wallet_rpc_server::on_open_wallet(
const wallet_rpc::COMMAND_RPC_OPEN_WALLET::request& req, wallet_rpc::COMMAND_RPC_OPEN_WALLET::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3160 if (m_wallet_dir.empty())
3163 er.
message =
"No wallet dir configured";
3167 namespace po = boost::program_options;
3168 po::variables_map vm2;
3169 const char *ptr = strchr(req.filename.c_str(),
'/');
3172 ptr = strchr(req.filename.c_str(),
'\\');
3174 ptr = strchr(req.filename.c_str(),
':');
3179 er.
message =
"Invalid filename";
3182 if (m_wallet && req.autosave_current)
3188 catch (
const std::exception& e)
3194 std::string wallet_file = m_wallet_dir +
"/" + req.filename;
3196 po::options_description desc(
"dummy");
3198 const char *argv[4];
3200 argv[0] =
"wallet-rpc";
3201 argv[1] =
"--password";
3202 argv[2] = req.password.c_str();
3206 po::store(po::parse_command_line(argc, argv, desc), vm2);
3208 std::unique_ptr<tools::wallet2> wal =
nullptr;
3212 catch (
const std::exception& e)
3219 er.
message =
"Failed to open wallet";
3225 m_wallet = wal.release();
3229 bool wallet_rpc_server::on_close_wallet(
const wallet_rpc::COMMAND_RPC_CLOSE_WALLET::request& req, wallet_rpc::COMMAND_RPC_CLOSE_WALLET::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3231 if (!m_wallet)
return not_open(er);
3233 if (req.autosave_current)
3239 catch (
const std::exception& e)
3250 bool wallet_rpc_server::on_change_wallet_password(
const wallet_rpc::COMMAND_RPC_CHANGE_WALLET_PASSWORD::request& req, wallet_rpc::COMMAND_RPC_CHANGE_WALLET_PASSWORD::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3252 if (!m_wallet)
return not_open(er);
3256 er.
message =
"Command unavailable in restricted mode.";
3259 if (m_wallet->verify_password(req.old_password))
3263 m_wallet->change_password(m_wallet->get_wallet_file(), req.old_password, req.new_password);
3266 catch (
const std::exception& e)
3275 er.
message =
"Invalid original password.";
3281 void wallet_rpc_server::handle_rpc_exception(
const std::exception_ptr& e,
epee::json_rpc::error& er,
int default_error_code) {
3284 std::rethrow_exception(e);
3314 er.
message = (boost::format(
tr(
"Transaction not possible. Available only %s, transaction amount %s = %s + %s (fee)")) %
3324 er.
message = e.what() + std::string(
" Please use sweep_dust.");
3326 catch (
const error::file_exists& e)
3329 er.
message =
"Cannot create wallet. Already exists.";
3331 catch (
const error::invalid_password& e)
3334 er.
message =
"Invalid password.";
3336 catch (
const error::account_index_outofbound& e)
3341 catch (
const error::address_index_outofbound& e)
3346 catch (
const error::signature_check_failed& e)
3351 catch (
const std::exception& e)
3353 er.
code = default_error_code;
3359 er.
message =
"WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
3363 bool wallet_rpc_server::on_generate_from_keys(
const wallet_rpc::COMMAND_RPC_GENERATE_FROM_KEYS::request &req, wallet_rpc::COMMAND_RPC_GENERATE_FROM_KEYS::response &
res,
epee::json_rpc::error &er,
const connection_context *ctx)
3365 if (m_wallet_dir.empty())
3368 er.
message =
"No wallet dir configured";
3373 if (req.viewkey.empty())
3376 er.
message =
"field 'viewkey' is mandatory. Please provide a view key you want to restore from.";
3379 if (req.address.empty())
3382 er.
message =
"field 'address' is mandatory. Please provide a public address.";
3386 namespace po = boost::program_options;
3387 po::variables_map vm2;
3388 const char *ptr = strchr(req.filename.c_str(),
'/');
3391 ptr = strchr(req.filename.c_str(),
'\\');
3393 ptr = strchr(req.filename.c_str(),
':');
3398 er.
message =
"Invalid filename";
3401 std::string wallet_file = req.filename.empty() ?
"" : (m_wallet_dir +
"/" + req.filename);
3403 if (!wallet_file.empty())
3407 boost::system::error_code ignored_ec;
3410 catch (
const std::exception &e)
3413 er.
message =
"Wallet already exists.";
3419 po::options_description desc(
"dummy");
3421 const char *argv[4];
3423 argv[0] =
"wallet-rpc";
3424 argv[1] =
"--password";
3425 argv[2] = req.password.c_str();
3429 po::store(po::parse_command_line(argc, argv, desc), vm2);
3433 std::unique_ptr<wallet2> wal;
3434 wal = std::move(rc.first);
3438 er.
message =
"Failed to create wallet";
3446 er.
message =
"Failed to parse public address";
3456 er.
message =
"Failed to parse view key secret key";
3460 if (m_wallet && req.autosave_current)
3464 if (!wallet_file.empty())
3467 catch (
const std::exception &e)
3476 if (!req.spendkey.empty())
3483 er.
message =
"Failed to parse spend key secret key";
3486 wal->generate(wallet_file, std::move(rc.second).password(),
info.address,
spendkey, viewkey,
false);
3487 res.info =
"Wallet has been generated successfully.";
3491 wal->generate(wallet_file, std::move(rc.second).password(),
info.address, viewkey,
false);
3492 res.info =
"Watch-only wallet has been generated successfully.";
3494 MINFO(
"Wallet has been generated.\n");
3496 catch (
const std::exception &e)
3505 er.
message =
"Failed to generate wallet";
3512 wal->set_refresh_from_block_height(req.restore_height);
3513 wal->rewrite(wallet_file, password);
3515 catch (
const std::exception &e)
3523 m_wallet = wal.release();
3524 res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
3528 bool wallet_rpc_server::on_restore_deterministic_wallet(
const wallet_rpc::COMMAND_RPC_RESTORE_DETERMINISTIC_WALLET::request &req, wallet_rpc::COMMAND_RPC_RESTORE_DETERMINISTIC_WALLET::response &
res,
epee::json_rpc::error &er,
const connection_context *ctx)
3530 if (m_wallet_dir.empty())
3533 er.
message =
"No wallet dir configured";
3538 if (req.seed.empty())
3541 er.
message =
"field 'seed' is mandatory. Please provide a seed you want to restore from.";
3545 namespace po = boost::program_options;
3546 po::variables_map vm2;
3547 const char *ptr = strchr(req.filename.c_str(),
'/');
3550 ptr = strchr(req.filename.c_str(),
'\\');
3552 ptr = strchr(req.filename.c_str(),
':');
3557 er.
message =
"Invalid filename";
3560 std::string wallet_file = req.filename.empty() ?
"" : (m_wallet_dir +
"/" + req.filename);
3562 if (!wallet_file.empty())
3566 boost::system::error_code ignored_ec;
3569 catch (
const std::exception &e)
3572 er.
message =
"Wallet already exists.";
3577 std::string old_language;
3584 er.
message =
"Electrum-style word list failed verification";
3588 if (m_wallet && req.autosave_current)
3594 catch (
const std::exception &e)
3603 if (!req.seed_offset.empty())
3609 po::options_description desc(
"dummy");
3611 const char *argv[4];
3613 argv[0] =
"wallet-rpc";
3614 argv[1] =
"--password";
3615 argv[2] = req.password.c_str();
3619 po::store(po::parse_command_line(argc, argv, desc), vm2);
3623 std::unique_ptr<wallet2> wal;
3624 wal = std::move(rc.first);
3628 er.
message =
"Failed to create wallet";
3637 std::string mnemonic_language = old_language;
3638 if (was_deprecated_wallet)
3641 res.was_deprecated =
true;
3646 if (req.language.empty())
3649 er.
message =
"Wallet was using the old seed language. You need to specify a new seed language.";
3652 std::vector<std::string> language_list;
3653 std::vector<std::string> language_list_en;
3656 if (std::find(language_list.begin(), language_list.end(), req.language) == language_list.end() &&
3657 std::find(language_list_en.begin(), language_list_en.end(), req.language) == language_list_en.end())
3660 er.
message =
"Wallet was using the old seed language, and the specified new seed language is invalid.";
3663 mnemonic_language = req.language;
3666 wal->set_seed_language(mnemonic_language);
3671 recovery_val = wal->generate(wallet_file, std::move(rc.second).password(), recovery_key,
true,
false,
false);
3672 MINFO(
"Wallet has been restored.\n");
3674 catch (
const std::exception &e)
3685 er.
message =
"Failed to encode seed";
3688 res.seed = std::string(electrum_words.
data(), electrum_words.
size());
3693 er.
message =
"Failed to generate wallet";
3700 wal->set_refresh_from_block_height(req.restore_height);
3701 wal->rewrite(wallet_file, password);
3703 catch (
const std::exception &e)
3711 m_wallet = wal.release();
3712 res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
3713 res.info =
"Wallet has been restored successfully.";
3717 bool wallet_rpc_server::on_is_multisig(
const wallet_rpc::COMMAND_RPC_IS_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_IS_MULTISIG::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3719 if (!m_wallet)
return not_open(er);
3720 res.multisig = m_wallet->multisig(&
res.ready, &
res.threshold, &
res.total);
3724 bool wallet_rpc_server::on_prepare_multisig(
const wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3726 if (!m_wallet)
return not_open(er);
3730 er.
message =
"Command unavailable in restricted mode.";
3733 if (m_wallet->multisig())
3736 er.
message =
"This wallet is already multisig";
3739 if (m_wallet->watch_only())
3742 er.
message =
"wallet is watch-only and cannot be made multisig";
3746 res.multisig_info = m_wallet->get_multisig_info();
3750 bool wallet_rpc_server::on_make_multisig(
const wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3752 if (!m_wallet)
return not_open(er);
3756 er.
message =
"Command unavailable in restricted mode.";
3759 if (m_wallet->multisig())
3762 er.
message =
"This wallet is already multisig";
3765 if (m_wallet->watch_only())
3768 er.
message =
"wallet is watch-only and cannot be made multisig";
3774 res.multisig_info = m_wallet->make_multisig(req.password, req.multisig_info, req.threshold);
3775 res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
3777 catch (
const std::exception &e)
3787 bool wallet_rpc_server::on_export_multisig(
const wallet_rpc::COMMAND_RPC_EXPORT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_EXPORT_MULTISIG::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3789 if (!m_wallet)
return not_open(er);
3793 er.
message =
"Command unavailable in restricted mode.";
3797 if (!m_wallet->multisig(&ready))
3800 er.
message =
"This wallet is not multisig";
3806 er.
message =
"This wallet is multisig, but not yet finalized";
3813 info = m_wallet->export_multisig();
3815 catch (
const std::exception &e)
3827 bool wallet_rpc_server::on_import_multisig(
const wallet_rpc::COMMAND_RPC_IMPORT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_IMPORT_MULTISIG::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3829 if (!m_wallet)
return not_open(er);
3833 er.
message =
"Command unavailable in restricted mode.";
3838 if (!m_wallet->multisig(&ready, &
threshold, &total))
3841 er.
message =
"This wallet is not multisig";
3847 er.
message =
"This wallet is multisig, but not yet finalized";
3854 er.
message =
"Needs multisig export info from more participants";
3858 std::vector<cryptonote::blobdata>
info;
3859 info.resize(req.info.size());
3860 for (
size_t n = 0; n <
info.size(); ++n)
3865 er.
message =
"Failed to parse hex.";
3872 res.n_outputs = m_wallet->import_multisig(
info);
3874 catch (
const std::exception &e)
3877 er.
message =
"Error calling import_multisig";
3881 if (m_wallet->is_trusted_daemon())
3885 m_wallet->rescan_spent();
3887 catch (
const std::exception &e)
3889 er.
message = std::string(
"Success, but failed to update spent status after import multisig info: ") + e.what();
3894 er.
message =
"Success, but cannot update spent status after import multisig info as daemon is untrusted";
3900 bool wallet_rpc_server::on_finalize_multisig(
const wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3902 if (!m_wallet)
return not_open(er);
3906 er.
message =
"Command unavailable in restricted mode.";
3911 if (!m_wallet->multisig(&ready, &
threshold, &total))
3914 er.
message =
"This wallet is not multisig";
3920 er.
message =
"This wallet is multisig, and already finalized";
3924 if (req.multisig_info.size() < 1 || req.multisig_info.size() > total)
3927 er.
message =
"Needs multisig info from more participants";
3933 if (!m_wallet->finalize_multisig(req.password, req.multisig_info))
3936 er.
message =
"Error calling finalize_multisig";
3940 catch (
const std::exception &e)
3943 er.
message = std::string(
"Error calling finalize_multisig: ") + e.what();
3946 res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
3951 bool wallet_rpc_server::on_exchange_multisig_keys(
const wallet_rpc::COMMAND_RPC_EXCHANGE_MULTISIG_KEYS::request& req, wallet_rpc::COMMAND_RPC_EXCHANGE_MULTISIG_KEYS::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
3953 if (!m_wallet)
return not_open(er);
3957 er.
message =
"Command unavailable in restricted mode.";
3962 if (!m_wallet->multisig(&ready, &
threshold, &total))
3965 er.
message =
"This wallet is not multisig";
3972 er.
message =
"This wallet is multisig, and already finalized";
3976 if (req.multisig_info.size() < 1 || req.multisig_info.size() > total)
3979 er.
message =
"Needs multisig info from more participants";
3985 res.multisig_info = m_wallet->exchange_multisig_keys(req.password, req.multisig_info);
3986 if (
res.multisig_info.empty())
3988 res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
3991 catch (
const std::exception &e)
3994 er.
message = std::string(
"Error calling exchange_multisig_info: ") + e.what();
4000 bool wallet_rpc_server::on_sign_multisig(
const wallet_rpc::COMMAND_RPC_SIGN_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_SIGN_MULTISIG::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
4002 if (!m_wallet)
return not_open(er);
4006 er.
message =
"Command unavailable in restricted mode.";
4011 if (!m_wallet->multisig(&ready, &
threshold, &total))
4014 er.
message =
"This wallet is not multisig";
4020 er.
message =
"This wallet is multisig, but not yet finalized";
4028 er.
message =
"Failed to parse hex.";
4033 bool r = m_wallet->load_multisig_tx(blob, txs, NULL);
4037 er.
message =
"Failed to parse multisig tx data.";
4041 std::vector<crypto::hash> txids;
4044 bool r = m_wallet->sign_multisig_tx(txs, txids);
4048 er.
message =
"Failed to sign multisig tx";
4052 catch (
const std::exception &e)
4055 er.
message = std::string(
"Failed to sign multisig tx: ") + e.what();
4069 bool wallet_rpc_server::on_submit_multisig(
const wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
4071 if (!m_wallet)
return not_open(er);
4075 er.
message =
"Command unavailable in restricted mode.";
4080 if (!m_wallet->multisig(&ready, &
threshold, &total))
4083 er.
message =
"This wallet is not multisig";
4089 er.
message =
"This wallet is multisig, but not yet finalized";
4097 er.
message =
"Failed to parse hex.";
4102 bool r = m_wallet->load_multisig_tx(blob, txs, NULL);
4106 er.
message =
"Failed to parse multisig tx data.";
4113 er.
message =
"Not enough signers signed this transaction.";
4119 for (
auto &ptx: txs.
m_ptx)
4121 m_wallet->commit_tx(ptx);
4125 catch (
const std::exception &e)
4128 er.
message = std::string(
"Failed to submit multisig tx: ") + e.what();
4135 bool wallet_rpc_server::on_validate_address(
const wallet_rpc::COMMAND_RPC_VALIDATE_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_VALIDATE_ADDRESS::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
4143 if (!req.any_net_type && !m_wallet)
return not_open(er);
4144 for (
const auto &net_type: net_types)
4146 if (!req.any_net_type && (!m_wallet || net_type.type != m_wallet->nettype()))
4148 if (req.allow_openalias)
4152 [&er, &
address](
const std::string &url,
const std::vector<std::string> &addresses,
bool dnssec_valid)->std::string {
4155 er.message = std::string(
"Invalid DNSSEC for ") + url;
4158 if (addresses.empty())
4160 er.message = std::string(
"No ETN address found at ") + url;
4175 res.integrated =
info.has_payment_id;
4176 res.subaddress =
info.is_subaddress;
4177 res.nettype = net_type.stype;
4183 er.
message = std::string(
"Invalid address");
4187 bool wallet_rpc_server::on_set_daemon(
const wallet_rpc::COMMAND_RPC_SET_DAEMON::request& req, wallet_rpc::COMMAND_RPC_SET_DAEMON::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
4189 if (!m_wallet)
return not_open(er);
4193 er.
message =
"Command unavailable in restricted mode.";
4197 std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints;
4198 ssl_allowed_fingerprints.reserve(req.ssl_allowed_fingerprints.size());
4199 for (
const std::string &fp: req.ssl_allowed_fingerprints)
4201 ssl_allowed_fingerprints.push_back({});
4202 std::vector<uint8_t> &v = ssl_allowed_fingerprints.back();
4208 if (req.ssl_allow_any_cert)
4210 else if (!ssl_allowed_fingerprints.empty() || !req.ssl_ca_file.empty())
4216 er.
message = std::string(
"Invalid ssl support mode");
4221 std::move(req.ssl_private_key_path), std::move(req.ssl_certificate_path)
4224 const bool verification_required =
4231 er.
message =
"SSL is enabled but no user certificate or fingerprints were provided";
4235 if (!m_wallet->set_daemon(req.address, boost::none, req.trusted, std::move(ssl_options)))
4238 er.
message = std::string(
"Unable to set daemon");
4244 bool wallet_rpc_server::on_set_log_level(
const wallet_rpc::COMMAND_RPC_SET_LOG_LEVEL::request& req, wallet_rpc::COMMAND_RPC_SET_LOG_LEVEL::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
4249 er.
message =
"Command unavailable in restricted mode.";
4253 if (req.level < 0 || req.level > 4)
4256 er.
message =
"Error: log level not valid";
4263 bool wallet_rpc_server::on_set_log_categories(
const wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES::request& req, wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
4268 er.
message =
"Command unavailable in restricted mode.";
4277 bool wallet_rpc_server::on_get_version(
const wallet_rpc::COMMAND_RPC_GET_VERSION::request& req, wallet_rpc::COMMAND_RPC_GET_VERSION::response&
res,
epee::json_rpc::error& er,
const connection_context *ctx)
4288 const boost::program_options::variables_map& vm;
4290 std::unique_ptr<tools::wallet_rpc_server> wrpc;
4293 t_daemon(boost::program_options::variables_map
const & _vm)
4295 , wrpc(new
tools::wallet_rpc_server)
4301 std::unique_ptr<tools::wallet2> wal;
4306 if (testnet && stagenet)
4319 const auto password_prompt = prompt_for_password ? password_prompter :
nullptr;
4321 if(!wallet_file.empty() && !from_json.empty())
4327 if (!wallet_dir.empty())
4333 if (wallet_file.empty() && from_json.empty())
4340 if(!wallet_file.empty())
4349 wal = std::move(rc.first);
4351 catch (
const std::exception &e)
4353 MERROR(
"Error creating wallet: " << e.what());
4369 wal->refresh(wal->is_trusted_daemon());
4380 catch (
const std::exception& e)
4386 if (wal) wrpc->set_wallet(wal.release());
4387 bool r = wrpc->init(&vm);
4390 wrpc->send_stop_signal();
4397 catch (
const std::exception &e)
4409 catch (
const std::exception& e)
4419 wrpc->send_stop_signal();
4456 namespace po = boost::program_options;
4461 po::options_description hidden_options(
"Hidden");
4463 po::options_description desc_params(
wallet_args::tr(
"Wallet options"));
4475 desc_params.add(hidden_options);
4477 boost::optional<po::variables_map> vm;
4478 bool should_terminate =
false;
4481 "electroneum-wallet-rpc [--wallet-file=<file>|--generate-from-json=<file>|--wallet-dir=<directory>] [--rpc-bind-port=<port>]",
4484 po::positional_options_description(),
4486 "electroneum-wallet-rpc.log",
4493 if (should_terminate)
bool run(size_t threads_count, bool wait=true)
bool init(std::function< void(size_t, uint8_t *)> rng, const std::string &bind_port="0", const std::string &bind_ip="0.0.0.0", std::vector< std::string > access_control_origins=std::vector< std::string >(), boost::optional< net_utils::http::login > user=boost::none, net_utils::ssl_options_t ssl_options=net_utils::ssl_support_t::e_ssl_support_autodetect)
net_utils::boosted_tcp_server< net_utils::http::http_custom_handler< epee::net_utils::connection_context_base > > m_net_server
ssl_verification_t verification
bool has_strong_verification(boost::string_ref host) const noexcept
\retrurn True if host can be verified using this configuration WITHOUT system "root" CAs.
ssl_authentication_t auth
bool hex_to_pod(T &pod) const
const char * data() const noexcept
size_t size() const noexcept
t_daemon(boost::program_options::variables_map const &_vm)
static std::string const NAME
std::string const & name() const
bool run_interactive(boost::program_options::variables_map const &vm)
bool run_non_interactive(boost::program_options::variables_map const &vm)
t_daemon create_daemon(boost::program_options::variables_map const &vm)
#define CORE_RPC_STATUS_OK
#define CRYPTONOTE_MAX_BLOCK_NUMBER
Mnemonic seed generation and wallet restoration from them.
void * memcpy(void *a, const void *b, size_t c)
const char * i18n_translate(const char *s, const std::string &context)
std::string mlog_get_categories()
void mlog_set_log(const char *log)
void mlog_set_log_level(int level)
#define CATCH_ENTRY_L0(lacation, return_val)
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
bool is_arg_defaulted(const boost::program_options::variables_map &vm, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg)
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
std::vector< const Language::Base * > get_language_list()
bool words_to_bytes(const epee::wipeable_string &words, epee::wipeable_string &dst, size_t len, bool duplicate, std::string &language_name)
Converts seed words to bytes (secret key).
bool get_is_old_style_seed(const epee::wipeable_string &seed)
Tells if the seed passed is an old style seed or not.
const std::string old_language_name
bool bytes_to_words(const char *src, size_t len, epee::wipeable_string &words, const std::string &language_name)
Converts bytes (secret key) to seed words.
std::enable_if< std::is_pod< T >::value, T >::type rand()
epee::mlocked< tools::scrubbed< ec_scalar > > secret_key
bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata &extra_nonce, crypto::hash8 &payment_id)
bool get_payment_id_from_tx_extra_nonce(const blobdata &extra_nonce, crypto::hash &payment_id)
void set_payment_id_to_tx_extra_nonce(blobdata &extra_nonce, const crypto::hash &payment_id)
bool get_account_address_from_str(address_parse_info &info, network_type nettype, std::string const &str)
std::string get_account_address_as_str(network_type nettype, bool subaddress, account_public_address const &adr)
crypto::hash get_transaction_hash(const transaction &t)
bool find_tx_extra_field_by_type(const std::vector< tx_extra_field > &tx_extra_fields, T &field, size_t index=0)
crypto::secret_key decrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase)
blobdata tx_to_blob(const transaction &tx)
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
bool get_account_address_from_str_or_url(address_parse_info &info, network_type nettype, const std::string &str_or_url, std::function< std::string(const std::string &, const std::vector< std::string > &, bool)> dns_confirm)
std::string get_account_integrated_address_as_str(network_type nettype, account_public_address const &adr, crypto::hash8 const &payment_id)
bool add_extra_nonce_to_tx_extra(std::vector< uint8_t > &tx_extra, const blobdata &extra_nonce)
bool daemonize(int argc, char const *argv[], T_executor &&executor, boost::program_options::variables_map const &vm)
void init_options(boost::program_options::options_description &hidden_options, boost::program_options::options_description &normal_options)
@ none
Do not verify peer.
bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s)
std::string base64_encode(unsigned char const *bytes_to_encode, size_t in_len)
void set_console_color(int color, bool bright)
void reset_console_color()
T & unwrap(mlocked< T > &src)
error
Tracks LMDB error codes.
const char * tr(const char *str)
std::pair< boost::optional< boost::program_options::variables_map >, bool > main(int argc, char **argv, const char *const usage, const char *const notice, boost::program_options::options_description desc_params, const boost::program_options::positional_options_description &positional_options, const std::function< void(const std::string &, bool)> &print, const char *default_log_name, bool log_to_console)
command_line::arg_descriptor< std::string > arg_generate_from_json()
command_line::arg_descriptor< std::string > arg_wallet_file()
CXA_THROW_INFO_T void(* dest)(void *))
unsigned __int64 uint64_t
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
const command_line::arg_descriptor< std::string > rpc_login
static boost::optional< rpc_args > process(const boost::program_options::variables_map &vm, const bool any_cert_option=false)
static void init_options(boost::program_options::options_description &desc, const bool any_cert_option=false)
account_public_address addr
static epee::wipeable_string wipeable_string(const span< const std::uint8_t > src)
static std::string string(const span< const std::uint8_t > src)
bool nonexistent_utxo_seen
cryptonote::subaddress_index subaddr_index
uint64_t suggested_confirmations_threshold
std::list< transfer_destination > destinations
std::vector< cryptonote::subaddress_index > subaddr_indices
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)
#define MKDIR(path, mode)
#define DEFAULT_AUTO_REFRESH_PERIOD
#define WALLET_RPC_VERSION
#define WALLET_RPC_ERROR_CODE_NON_DETERMINISTIC
#define WALLET_RPC_ERROR_CODE_TX_TOO_LARGE
#define WALLET_RPC_ERROR_CODE_BAD_HEX
#define WALLET_RPC_ERROR_CODE_SIGNED_SUBMISSION
#define WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE
#define WALLET_RPC_ERROR_CODE_TRANSFER_TYPE
#define WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED
#define WALLET_RPC_ERROR_CODE_WATCH_ONLY
#define WALLET_RPC_ERROR_CODE_BAD_TX_METADATA
#define WALLET_RPC_ERROR_CODE_INVALID_PASSWORD
#define WALLET_RPC_ERROR_CODE_WALLET_ALREADY_EXISTS
#define WALLET_RPC_ERROR_CODE_MULTISIG_SIGNATURE
#define WALLET_RPC_ERROR_CODE_WRONG_INDEX
#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_ETN
#define WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID
#define WALLET_RPC_ERROR_CODE_NO_TXKEY
#define WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION
#define WALLET_RPC_ERROR_CODE_NOT_MULTISIG
#define WALLET_RPC_ERROR_CODE_ZERO_DESTINATION
#define WALLET_RPC_ERROR_CODE_NOT_OPEN
#define WALLET_RPC_ERROR_CODE_INVALID_LOG_LEVEL
#define WALLET_RPC_ERROR_CODE_WRONG_TXID
#define WALLET_RPC_ERROR_CODE_WRONG_KEY
#define WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE
#define WALLET_RPC_ERROR_CODE_WRONG_ADDRESS
#define WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUT_OF_BOUNDS
#define WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA
#define WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY
#define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR
#define WALLET_RPC_ERROR_CODE_NO_WALLET_DIR
#define WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA
#define WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUT_OF_BOUNDS
#define WALLET_RPC_ERROR_CODE_DENIED
#define WALLET_RPC_ERROR_CODE_SIGN_UNSIGNED
#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_ETN
#define WALLET_RPC_ERROR_CODE_WRONG_SIGNATURE
#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_OUTS_TO_MIX
#define WALLET_RPC_ERROR_CODE_ALREADY_MULTISIG
#define WALLET_RPC_ERROR_CODE_BAD_SIGNED_TX_DATA
#define WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR
#define WALLET_RPC_ERROR_CODE_WRONG_URI
#define WALLET_RPC_ERROR_CODE_MULTISIG_SUBMISSION