aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplewallet')
-rw-r--r--src/simplewallet/password_container.cpp231
-rw-r--r--src/simplewallet/password_container.h36
-rw-r--r--src/simplewallet/simplewallet.cpp523
-rw-r--r--src/simplewallet/simplewallet.h74
4 files changed, 864 insertions, 0 deletions
diff --git a/src/simplewallet/password_container.cpp b/src/simplewallet/password_container.cpp
new file mode 100644
index 000000000..0b9dc1cdf
--- /dev/null
+++ b/src/simplewallet/password_container.cpp
@@ -0,0 +1,231 @@
+// Copyright (c) 2012-2013 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "password_container.h"
+
+#include <iostream>
+#include <memory.h>
+#include <stdio.h>
+
+#if defined(_WIN32)
+#include <io.h>
+#include <windows.h>
+#else
+#include <termios.h>
+#include <unistd.h>
+#endif
+
+namespace tools
+{
+ namespace
+ {
+ bool is_cin_tty();
+ }
+
+ password_container::password_container()
+ : m_empty(true)
+ {
+ }
+
+ password_container::password_container(std::string&& password)
+ : m_empty(false)
+ , m_password(std::move(password))
+ {
+ }
+
+ password_container::password_container(password_container&& rhs)
+ : m_empty(std::move(rhs.m_empty))
+ , m_password(std::move(rhs.m_password))
+ {
+ }
+
+ password_container::~password_container()
+ {
+ clear();
+ }
+
+ void password_container::clear()
+ {
+ if (0 < m_password.capacity())
+ {
+ m_password.replace(0, m_password.capacity(), m_password.capacity(), '\0');
+ m_password.resize(0);
+ }
+ m_empty = true;
+ }
+
+ bool password_container::read_password()
+ {
+ clear();
+
+ bool r;
+ if (is_cin_tty())
+ {
+ std::cout << "password: ";
+ r = read_from_tty();
+ }
+ else
+ {
+ r = read_from_file();
+ }
+
+ if (r)
+ {
+ m_empty = false;
+ }
+ else
+ {
+ clear();
+ }
+
+ return r;
+ }
+
+ bool password_container::read_from_file()
+ {
+ m_password.reserve(max_password_size);
+ for (size_t i = 0; i < max_password_size; ++i)
+ {
+ char ch = static_cast<char>(std::cin.get());
+ if (std::cin.eof() || ch == '\n' || ch == '\r')
+ {
+ break;
+ }
+ else if (std::cin.fail())
+ {
+ return false;
+ }
+ else
+ {
+ m_password.push_back(ch);
+ }
+ }
+
+ return true;
+ }
+
+#if defined(_WIN32)
+
+ namespace
+ {
+ bool is_cin_tty()
+ {
+ return 0 != _isatty(_fileno(stdin));
+ }
+ }
+
+ bool password_container::read_from_tty()
+ {
+ const char BACKSPACE = 8;
+
+ HANDLE h_cin = ::GetStdHandle(STD_INPUT_HANDLE);
+
+ DWORD mode_old;
+ ::GetConsoleMode(h_cin, &mode_old);
+ DWORD mode_new = mode_old & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
+ ::SetConsoleMode(h_cin, mode_new);
+
+ bool r = true;
+ m_password.reserve(max_password_size);
+ while (m_password.size() < max_password_size)
+ {
+ DWORD read;
+ char ch;
+ r = (TRUE == ::ReadConsoleA(h_cin, &ch, 1, &read, NULL));
+ r &= (1 == read);
+ if (!r)
+ {
+ break;
+ }
+ else if (ch == '\n' || ch == '\r')
+ {
+ std::cout << std::endl;
+ break;
+ }
+ else if (ch == BACKSPACE)
+ {
+ if (!m_password.empty())
+ {
+ m_password.back() = '\0';
+ m_password.resize(m_password.size() - 1);
+ std::cout << "\b \b";
+ }
+ }
+ else
+ {
+ m_password.push_back(ch);
+ std::cout << '*';
+ }
+ }
+
+ ::SetConsoleMode(h_cin, mode_old);
+
+ return r;
+ }
+
+#else
+
+ namespace
+ {
+ bool is_cin_tty()
+ {
+ return 0 != isatty(fileno(stdin));
+ }
+
+ int getch()
+ {
+ struct termios tty_old;
+ tcgetattr(STDIN_FILENO, &tty_old);
+
+ struct termios tty_new;
+ tty_new = tty_old;
+ tty_new.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(STDIN_FILENO, TCSANOW, &tty_new);
+
+ int ch = getchar();
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &tty_old);
+
+ return ch;
+ }
+ }
+
+ bool password_container::read_from_tty()
+ {
+ const char BACKSPACE = 127;
+
+ m_password.reserve(max_password_size);
+ while (m_password.size() < max_password_size)
+ {
+ int ch = getch();
+ if (EOF == ch)
+ {
+ return false;
+ }
+ else if (ch == '\n' || ch == '\r')
+ {
+ std::cout << std::endl;
+ break;
+ }
+ else if (ch == BACKSPACE)
+ {
+ if (!m_password.empty())
+ {
+ m_password.back() = '\0';
+ m_password.resize(m_password.size() - 1);
+ std::cout << "\b \b";
+ }
+ }
+ else
+ {
+ m_password.push_back(ch);
+ std::cout << '*';
+ }
+ }
+
+ return true;
+ }
+
+#endif
+}
diff --git a/src/simplewallet/password_container.h b/src/simplewallet/password_container.h
new file mode 100644
index 000000000..2e99d9a62
--- /dev/null
+++ b/src/simplewallet/password_container.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012-2013 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+
+#pragma once
+
+#include <string>
+
+namespace tools
+{
+ class password_container
+ {
+ public:
+ static const size_t max_password_size = 1024;
+
+ password_container();
+ password_container(std::string&& password);
+ password_container(password_container&& rhs);
+ ~password_container();
+
+ void clear();
+ bool empty() const { return m_empty; }
+ const std::string& password() const { return m_password; }
+ void password(std::string&& val) { m_password = std::move(val); m_empty = false; }
+ bool read_password();
+
+ private:
+ bool read_from_file();
+ bool read_from_tty();
+
+ private:
+ bool m_empty;
+ std::string m_password;
+ };
+}
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
new file mode 100644
index 000000000..bda47019b
--- /dev/null
+++ b/src/simplewallet/simplewallet.cpp
@@ -0,0 +1,523 @@
+// Copyright (c) 2012-2013 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <thread>
+#include <boost/lexical_cast.hpp>
+#include <boost/program_options.hpp>
+#include <boost/algorithm/string.hpp>
+#include "include_base_utils.h"
+#include "common/command_line.h"
+#include "p2p/net_node.h"
+#include "cryptonote_protocol/cryptonote_protocol_handler.h"
+#include "simplewallet.h"
+#include "cryptonote_core/cryptonote_format_utils.h"
+#include "storages/http_abstract_invoke.h"
+#include "rpc/core_rpc_server_commands_defs.h"
+#include "version.h"
+
+#if defined(WIN32)
+#include <crtdbg.h>
+#endif
+
+using namespace std;
+using namespace epee;
+using namespace cryptonote;
+using boost::lexical_cast;
+namespace po = boost::program_options;
+
+#define EXTENDED_LOGS_FILE "wallet_details.log"
+
+
+namespace
+{
+ const command_line::arg_descriptor<std::string> arg_wallet_file = {"wallet-file", "Use wallet <arg>", ""};
+ const command_line::arg_descriptor<std::string> arg_generate_new_wallet = {"generate-new-wallet", "Generate new wallet and save it to <arg> or <address>.wallet by default", ""};
+ const command_line::arg_descriptor<std::string> arg_daemon_address = {"daemon-address", "Use daemon instance at <host>:<port>", ""};
+ const command_line::arg_descriptor<std::string> arg_daemon_host = {"daemon-host", "Use daemon instance at host <arg> instead of localhost", ""};
+ const command_line::arg_descriptor<std::string> arg_password = {"password", "Wallet password", "", true};
+ const command_line::arg_descriptor<int> arg_daemon_port = {"daemon-port", "Use daemon instance at port <arg> instead of 8080", 0};
+ const command_line::arg_descriptor<uint32_t> arg_log_level = {"set_log", "", 0, true};
+
+ const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
+}
+
+/*const char *commands_help =
+ "Commands:\n"
+ " help Show this help\n"
+ " address Show current account public address\n"
+ " exit\n"
+ " refresh\n"
+ " start_mining Start mining\n"
+ " set_log\n"
+ " show_balance Show current account balance\n"
+ " show_bc_height Show blockchain height\n"
+ " show_incoming_transfers Show coins\n"
+ " transfer <mixin_count> (<addr> <amount>)... Transfer <amount> to <addr>\n";*/
+
+
+
+std::string simple_wallet::get_commands_str()
+{
+ std::stringstream ss;
+ ss << "Commands: " << ENDL;
+ std::string usage = m_cmd_binder.get_usage();
+ boost::replace_all(usage, "\n", "\n ");
+ usage.insert(0, " ");
+ ss << usage << ENDL;
+ return ss.str();
+}
+
+bool simple_wallet::help(const std::vector<std::string> &args)
+{
+ std::cout << get_commands_str();
+ return true;
+}
+
+simple_wallet::simple_wallet()
+ : m_daemon_port(0)
+ , m_tried_to_connect(false)
+{
+ m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "Start mining in daemon");
+ m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon");
+ m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance");
+ m_cmd_binder.set_handler("show_balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance");
+ m_cmd_binder.set_handler("show_incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "Show incoming transfers");
+ m_cmd_binder.set_handler("show_bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height");
+ m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer <mixin_count> <<addr> <amount>> Transfer <amount> to <address>. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)");
+ m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "Change current log detalization level, <level> is a number 0-4");
+ m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address");
+ m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data");
+ m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), "Show this help");
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::set_log(const std::vector<std::string> &args)
+{
+ if(args.size() != 1)
+ {
+ std::cout << "use: set_log <log_level_number_0-4>" << ENDL;
+ return true;
+ }
+ int l = 0;
+ if(!string_tools::get_xtype_from_string(l, args[0]))
+ {
+ std::cout << "wrong number format, use: set_log <log_level_number_0-4>" << ENDL;
+ return true;
+ }
+ if(l < 0 || l > LOG_LEVEL_4)
+ {
+ std::cout << "wrong number range, use: set_log <log_level_number_0-4>" << ENDL;
+ return true;
+ }
+
+ log_space::log_singletone::get_set_log_detalisation_level(true, l);
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::init(const boost::program_options::variables_map& vm)
+{
+ handle_command_line(vm);
+
+ CHECK_AND_ASSERT_MES(m_daemon_address.empty() || (m_daemon_host.empty() && !m_daemon_port), false, "you can't specify daemon host or port several times");
+
+ size_t c = 0;
+ if(!m_generate_new.empty()) ++c;
+ if(!m_wallet_file.empty()) ++c;
+ CHECK_AND_ASSERT_MES(c == 1, false, "you must specify --wallet-file or --generate-new-wallet params");
+
+ if (m_daemon_host.empty())
+ m_daemon_host = "localhost";
+ if (!m_daemon_port)
+ m_daemon_port = RPC_DEFAULT_PORT;
+ if (m_daemon_address.empty())
+ m_daemon_address = string("http://") + m_daemon_host + ":" + lexical_cast<string>(m_daemon_port);
+
+ tools::password_container pwd_container;
+ if (command_line::has_arg(vm, arg_password))
+ {
+ pwd_container.password(command_line::get_arg(vm, arg_password));
+ }
+ else
+ {
+ bool r = pwd_container.read_password();
+ CHECK_AND_ASSERT_MES(r, false, "failed to read wallet password");
+ }
+
+ if (!m_generate_new.empty())
+ {
+ bool r = new_wallet(m_generate_new, pwd_container.password());
+ CHECK_AND_ASSERT_MES(r, false, "account creation failed");
+ }
+ else
+ {
+ bool r = open_wallet(m_wallet_file, pwd_container.password());
+ CHECK_AND_ASSERT_MES(r, false, "could not open account");
+ }
+
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::deinit()
+{
+ if (!m_wallet.get())
+ return true;
+
+ return close_wallet();
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::handle_command_line(const boost::program_options::variables_map& vm)
+{
+ m_wallet_file = command_line::get_arg(vm, arg_wallet_file);
+ m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet);
+ m_daemon_address = command_line::get_arg(vm, arg_daemon_address);
+ m_daemon_host = command_line::get_arg(vm, arg_daemon_host);
+ m_daemon_port = command_line::get_arg(vm, arg_daemon_port);
+
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+void simple_wallet::try_connect_to_daemon()
+{
+ if (!m_tried_to_connect)
+ {
+ m_tried_to_connect = true;
+
+ if(!m_wallet->check_connection())
+ {
+ std::cout <<
+ "**********************************************************************" << ENDL <<
+ "Wallet failed to connect to daemon. Daemon either is not started or passed wrong port. Please, make sure that daemon is running or restart the wallet with correct daemon address." << ENDL <<
+ "**********************************************************************" << ENDL;
+ }
+ }
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password)
+{
+ m_wallet_file = wallet_file;
+ if(boost::filesystem::exists(wallet_file))
+ {
+ std::cout << "wallet creation failed, file " << wallet_file << " already exists" << std::endl;
+ return false;
+ }
+
+ m_wallet.reset(new tools::wallet2());
+ bool r = m_wallet->generate(wallet_file, password);
+ if(!r)
+ return false;
+
+ cout << "Generated new wallet" << ENDL;
+ print_address(std::vector<std::string>());
+ r = m_wallet->init(m_daemon_address);
+ CHECK_AND_ASSERT_MES(r, false, "failed to init wallet");
+ std::cout << "**********************************************************************" << ENDL
+ << "Your wallet has been generated. " << ENDL
+ << "To start synchronizing with the daemon use \"refresh\" command." << ENDL
+ << "Use \"help\" command to see the list of available commands." << ENDL
+ << "Always use \"exit\" command when closing simplewallet to save "
+ << "current session's state. Otherwise, you will possibly need to synchronize " << ENDL
+ << "your wallet again. Your wallet key is NOT under risk anyway." << ENDL
+ << "**********************************************************************" << ENDL;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::open_wallet(const string &wallet_file, const std::string& password)
+{
+ m_wallet_file = wallet_file;
+ m_wallet.reset(new tools::wallet2());
+
+ bool r = m_wallet->load(m_wallet_file, password);
+ CHECK_AND_ASSERT_MES(r, false, "failed to load wallet " + m_wallet_file);
+ r = m_wallet->init(m_daemon_address);
+ CHECK_AND_ASSERT_MES(r, false, "failed to init wallet");
+
+ refresh(vector<string>());
+ std::cout << "**********************************************************************" << ENDL
+ << "Use \"help\" command to see the list of available commands." << ENDL
+ << "**********************************************************************" << ENDL ;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::close_wallet()
+{
+ bool r = m_wallet->deinit();
+ CHECK_AND_ASSERT_MES(r, false, "failed to deinit wallet");
+ r = m_wallet->store();
+ CHECK_AND_ASSERT_MES(r, false, "failed to store wallet " + m_wallet_file);
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::save(const std::vector<std::string> &args)
+{
+ bool r = m_wallet->store();
+ CHECK_AND_ASSERT_MES(r, false, "failed to store wallet " + m_wallet_file);
+ std::cout << "Wallet data saved" << ENDL;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::start_mining(const vector<string>& args)
+{
+ try_connect_to_daemon();
+
+ COMMAND_RPC_START_MINING::request req;
+ req.miner_address = m_wallet->get_account().get_public_address_str();
+ req.threads_count = 1;
+ if(args.size() == 1)
+ {
+ if(!string_tools::get_xtype_from_string(req.threads_count, args[0]))
+ {
+ std::cout << "Threads count value invalid \"" << args[0] << "\"" << ENDL;
+ return false;
+ }
+ }
+ COMMAND_RPC_START_MINING::response res;
+ bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/start_mining", req, res, m_http_client);
+ if (!r)
+ std::cout << "Mining has NOT been started" << std::endl;
+ CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "failed to invoke http request");
+ std::cout << "Mining started in daemon." << ENDL;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::stop_mining(const vector<string>& args)
+{
+ try_connect_to_daemon();
+
+ COMMAND_RPC_STOP_MINING::request req;
+ COMMAND_RPC_STOP_MINING::response res;
+ bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/stop_mining", req, res, m_http_client);
+ if (!r)
+ std::cout << "Mining has NOT been stopped" << std::endl;
+ CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "failed to invoke http request");
+ std::cout << "Mining stopped in daemon." << ENDL;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::refresh(const vector<string>& args)
+{
+ try_connect_to_daemon();
+
+ std::cout << "Starting refresh..." << endl;
+ std::atomic<bool> refresh_is_done(false);
+ std::thread th([&]()
+ {
+ epee::misc_utils::sleep_no_w(1000);
+ while(!refresh_is_done)
+ {
+ bool ok;
+ uint64_t bc_height = get_daemon_blockchain_height(ok);
+ if (ok)
+ cout << "Height " << m_wallet->get_blockchain_current_height() << " of " << bc_height << endl;
+ epee::misc_utils::sleep_no_w(1000);
+ }
+ });
+ uint64_t fetched_blocks = 0;
+ bool money_received = false;
+ bool ok = m_wallet->refresh(fetched_blocks, money_received);
+ refresh_is_done = true;
+ th.join();
+ if (ok)
+ std::cout << "Refresh done, blocks received: " << fetched_blocks << endl;
+ else
+ std::cout << "Refresh failed, no blocks received" << std::endl;
+ show_balance(vector<string>());
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::show_balance(const vector<string>& args)
+{
+ cout << "balance: " << print_money(m_wallet->balance()) << ", unlocked balance: " << print_money(m_wallet->unlocked_balance()) << endl;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::show_incoming_transfers(const vector<string>& args)
+{
+ m_wallet->show_incoming_transfers();
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+uint64_t simple_wallet::get_daemon_blockchain_height(bool& ok)
+{
+ COMMAND_RPC_GET_HEIGHT::request req;
+ COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>();
+ ok = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client);
+ CHECK_AND_ASSERT_MES(ok, 0, "failed to invoke http request");
+ return res.height;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::show_blockchain_height(const vector<string>& args)
+{
+ try_connect_to_daemon();
+
+ bool ok;
+ uint64_t bc_height = get_daemon_blockchain_height(ok);
+ if (ok)
+ cout << "core returned height: " << bc_height << endl;
+ else
+ std::cout << "Failed to get blockchain height" << std::endl;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::transfer(const vector<string> &args_)
+{
+ try_connect_to_daemon();
+
+ vector<string> local_args = args_;
+ if(local_args.size() < 3)
+ {
+ std::cout << "wrong transfer arguments" << std::endl;
+ help(vector<string>());
+ return true;
+ }
+ size_t fake_outs_count;
+ if(!string_tools::get_xtype_from_string(fake_outs_count, local_args[0]))
+ {
+ std::cout << " ambiguity_degree set wrong" << std::endl;
+ help(vector<string>());
+ return true;
+ }
+ local_args.erase(local_args.begin());
+ if(local_args.size() % 2 != 0)
+ {
+ cout << "wrong transfer arguments" << endl;
+ help(vector<string>());
+ return true;
+ }
+
+ vector<cryptonote::tx_destination_entry> dsts;
+ uint64_t summary_amount = 0;
+ for (size_t i = 0; i < local_args.size(); i += 2)
+ {
+ cryptonote::tx_destination_entry de;
+ if(!cryptonote::parse_amount(de.amount, local_args[i+1]))
+ {
+ cout << "Wrong transfer arguments" << endl;;
+ help(vector<string>());
+ return true;
+ }
+ if(de.amount <= 0)
+ {
+ cout << "Wrong transfer amount: " << de.amount << endl;;
+ help(vector<string>());
+ return true;
+ }
+ summary_amount += de.amount;
+ if(!get_account_address_from_str(de.addr, local_args[i]))
+ {
+ cout << "Wrong address: " << local_args[i] << endl;
+ help(vector<string>());
+ return true;
+ }
+ dsts.push_back(de);
+ }
+
+ if(summary_amount > m_wallet->unlocked_balance())
+ {
+ cout << "Not enough money to transfer " << print_money(summary_amount) << ", available(unlocked) only " << print_money(m_wallet->unlocked_balance()) << endl;
+ return true;
+ }
+
+ m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE);
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::run()
+{
+ m_cmd_binder.run_handling("");
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::print_address(const std::vector<std::string> &args)
+{
+ std::cout << "Public address: " << m_wallet->get_account().get_public_address_str() << ENDL;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::process_command(const std::vector<std::string> &args)
+{
+ return m_cmd_binder.process_command_vec(args);
+}
+//----------------------------------------------------------------------------------------------------
+int main(int argc, char* argv[])
+{
+
+#ifdef WIN32
+ _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
+#endif
+
+ //TRY_ENTRY();
+
+ string_tools::set_module_name_and_folder(argv[0]);
+
+ po::options_description desc_general("General options");
+ command_line::add_arg(desc_general, command_line::arg_help);
+ command_line::add_arg(desc_general, command_line::arg_version);
+
+ po::options_description desc_params("Wallet options");
+ command_line::add_arg(desc_params, arg_wallet_file);
+ command_line::add_arg(desc_params, arg_generate_new_wallet);
+ command_line::add_arg(desc_params, arg_password);
+ command_line::add_arg(desc_params, arg_daemon_address);
+ command_line::add_arg(desc_params, arg_daemon_host);
+ command_line::add_arg(desc_params, arg_daemon_port);
+ command_line::add_arg(desc_params, arg_command);
+ command_line::add_arg(desc_params, arg_log_level);
+
+ po::positional_options_description positional_options;
+ positional_options.add(arg_command.name, -1);
+
+ po::options_description desc_all;
+ desc_all.add(desc_general).add(desc_params);
+ cryptonote::simple_wallet w;
+ po::variables_map vm;
+ bool r = command_line::handle_error_helper(desc_all, [&]()
+ {
+ po::store(command_line::parse_command_line(argc, argv, desc_general, true), vm);
+
+ if (command_line::get_arg(vm, command_line::arg_help))
+ {
+ std::cout << "Usage: simplewallet [--wallet-file=<file>|--generate-new-wallet=<file>] [--daemon-address=<host>:<port>] [<COMMAND>]\n";
+ std::cout << desc_all << '\n' << w.get_commands_str() << std::endl;
+ return false;
+ }
+ else if (command_line::get_arg(vm, command_line::arg_version))
+ {
+ std::cout << "BYTECOIN WALLET v" << PROJECT_VERSION_LONG << ENDL;
+ return false;
+ }
+
+ auto parser = po::command_line_parser(argc, argv).options(desc_params).positional(positional_options);
+ po::store(parser.run(), vm);
+ po::notify(vm);
+ return true;
+ });
+ if (!r)
+ return 1;
+
+ //set up logging options
+ log_space::get_set_log_detalisation_level(true, LOG_LEVEL_1);
+ log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
+ log_space::log_singletone::add_logger(LOGGER_FILE,
+ log_space::log_singletone::get_default_log_file().c_str(),
+ log_space::log_singletone::get_default_log_folder().c_str());
+
+ if(command_line::has_arg(vm, arg_log_level))
+ {
+ LOG_PRINT_L0("Setting log level = " << command_line::get_arg(vm, arg_log_level));
+ log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, arg_log_level));
+ }
+ LOG_PRINT("simplewallet starting", LOG_LEVEL_0);
+
+ r = w.init(vm);
+ CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet");
+
+ std::vector<std::string> command = command_line::get_arg(vm, arg_command);
+ if (!command.empty())
+ w.process_command(command);
+ w.run();
+
+ w.deinit();
+
+ return 1;
+ //CATCH_ENTRY_L0("main", 1);
+}
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
new file mode 100644
index 000000000..01d3ac4a7
--- /dev/null
+++ b/src/simplewallet/simplewallet.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2012-2013 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#pragma once
+
+#include <memory>
+
+#include <boost/program_options/variables_map.hpp>
+
+#include "cryptonote_core/account.h"
+#include "cryptonote_core/cryptonote_basic_impl.h"
+#include "wallet/wallet2.h"
+#include "console_handler.h"
+#include "password_container.h"
+
+
+namespace cryptonote
+{
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class simple_wallet
+ {
+ public:
+ typedef std::vector<std::string> command_type;
+
+ simple_wallet();
+ bool init(const boost::program_options::variables_map& vm);
+ bool deinit();
+ bool run();
+
+ //wallet *create_wallet();
+ bool process_command(const std::vector<std::string> &args);
+ std::string get_commands_str();
+ private:
+ bool handle_command_line(const boost::program_options::variables_map& vm);
+
+ bool run_console_handler();
+
+ bool new_wallet(const std::string &wallet_file, const std::string& password);
+ bool open_wallet(const std::string &wallet_file, const std::string& password);
+ bool close_wallet();
+
+ bool help(const std::vector<std::string> &args);
+ bool start_mining(const std::vector<std::string> &args);
+ bool stop_mining(const std::vector<std::string> &args);
+ bool refresh(const std::vector<std::string> &args);
+ bool show_balance(const std::vector<std::string> &args);
+ bool show_incoming_transfers(const std::vector<std::string> &args);
+ bool show_blockchain_height(const std::vector<std::string> &args);
+ bool transfer(const std::vector<std::string> &args);
+ bool print_address(const std::vector<std::string> &args);
+ bool save(const std::vector<std::string> &args);
+ bool set_log(const std::vector<std::string> &args);
+
+ uint64_t get_daemon_blockchain_height(bool& ok);
+ void try_connect_to_daemon();
+
+ std::string m_wallet_file;
+ std::string m_generate_new;
+ std::string m_import_path;
+
+ std::string m_daemon_address;
+ std::string m_daemon_host;
+ int m_daemon_port;
+ bool m_tried_to_connect;
+
+ epee::console_handlers_binder m_cmd_binder;
+
+ std::auto_ptr<tools::wallet2> m_wallet;
+ net_utils::http::http_simple_client m_http_client;
+ };
+}