diff --git a/CMakeLists.txt b/CMakeLists.txt index 89a3be9..3df22d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -281,6 +281,65 @@ target_link_libraries(monero-cpp ${EXTRA_LIBRARIES} ) +######################## +# Build C++ Sample Code +######################## + +###[[ --- START BLOCK COMMENT --- + +set( + SAMPLE_CODE_SRC_FILES + test/sample_code.cpp +) + +add_executable(sample_code ${SAMPLE_CODE_SRC_FILES} ${LIBRARY_SRC_FILES}) + +target_link_libraries(sample_code + + hidapi + + boost_chrono + boost_date_time + boost_filesystem + boost_program_options + boost_regex + boost_serialization + boost_wserialization + boost_system + boost_thread + + ssl + crypto + + wallet_merged + #wallet_api + wallet + lmdb + epee + unbound + sodium + easylogging + + cryptonote_core + cryptonote_basic + mnemonics + ringct + ringct_basic + common + cncrypto + blockchain_db + blocks + checkpoints + device + device_trezor + multisig + version + + ${EXTRA_LIBRARIES} +) + +###]] # --- END BLOCK COMMENT --- + ######################## # Build C++ scratchpad ######################## diff --git a/src/wallet/monero_wallet.cpp b/src/wallet/monero_wallet.cpp index 0032f2a..6333b28 100644 --- a/src/wallet/monero_wallet.cpp +++ b/src/wallet/monero_wallet.cpp @@ -1116,6 +1116,11 @@ namespace monero { return epee::string_tools::pod_to_hex(m_w2->get_account().get_keys().m_spend_secret_key); } + string monero_wallet::get_primary_address() const { + MTRACE("get_primary_address()"); + return get_address(0, 0); + } + void monero_wallet::set_listener(const boost::optional listener) { MTRACE("set_listener()"); m_w2_listener->set_wallet_listener(listener); diff --git a/test/sample_code.cpp b/test/sample_code.cpp new file mode 100644 index 0000000..11cf83f --- /dev/null +++ b/test/sample_code.cpp @@ -0,0 +1,108 @@ +#include +#include +#include "wallet2.h" +#include "wallet/monero_wallet.h" + +using namespace std; + +/** + * This code introduces the API. + * + * NOTE: depending on feedback, fields might become private and accessible only + * through public acessors/mutators for pure object-oriented. + */ +int main(int argc, const char* argv[]) { + + // create a wallet from a mnemonic phrase + string mnemonic = "hefty value later extra artistic firm radar yodel talent future fungal nutshell because sanity awesome nail unjustly rage unafraid cedar delayed thumbs comb custom sanity"; + monero_wallet* wallet_restored = monero_wallet::create_wallet_from_mnemonic( + "MyWalletRestored", // wallet path and name + "supersecretpassword123", // wallet password + monero_network_type::STAGENET, // network type + mnemonic, // mnemonic phrase + monero_rpc_connection("http://localhost:38081"), // daemon connection + 380104 // restore height + ); + + // sync the wallet + wallet_restored->sync(); // one time synchronous sync + wallet_restored->start_syncing(); // continuously sync as an asynchronous thread in the background + + // get balance, account, subaddresses + string primary_address = wallet_restored->get_primary_address(); + uint64_t balance = wallet_restored->get_balance(); // can specify account and subaddress indices + monero_account account = wallet_restored->get_account(1, true); // get account with subaddresses + uint64_t unlocked_account_balance = account.m_unlocked_balance.get(); // get boost::optional value + + // query a transaction by id + monero_tx_query tx_query; + tx_query.m_id = "3276252c5a545b90c8e147fcde45d3e1917726470a8f7d4c8977b527a44dfd15"; + shared_ptr tx = wallet_restored->get_txs(tx_query)[0]; + for (const shared_ptr in_transfer : tx->m_incoming_transfers) { + uint64_t in_amount = in_transfer->m_amount.get(); + int account_index = in_transfer->m_account_index.get(); + } + + // query incoming transfers to account 1 + monero_transfer_query transfer_query; + transfer_query.m_is_incoming = true; + transfer_query.m_account_index = 1; + vector> transfers = wallet_restored->get_transfers(transfer_query); + + // query unspent outputs + monero_output_query output_query; + output_query.m_is_spent = false; + vector> outputs = wallet_restored->get_outputs(output_query); + + // create a new wallet with a random mnemonic phrase + monero_wallet* wallet_random = monero_wallet::create_wallet_random( + "MyWalletRandom", // wallet path and name + "supersecretpassword123", // wallet password + monero_network_type::STAGENET, // network type + monero_rpc_connection("http://localhost:38081"), // daemon connection + "English" + ); + + // continuously synchronize the wallet + wallet_random->start_syncing(); + + // get wallet info + string random_mnemonic = wallet_random->get_mnemonic(); + string address = wallet_random->get_primary_address(); + uint64_t height = wallet_random->get_height(); + bool is_synced = wallet_random->is_synced(); + + // be notified when the wallet receives funds + class : monero_wallet_listener { + void on_output_received(const monero_output_wallet& output) { + cout << "Wallet received funds!" << endl; + int account_index = output.m_account_index.get(); + int subaddress_index = output.m_subaddress_index.get(); + shared_ptr key_image = output.m_key_image.get(); + } + } my_listener; + //wallet_random->set_listener(&my_listener); + + // TODO: define wallet send convenience methods +// // send funds from the restored wallet to the random wallet +// monero_tx_wallet sent_tx = wallet_restored->send(0, wallet_random->get_address(1, 0), 50000); +// boolean in_pool = sent_tx.in_tx_pool(); // true + + // create a request to send funds to multiple destinations in the random wallet + monero_send_request send_request = monero_send_request(); + send_request.m_account_index = 1; // withdraw funds from this account + send_request.m_subaddress_indices = vector(); + send_request.m_subaddress_indices.push_back(0); + send_request.m_subaddress_indices.push_back(1); // withdraw funds from these subaddresses within the account + send_request.m_priority = monero_send_priority::UNIMPORTANT; // no rush + vector> destinations; // specify the recipients and their amounts +// destinations.push_back(make_shared(wallet_random->get_address(1, 0), 50000)); // TODO: destination constructor +// destinations.push_back(make_shared(wallet_random->get_address(2, 0), 50000)); + send_request.m_destinations = destinations; + + // TODO: define wallet send convenience methods +// // create the transaction, confirm with the user, and relay to the network +// shared_ptr created_tx = wallet_restored->create_tx(send_request); +// uint64_t fee = created_tx->fee.get(); // "Are you sure you want to send ...?" +// wallet_restored->relay_tx(created_tx); // submit the transaction to the Monero network which will notify the recipient wallet +} diff --git a/test/scratchpad.cpp b/test/scratchpad.cpp index 5342c2b..41a5cf6 100644 --- a/test/scratchpad.cpp +++ b/test/scratchpad.cpp @@ -2,36 +2,9 @@ #include #include "wallet2.h" #include "wallet/monero_wallet.h" -//#include + using namespace std; -bool wallet_exists(string path) { - //std::cout << boost::stacktrace::stacktrace(); - bool keys_file_exists; - bool wallet_file_exists; - tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); - return wallet_file_exists; -} - -void open_wallet(string path, string password, int network_type) { - cout << "open_wallet(" << path << ", " << password << ", " << network_type << ")" << endl; - std::unique_ptr wallet; - wallet.reset(new tools::wallet2(cryptonote::network_type::STAGENET, 1, true)); - throw runtime_error("Not implemented"); -} - -void create_wallet_random(string language, int network_type) { - tools::wallet2* wallet = new tools::wallet2(static_cast(network_type), 1, true); - wallet->set_seed_language(language); - crypto::secret_key recovery_val, secret_key; - wallet->generate(string(""), string(""), secret_key, false, false); - - // print the mnemonic - epee::wipeable_string mnemonic; - wallet->get_seed(mnemonic); - cout << "Mnemonic: " << string(mnemonic.data(), mnemonic.size()) << endl; -} - /** * Scratchpad main entry point. */ @@ -55,20 +28,6 @@ int main(int argc, const char* argv[]) { string language = "English"; int network_type = 2; - MINFO("Wallet exists: " << wallet_exists(path)); - -// open_wallet(path, password, network_type); -// create_wallet_random(language, network_type); - -// // create wallet -// monero_wallet* wallet = new monero_wallet(); -// -// // get the mnemonic -// epee::wipeable_string mnemonic; -// wallet->get_mnemonic(mnemonic); -// cout << "Mnemonic: " << string(mnemonic.data(), mnemonic.size()) << endl; - - // load wallet monero_wallet* wallet = monero_wallet::open_wallet("../../test_wallets/test_wallet_1", "supersecretpassword123", monero_network_type::STAGENET); wallet->set_daemon_connection("http://localhost:38081", "", ""); @@ -100,23 +59,4 @@ int main(int argc, const char* argv[]) { // for (const shared_ptr& tx : txs) { // if (!*tx->is_confirmed) throw runtime_error("Tx should be confirmed"); // } - - -// // debug simple block merging -// vector> txs = wallet->get_txs(); -// if (txs.empty()) throw runtime_error("Txs should not be empty"); -// shared_ptr block = nullptr; -// for (const shared_ptr& tx : txs) { -// if (tx->get_height().get() != 360559l) throw runtime_error("Anything other than 360559l should be filtered"); -// cout << "We have one!!!" << endl; -// if (block == nullptr) block = tx->block.get(); -// else { -// if (block != tx->block.get()) { -// cout << "BOOM" << endl; -// cout << block->serialize(); -// cout << "--- VS ---" << endl; -// cout << tx->block.get()->serialize(); -// } -// } -// } } diff --git a/todo.txt b/todo.txt index c284120..a315770 100644 --- a/todo.txt +++ b/todo.txt @@ -4,6 +4,8 @@ gen documentation sample code including readme MEDIUM PRIORITY +should not need wallet.h / wallet.cpp as dependency, why are GUI deps needed? +make model fields private and use accessors / mutators? remove jstring2string, be consistent with other string inits number of mining threads should be uint32_t instead of uint64_t getReserveProofAccount() jni seg fault