aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet/simplewallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplewallet/simplewallet.cpp')
-rw-r--r--src/simplewallet/simplewallet.cpp154
1 files changed, 142 insertions, 12 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index f4f24ed77..2ab714aff 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -122,7 +122,7 @@ namespace
const command_line::arg_descriptor<std::string> arg_electrum_seed = {"electrum-seed", sw::tr("Specify Electrum seed for wallet recovery/creation"), ""};
const command_line::arg_descriptor<bool> arg_restore_deterministic_wallet = {"restore-deterministic-wallet", sw::tr("Recover wallet using Electrum-style mnemonic seed"), false};
const command_line::arg_descriptor<bool> arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false};
- const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Create non-deterministic view and spend keys"), false};
+ const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false};
const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false};
const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
@@ -1690,6 +1690,16 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::check_spend_proof, this, _1),
tr("check_spend_proof <txid> <signature_file> [<message>]"),
tr("Check a signature proving that the signer generated <txid>, optionally with a challenge string <message>."));
+ m_cmd_binder.set_handler("get_reserve_proof",
+ boost::bind(&simple_wallet::get_reserve_proof, this, _1),
+ tr("get_reserve_proof (all|<amount>) [<message>]"),
+ tr("Generate a signature proving that you own at least this much, optionally with a challenge string <message>.\n"
+ "If 'all' is specified, you prove the entire sum of all of your existing accounts' balances.\n"
+ "Otherwise, you prove the reserve of the smallest possible amount above <amount> available in your current account."));
+ m_cmd_binder.set_handler("check_reserve_proof",
+ boost::bind(&simple_wallet::check_reserve_proof, this, _1),
+ tr("check_reserve_proof <address> <signature_file> [<message>]"),
+ tr("Check a signature proving that the owner of <address> holds at least this much, optionally with a challenge string <message>."));
m_cmd_binder.set_handler("show_transfers",
boost::bind(&simple_wallet::show_transfers, this, _1),
tr("show_transfers [in|out|pending|failed|pool] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]"),
@@ -1770,11 +1780,11 @@ simple_wallet::simple_wallet()
tr("Turn this wallet into a multisig wallet, extra step for N-1/N wallets"));
m_cmd_binder.set_handler("export_multisig_info",
boost::bind(&simple_wallet::export_multisig, this, _1),
- tr("export_multisig <filename>"),
+ tr("export_multisig_info <filename>"),
tr("Export multisig info for other participants"));
m_cmd_binder.set_handler("import_multisig_info",
boost::bind(&simple_wallet::import_multisig, this, _1),
- tr("import_multisig <filename> [<filename>...]"),
+ tr("import_multisig_info <filename> [<filename>...]"),
tr("Import multisig info from other participants"));
m_cmd_binder.set_handler("sign_multisig",
boost::bind(&simple_wallet::sign_multisig, this, _1),
@@ -1786,7 +1796,7 @@ simple_wallet::simple_wallet()
tr("Submit a signed multisig transaction from a file"));
m_cmd_binder.set_handler("export_raw_multisig_tx",
boost::bind(&simple_wallet::export_raw_multisig, this, _1),
- tr("export_raw_multisig <filename>"),
+ tr("export_raw_multisig_tx <filename>"),
tr("Export a signed multisig transaction to a file"));
m_cmd_binder.set_handler("help",
boost::bind(&simple_wallet::help, this, _1),
@@ -3307,6 +3317,13 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
{
if (!parse_subaddress_indices(local_args[0], subaddr_indices))
return true;
+ local_args.erase(local_args.begin());
+ }
+
+ if (local_args.size() > 0)
+ {
+ fail_msg_writer() << tr("usage: incoming_transfers [available|unavailable] [verbose] [index=<N>]");
+ return true;
}
tools::wallet2::transfer_container transfers;
@@ -3825,7 +3842,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
else
{
if (nblocks[0].first > m_wallet->get_confirm_backlog_threshold())
- prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No)")) % nblocks[0].first).str();
+ prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No): ")) % nblocks[0].first).str();
}
}
catch (const std::exception &e)
@@ -4243,7 +4260,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
print_money(total_fee);
}
else {
- prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No)")) %
+ prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
print_money(total_sent) %
print_money(total_fee);
}
@@ -4448,7 +4465,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
std::ostringstream prompt;
if (!print_ring_members(ptx_vector, prompt))
return true;
- prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No)")) %
+ prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
print_money(total_sent) %
print_money(total_fee);
std::string accepted = input_line(prompt.str());
@@ -4528,14 +4545,18 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::donate(const std::vector<std::string> &args_)
{
+ if(m_wallet->testnet())
+ {
+ fail_msg_writer() << tr("donations are not enabled on the testnet");
+ return true;
+ }
+
std::vector<std::string> local_args = args_;
if(local_args.empty() || local_args.size() > 5)
{
fail_msg_writer() << tr("usage: donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>]");
return true;
}
- // Hardcode Monero's donation address (see #1447)
- const std::string address_str = "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A";
std::string amount_str;
std::string payment_id_str;
// get payment id and pop
@@ -4551,11 +4572,11 @@ bool simple_wallet::donate(const std::vector<std::string> &args_)
amount_str = local_args.back();
local_args.pop_back();
// push back address, amount, payment id
- local_args.push_back(address_str);
+ local_args.push_back(MONERO_DONATION_ADDR);
local_args.push_back(amount_str);
if (!payment_id_str.empty())
local_args.push_back(payment_id_str);
- message_writer() << tr("Donating ") << amount_str << " to The Monero Project (donate.getmonero.org/44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A).";
+ message_writer() << tr("Donating ") << amount_str << " to The Monero Project (donate.getmonero.org/"<< MONERO_DONATION_ADDR <<").";
transfer_new(local_args);
return true;
}
@@ -5112,6 +5133,110 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
+{
+ if(args.size() != 1 && args.size() != 2) {
+ fail_msg_writer() << tr("usage: get_reserve_proof (all|<amount>) [<message>]");
+ return true;
+ }
+
+ if (m_wallet->watch_only() || m_wallet->multisig())
+ {
+ fail_msg_writer() << tr("The reserve proof can be generated only by a full wallet");
+ return true;
+ }
+
+ boost::optional<std::pair<uint32_t, uint64_t>> account_minreserve;
+ if (args[0] != "all")
+ {
+ account_minreserve = std::pair<uint32_t, uint64_t>();
+ account_minreserve->first = m_current_subaddress_account;
+ if (!cryptonote::parse_amount(account_minreserve->second, args[0]))
+ {
+ fail_msg_writer() << tr("amount is wrong: ") << args[0];
+ return true;
+ }
+ }
+
+ if (!try_connect_to_daemon())
+ {
+ fail_msg_writer() << tr("failed to connect to the daemon");
+ return true;
+ }
+
+ if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ LOCK_IDLE_SCOPE();
+
+ try
+ {
+ const std::string sig_str = m_wallet->get_reserve_proof(account_minreserve, args.size() == 2 ? args[1] : "");
+ const std::string filename = "monero_reserve_proof";
+ if (epee::file_io_utils::save_string_to_file(filename, sig_str))
+ success_msg_writer() << tr("signature file saved to: ") << filename;
+ else
+ fail_msg_writer() << tr("failed to save signature file");
+ }
+ catch (const std::exception &e)
+ {
+ fail_msg_writer() << e.what();
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::check_reserve_proof(const std::vector<std::string> &args)
+{
+ if(args.size() != 2 && args.size() != 3) {
+ fail_msg_writer() << tr("usage: check_reserve_proof <address> <signature_file> [<message>]");
+ return true;
+ }
+
+ if (!try_connect_to_daemon())
+ {
+ fail_msg_writer() << tr("failed to connect to the daemon");
+ return true;
+ }
+
+ cryptonote::address_parse_info info;
+ if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), args[0], oa_prompter))
+ {
+ fail_msg_writer() << tr("failed to parse address");
+ return true;
+ }
+ if (info.is_subaddress)
+ {
+ fail_msg_writer() << tr("Address must not be a subaddress");
+ return true;
+ }
+
+ std::string sig_str;
+ if (!epee::file_io_utils::load_file_to_string(args[1], sig_str))
+ {
+ fail_msg_writer() << tr("failed to load signature file");
+ return true;
+ }
+
+ LOCK_IDLE_SCOPE();
+
+ try
+ {
+ uint64_t total, spent;
+ if (m_wallet->check_reserve_proof(info.address, args.size() == 3 ? args[2] : "", sig_str, total, spent))
+ {
+ success_msg_writer() << boost::format(tr("Good signature -- total: %s, spent: %s, unspent: %s")) % print_money(total) % print_money(spent) % print_money(total - spent);
+ }
+ else
+ {
+ fail_msg_writer() << tr("Bad signature");
+ }
+ }
+ catch (const std::exception& e)
+ {
+ fail_msg_writer() << e.what();
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
static std::string get_human_readable_timestamp(uint64_t ts)
{
char buffer[64];
@@ -6195,6 +6320,7 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args)
try
{
+ LOCK_IDLE_SCOPE();
if (!m_wallet->export_key_images(filename))
{
fail_msg_writer() << tr("failed to save file ") << filename;
@@ -6227,6 +6353,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
}
std::string filename = args[0];
+ LOCK_IDLE_SCOPE();
try
{
uint64_t spent = 0, unspent = 0;
@@ -6258,6 +6385,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args)
if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
std::string filename = args[0];
+ LOCK_IDLE_SCOPE();
try
{
std::vector<tools::wallet2::transfer_details> outs = m_wallet->export_outputs();
@@ -6356,6 +6484,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
boost::archive::binary_iarchive ar(iss);
ar >> outputs;
}
+ LOCK_IDLE_SCOPE();
size_t n_outputs = m_wallet->import_outputs(outputs);
success_msg_writer() << boost::lexical_cast<std::string>(n_outputs) << " outputs imported";
}
@@ -6607,7 +6736,8 @@ int main(int argc, char* argv[])
std::vector<std::string> command = command_line::get_arg(*vm, arg_command);
if (!command.empty())
{
- w.process_command(command);
+ if (!w.process_command(command))
+ fail_msg_writer() << tr("Unknown command: ") << command.front();
w.stop();
w.deinit();
}