From 7d020bde5e0ef9d680c51a32b554cec6c29a4302 Mon Sep 17 00:00:00 2001 From: Oyvind Kvanes Date: Wed, 28 Sep 2016 16:27:45 +0200 Subject: [PATCH] Add locked_transfer --- src/simplewallet/simplewallet.cpp | 172 +++++++++++++++--------------- 1 file changed, 84 insertions(+), 88 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index d7218545..3fe9b909 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -652,7 +652,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), tr("Show blockchain height")); m_cmd_binder.set_handler("transfer_original", boost::bind(&simple_wallet::transfer, this, _1), tr("transfer [] [ ... ] [payment_id] - Transfer ,... to ,... , respectively. is the number of extra inputs to include for untraceability (from 0 to maximum available)")); m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer_new, this, _1), tr("Same as transfer_original, but using a new transaction building algorithm")); - m_cmd_binder.set_handler("locked_transfer", boost::bind(&simple_wallet::locked_transfer, this, _1), tr("Make a transfer using unlock_time")); + m_cmd_binder.set_handler("locked_transfer", boost::bind(&simple_wallet::locked_transfer, this, _1), tr("transfer [] (Number of blocks to lock the transaction for) [payment_id]")); m_cmd_binder.set_handler("sweep_unmixable", boost::bind(&simple_wallet::sweep_unmixable, this, _1), tr("Send all unmixable outputs to yourself with mixin 0")); m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1), tr("Send all unlocked balance an address")); m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), tr("set_log - Change current log detail level, <0-4>")); @@ -836,7 +836,7 @@ bool simple_wallet::ask_wallet_create_if_needed() bool valid_path = false; do { wallet_path = command_line::input_line( - tr("NOTE: This is my Wallet- Specify wallet file name (e.g., MyWallet). If the wallet doesn't exist, it will be created.\n" + tr("Specify wallet file name (e.g., MyWallet). If the wallet doesn't exist, it will be created.\n" "Wallet file name: ") ); if (std::cin.eof()) @@ -2582,7 +2582,7 @@ bool simple_wallet::locked_transfer(const std::vector &args_) } } - if(local_args.size() < 2) + if(local_args.size() < 3 ) { fail_msg_writer() << tr("wrong number of arguments"); return true; @@ -2593,50 +2593,56 @@ bool simple_wallet::locked_transfer(const std::vector &args_) fail_msg_writer() << tr("this is a watch only wallet"); return true; } - int given_unlock_time = 10; + int given_unlock_time = 0; std::vector extra; bool payment_id_seen = false; - if (1 == local_args.size() % 2) + if (local_args.size() < 5) { - std::string payment_id_str = local_args.back(); - local_args.pop_back(); + if (local_args.size() == 4) + { + std::string payment_id_str = local_args.back(); + local_args.pop_back(); - crypto::hash payment_id; - bool r = tools::wallet2::parse_long_payment_id(payment_id_str, payment_id); - if(r) - { - std::string extra_nonce; - set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id); - r = add_extra_nonce_to_tx_extra(extra, extra_nonce); - } - else - { - crypto::hash8 payment_id8; - r = tools::wallet2::parse_short_payment_id(payment_id_str, payment_id8); + crypto::hash payment_id; + bool r = tools::wallet2::parse_long_payment_id(payment_id_str, payment_id); if(r) { std::string extra_nonce; - set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8); + set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id); r = add_extra_nonce_to_tx_extra(extra, extra_nonce); } + else + { + crypto::hash8 payment_id8; + r = tools::wallet2::parse_short_payment_id(payment_id_str, payment_id8); + if(r) + { + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8); + r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + } + } + payment_id_seen = true; + if(!r) + { + fail_msg_writer() << tr("payment id has invalid format, expected 16 or 64 character hex string: ") << payment_id_str; + return true; + } + } - payment_id_seen = true; - if(!r) - { - fail_msg_writer() << tr("payment id has invalid format, expected 16 or 64 character hex string: ") << payment_id_str; + //std::string unlock_time_string = local_args.back(); + given_unlock_time = std::stoi( local_args.back() ); + local_args.pop_back(); - std::string err; - int bc_height = get_daemon_blockchain_height(err); - - given_unlock_time = bc_height + std::stoi(payment_id_str); - //return true; - payment_id_seen = false; - } - + } + else + { + fail_msg_writer() << tr("wrong number of arguments"); + return true; } vector dsts; - for (size_t i = 0; i < local_args.size(); i += 2) + for (size_t i = 0; i < 1; i += 2) { cryptonote::tx_destination_entry de; bool has_payment_id; @@ -2677,60 +2683,57 @@ bool simple_wallet::locked_transfer(const std::vector &args_) { // figure out what tx will be necessary std::vector ptx_vector; - ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, given_unlock_time /* unlock_time */, 0 /* unused fee arg*/, extra, m_trusted_daemon); + std::string err; + int bc_height = get_daemon_blockchain_height(err); + int unlock_time = given_unlock_time + bc_height; + ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_time , 0 /* unused fee arg*/, extra, m_trusted_daemon); - // if more than one tx necessary, prompt user to confirm - if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1) + uint64_t total_fee = 0; + uint64_t dust_not_in_fee = 0; + uint64_t dust_in_fee = 0; + for (size_t n = 0; n < ptx_vector.size(); ++n) { - uint64_t total_fee = 0; - uint64_t dust_not_in_fee = 0; - uint64_t dust_in_fee = 0; - for (size_t n = 0; n < ptx_vector.size(); ++n) - { - total_fee += ptx_vector[n].fee; + total_fee += ptx_vector[n].fee; - if (ptx_vector[n].dust_added_to_fee) - dust_in_fee += ptx_vector[n].dust; - else - dust_not_in_fee += ptx_vector[n].dust; - } - - std::stringstream prompt; - if (ptx_vector.size() > 1) - { - prompt << boost::format(tr("Your transaction needs to be split into %llu transactions. " - "This will result in a transaction fee being applied to each transaction, for a total fee of %s")) % - ((unsigned long long)ptx_vector.size()) % print_money(total_fee); - } - else - { - std::string err; - int bc_height = get_daemon_blockchain_height(err); - float days = (float)(given_unlock_time - bc_height) / 720.0; - prompt << boost::format(tr("The transaction fee is %s")) % - print_money(total_fee); - prompt << boost::format(tr("The unlock time is approximately %s days")) % - days; - } - if (dust_in_fee != 0) prompt << boost::format(tr(", of which %s is dust from change")) % print_money(dust_in_fee); - if (dust_not_in_fee != 0) prompt << tr(".") << ENDL << boost::format(tr("A total of %s from dust change will be sent to dust address")) - % print_money(dust_not_in_fee); - prompt << tr(".") << ENDL << tr("Is this okay? (Y/Yes/N/No)"); - - std::string accepted = command_line::input_line(prompt.str()); - if (std::cin.eof()) - return true; - if (accepted != "Y" && accepted != "y" && accepted != "Yes" && accepted != "yes") - { - fail_msg_writer() << tr("transaction cancelled."); - - // would like to return false, because no tx made, but everything else returns true - // and I don't know what returning false might adversely affect. *sigh* - return true; - } + if (ptx_vector[n].dust_added_to_fee) + dust_in_fee += ptx_vector[n].dust; + else + dust_not_in_fee += ptx_vector[n].dust; } + std::stringstream prompt; + if (ptx_vector.size() > 1) + { + prompt << boost::format(tr("Your transaction needs to be split into %llu transactions. " + "This will result in a transaction fee being applied to each transaction, for a total fee of %s")) % + ((unsigned long long)ptx_vector.size()) % print_money(total_fee); + } + else + { + + prompt << boost::format(tr("Transaction fee is %s")) % + print_money(total_fee); + } + if (dust_in_fee != 0) prompt << boost::format(tr(", of which %s is dust from change")) % print_money(dust_in_fee); + if (dust_not_in_fee != 0) prompt << tr(".") << ENDL << boost::format(tr("A total of %s from dust change will be sent to dust address")) + % print_money(dust_not_in_fee); + + float days = (float)(given_unlock_time) / 720.0; + prompt << boost::format(tr(".\nThe unlock time is approximately %s days")) % + days; + + prompt << tr(".") << ENDL << tr("Is this okay? (Y/Yes/N/No)"); + + std::string accepted = command_line::input_line(prompt.str()); + if (std::cin.eof()) + return true; + if (accepted != "Y" && accepted != "y" && accepted != "Yes" && accepted != "yes") + { + fail_msg_writer() << tr("transaction cancelled."); + return true; + } + // actually commit the transactions while (!ptx_vector.empty()) { @@ -2761,18 +2764,11 @@ bool simple_wallet::locked_transfer(const std::vector &args_) } catch (const tools::error::not_enough_money& e) { - std::stringstream prompt; LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") % print_money(e.available()) % print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount()) % print_money(e.fee())); - prompt << boost::format(tr("Available %s, transaction amount %s = %s + %s (fee)")) % - print_money(e.available()) % - print_money(e.tx_amount() + e.fee()) % - print_money(e.tx_amount()) % - print_money(e.fee()); - std::string accepted = command_line::input_line(prompt.str()); fail_msg_writer() << tr("Failed to find a way to create transactions, too bad. This is usually due to dust which is so small it cannot pay for itself in fees"); } catch (const tools::error::not_enough_outs_to_mix& e)