Add locked_transfer

This commit is contained in:
Oyvind Kvanes 2016-09-28 16:27:45 +02:00
parent d5f918a0b1
commit 7d020bde5e

View file

@ -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("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 [<mixin_count>] <addr_1> <amount_1> [<addr_2> <amount_2> ... <addr_N> <amount_N>] [payment_id] - Transfer <amount_1>,... <amount_N> to <address_1>,... <address_N>, respectively. <mixin_count> is the number of extra inputs to include for untraceability (from 0 to maximum available)")); m_cmd_binder.set_handler("transfer_original", boost::bind(&simple_wallet::transfer, this, _1), tr("transfer [<mixin_count>] <addr_1> <amount_1> [<addr_2> <amount_2> ... <addr_N> <amount_N>] [payment_id] - Transfer <amount_1>,... <amount_N> to <address_1>,... <address_N>, respectively. <mixin_count> 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("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 [<mixin_count>] <addr> <amount> <locktime>(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_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("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 <level> - Change current log detail level, <0-4>")); m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), tr("set_log <level> - Change current log detail level, <0-4>"));
@ -836,7 +836,7 @@ bool simple_wallet::ask_wallet_create_if_needed()
bool valid_path = false; bool valid_path = false;
do { do {
wallet_path = command_line::input_line( 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: ") "Wallet file name: ")
); );
if (std::cin.eof()) if (std::cin.eof())
@ -2582,7 +2582,7 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
} }
} }
if(local_args.size() < 2) if(local_args.size() < 3 )
{ {
fail_msg_writer() << tr("wrong number of arguments"); fail_msg_writer() << tr("wrong number of arguments");
return true; return true;
@ -2593,50 +2593,56 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
fail_msg_writer() << tr("this is a watch only wallet"); fail_msg_writer() << tr("this is a watch only wallet");
return true; return true;
} }
int given_unlock_time = 10; int given_unlock_time = 0;
std::vector<uint8_t> extra; std::vector<uint8_t> extra;
bool payment_id_seen = false; bool payment_id_seen = false;
if (1 == local_args.size() % 2) if (local_args.size() < 5)
{ {
std::string payment_id_str = local_args.back(); if (local_args.size() == 4)
local_args.pop_back(); {
std::string payment_id_str = local_args.back();
local_args.pop_back();
crypto::hash payment_id; crypto::hash payment_id;
bool r = tools::wallet2::parse_long_payment_id(payment_id_str, 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);
if(r) if(r)
{ {
std::string extra_nonce; 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); 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; //std::string unlock_time_string = local_args.back();
if(!r) given_unlock_time = std::stoi( local_args.back() );
{ local_args.pop_back();
fail_msg_writer() << tr("payment id has invalid format, expected 16 or 64 character hex string: ") << payment_id_str;
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<cryptonote::tx_destination_entry> dsts; vector<cryptonote::tx_destination_entry> 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; cryptonote::tx_destination_entry de;
bool has_payment_id; bool has_payment_id;
@ -2677,58 +2683,55 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
{ {
// figure out what tx will be necessary // figure out what tx will be necessary
std::vector<tools::wallet2::pending_tx> ptx_vector; std::vector<tools::wallet2::pending_tx> 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 uint64_t total_fee = 0;
if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1) 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; total_fee += ptx_vector[n].fee;
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;
if (ptx_vector[n].dust_added_to_fee) if (ptx_vector[n].dust_added_to_fee)
dust_in_fee += ptx_vector[n].dust; dust_in_fee += ptx_vector[n].dust;
else else
dust_not_in_fee += ptx_vector[n].dust; dust_not_in_fee += ptx_vector[n].dust;
} }
std::stringstream prompt; std::stringstream prompt;
if (ptx_vector.size() > 1) if (ptx_vector.size() > 1)
{ {
prompt << boost::format(tr("Your transaction needs to be split into %llu transactions. " 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")) % "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); ((unsigned long long)ptx_vector.size()) % print_money(total_fee);
} }
else 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()); prompt << boost::format(tr("Transaction fee is %s")) %
if (std::cin.eof()) print_money(total_fee);
return true; }
if (accepted != "Y" && accepted != "y" && accepted != "Yes" && accepted != "yes") 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"))
fail_msg_writer() << tr("transaction cancelled."); % print_money(dust_not_in_fee);
// would like to return false, because no tx made, but everything else returns true float days = (float)(given_unlock_time) / 720.0;
// and I don't know what returning false might adversely affect. *sigh* prompt << boost::format(tr(".\nThe unlock time is approximately %s days")) %
return true; 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 // actually commit the transactions
@ -2761,18 +2764,11 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
} }
catch (const tools::error::not_enough_money& e) 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)") % 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.available()) %
print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount() + e.fee()) %
print_money(e.tx_amount()) % print_money(e.tx_amount()) %
print_money(e.fee())); 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"); 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) catch (const tools::error::not_enough_outs_to_mix& e)