diff --git a/.gitmodules b/.gitmodules index 5a3c641..93101a2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,7 @@ url = https://github.com/MrCyjaneK/wownero-seed branch = cyjan-namespace2 shallow = true +[submodule "salvium"] + path = salvium + url = https://github.com/salvium/salvium + branch = rebase-v0.18 diff --git a/apply_patches.sh b/apply_patches.sh index 8013c9d..dc20d67 100755 --- a/apply_patches.sh +++ b/apply_patches.sh @@ -6,14 +6,14 @@ repo="$1" if [[ "x$repo" == "x" ]]; then - echo "Usage: $0 monero/wownero" + echo "Usage: $0 monero/wownero/zano/salvium" exit 1 fi -if [[ "x$repo" != "xwownero" && "x$repo" != "xmonero" ]]; +if [[ "x$repo" != "xwownero" && "x$repo" != "xmonero" && "x$repo" != "xzano" && "x$repo" != "xsalvium" ]]; then - echo "Usage: $0 monero/wownero" - echo "Invalid target given, only monero and wownero are supported targets" + echo "Usage: $0 monero/wownero/zano/salvium" + echo "Invalid target given, only monero, wownero,zano, and salvium are supported targets" fi if [[ ! -d "$repo" ]] diff --git a/build_single.sh b/build_single.sh index c0ace0d..9e5545f 100755 --- a/build_single.sh +++ b/build_single.sh @@ -20,13 +20,13 @@ set -e repo=$1 if [[ "x$repo" == "x" ]]; then - echo "Usage: $0 monero/wownero/zano $(gcc -dumpmachine) -j$proccount" + echo "Usage: $0 monero/wownero/zano/salvium $(gcc -dumpmachine) -j$proccount" exit 1 fi -if [[ "x$repo" != "xwownero" && "x$repo" != "xmonero" && "x$repo" != "xzano" ]]; +if [[ "x$repo" != "xwownero" && "x$repo" != "xmonero" && "x$repo" != "xzano" && "x$repo" != "xsalvium" ]]; then - echo "Usage: $0 monero/wownero/zano $(gcc -dumpmachine) -j$proccount" + echo "Usage: $0 monero/wownero/zano/salvium $(gcc -dumpmachine) -j$proccount" echo "Invalid target given" exit 1 fi @@ -41,7 +41,7 @@ fi HOST_ABI="$2" if [[ "x$HOST_ABI" == "x" ]]; then - echo "Usage: $0 monero/wownero $(gcc -dumpmachine) -j$proccount" + echo "Usage: $0 monero/wownero/zano/salvium $(gcc -dumpmachine) -j$proccount" exit 1 fi @@ -49,7 +49,7 @@ NPROC="$3" if [[ "x$NPROC" == "x" ]]; then - echo "Usage: $0 monero/wownero $(gcc -dumpmachine) -j$proccount" + echo "Usage: $0 monero/wownero/zano/salvium $(gcc -dumpmachine) -j$proccount" exit 1 fi cd $(dirname $0) diff --git a/patches/salvium/0001-fix-missing-___clear_cache-when-targetting-iOS.patch b/patches/salvium/0001-fix-missing-___clear_cache-when-targetting-iOS.patch new file mode 100644 index 0000000..d8d3dca --- /dev/null +++ b/patches/salvium/0001-fix-missing-___clear_cache-when-targetting-iOS.patch @@ -0,0 +1,34 @@ +From 6e284a2ef552f1f47e8ca9edcf8651312c9e37dd Mon Sep 17 00:00:00 2001 +From: Czarek Nakamoto +Date: Tue, 2 Apr 2024 16:51:56 +0200 +Subject: [PATCH 01/14] fix missing ___clear_cache when targetting iOS + +--- + .gitmodules | 3 ++- + external/randomx | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/.gitmodules b/.gitmodules +index 721cce3b4..ffb73fe9a 100644 +--- a/.gitmodules ++++ b/.gitmodules +@@ -9,7 +9,8 @@ + url = https://github.com/trezor/trezor-common.git + [submodule "external/randomx"] + path = external/randomx +- url = https://github.com/tevador/RandomX ++ url = https://github.com/MrCyjaneK/RandomX ++ branch = cyjan-fix-ios + [submodule "external/supercop"] + path = external/supercop + url = https://github.com/monero-project/supercop +diff --git a/external/randomx b/external/randomx +index 102f8acf9..ce72c9bb9 160000 +--- a/external/randomx ++++ b/external/randomx +@@ -1 +1 @@ +-Subproject commit 102f8acf90a7649ada410de5499a7ec62e49e1da ++Subproject commit ce72c9bb9cb799e0d9171094b9abb009e04c5bfc +-- +2.48.1 + diff --git a/patches/salvium/0002-store-crash-fix.patch b/patches/salvium/0002-store-crash-fix.patch new file mode 100644 index 0000000..5a2c16a --- /dev/null +++ b/patches/salvium/0002-store-crash-fix.patch @@ -0,0 +1,208 @@ +From b4f4b38af1ab974872862fc20735e41941b955e9 Mon Sep 17 00:00:00 2001 +From: Czarek Nakamoto +Date: Sat, 11 May 2024 16:25:10 +0200 +Subject: [PATCH 02/14] store crash fix + +Monero wallet crashes (sometimes) when it is syncing, +while the proper solution (that can be seen in feather) +is to not store wallet while it is being synced, this is not +acceptable for mobile wallets where OS can just come +and kill the wallet because it felt like it. + +This patch depends on the background-sync patch, but +to use it as a standalone fix grabbing the definition for the +LOCK_REFRESH macro should be enough. + +tobtoht suggested: +_say you want to store every 15 minutes during background sync. you stop the refresh every 15 minutes. then do something like this in the callback:_ + +``` +// Make sure this doesn't run in the refresh thread +onRefreshed() { + if (hasItBeen15MinutesSinceWeStored()) { + store(); + } + + if (shouldWeContinueRefreshing()) { + startRefresh(); + } +} +``` + +which works for crashes after the wallet is initially synced +but doesn't solve the issue for wallet that are syncing (it +would just wait for it to finish before actually storing). + +Also imo store() functin should store the wallet, no matter +the current state. +--- + src/wallet/api/wallet.cpp | 25 ++++++++++++------------- + src/wallet/api/wallet.h | 1 - + src/wallet/wallet2.cpp | 11 ++++++++++- + src/wallet/wallet2.h | 3 +++ + 4 files changed, 25 insertions(+), 15 deletions(-) + +diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp +index 8fda0bab7..67b170e3d 100644 +--- a/src/wallet/api/wallet.cpp ++++ b/src/wallet/api/wallet.cpp +@@ -55,8 +55,8 @@ using namespace cryptonote; + #define MONERO_DEFAULT_LOG_CATEGORY "WalletAPI" + + #define LOCK_REFRESH() \ +- bool refresh_enabled = m_refreshEnabled; \ +- m_refreshEnabled = false; \ ++ bool refresh_enabled = m_wallet->get_refresh_enabled(); \ ++ m_wallet->set_refresh_enabled(false); \ + m_wallet->stop(); \ + m_refreshCV.notify_one(); \ + boost::mutex::scoped_lock lock(m_refreshMutex); \ +@@ -466,7 +466,7 @@ WalletImpl::WalletImpl(NetworkType nettype, uint64_t kdf_rounds) + m_wallet2Callback.reset(new Wallet2CallbackImpl(this)); + m_wallet->callback(m_wallet2Callback.get()); + m_refreshThreadDone = false; +- m_refreshEnabled = false; ++ m_wallet->set_refresh_enabled(false); + m_addressBook.reset(new AddressBookImpl(this)); + m_subaddress.reset(new SubaddressImpl(this)); + m_subaddressAccount.reset(new SubaddressAccountImpl(this)); +@@ -962,6 +962,7 @@ void WalletImpl::stop() + bool WalletImpl::store(const std::string &path) + { + clearStatus(); ++ LOCK_REFRESH(); + try { + if (path.empty()) { + m_wallet->store(); +@@ -2448,10 +2449,10 @@ void WalletImpl::refreshThreadFunc() + } + + LOG_PRINT_L3(__FUNCTION__ << ": refresh lock acquired..."); +- LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_refreshEnabled); ++ LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_wallet->get_refresh_enabled()); + LOG_PRINT_L3(__FUNCTION__ << ": m_status: " << status()); + LOG_PRINT_L3(__FUNCTION__ << ": m_refreshShouldRescan: " << m_refreshShouldRescan); +- if (m_refreshEnabled) { ++ if (m_wallet->get_refresh_enabled()) { + LOG_PRINT_L3(__FUNCTION__ << ": refreshing..."); + doRefresh(); + } +@@ -2481,12 +2482,12 @@ void WalletImpl::doRefresh() + } + m_wallet->find_and_save_rings(false); + } else { +- LOG_PRINT_L3(__FUNCTION__ << ": skipping refresh - daemon is not synced"); ++ LOG_PRINT_L3(__FUNCTION__ << ": skipping refresh - daemon is not synced"); + } + } catch (const std::exception &e) { + setStatusError(e.what()); + break; +- }while(!rescan && (rescan=m_refreshShouldRescan.exchange(false))); // repeat if not rescanned and rescan was requested ++ }while(m_wallet->get_refresh_enabled() && !rescan && (rescan=m_refreshShouldRescan.exchange(false))); // repeat if not rescanned and rescan was requested + + if (m_wallet2Callback->getListener()) { + m_wallet2Callback->getListener()->refreshed(); +@@ -2496,9 +2497,9 @@ void WalletImpl::doRefresh() + + void WalletImpl::startRefresh() + { +- if (!m_refreshEnabled) { ++ if (!m_wallet->get_refresh_enabled()) { + LOG_PRINT_L2(__FUNCTION__ << ": refresh started/resumed..."); +- m_refreshEnabled = true; ++ m_wallet->set_refresh_enabled(true); + m_refreshCV.notify_one(); + } + } +@@ -2508,7 +2509,7 @@ void WalletImpl::startRefresh() + void WalletImpl::stopRefresh() + { + if (!m_refreshThreadDone) { +- m_refreshEnabled = false; ++ m_wallet->set_refresh_enabled(false); + m_refreshThreadDone = true; + m_refreshCV.notify_one(); + m_refreshThread.join(); +@@ -2519,9 +2520,7 @@ void WalletImpl::pauseRefresh() + { + LOG_PRINT_L2(__FUNCTION__ << ": refresh paused..."); + // TODO synchronize access +- if (!m_refreshThreadDone) { +- m_refreshEnabled = false; +- } ++ m_wallet->set_refresh_enabled(false); + } + + +diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h +index 1f199a72c..ac7ce2f6a 100644 +--- a/src/wallet/api/wallet.h ++++ b/src/wallet/api/wallet.h +@@ -273,7 +273,6 @@ private: + std::unique_ptr m_subaddressAccount; + + // multi-threaded refresh stuff +- std::atomic m_refreshEnabled; + std::atomic m_refreshThreadDone; + std::atomic m_refreshIntervalMillis; + std::atomic m_refreshShouldRescan; +diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp +index dfb8b23cb..c9c2dbc82 100644 +--- a/src/wallet/wallet2.cpp ++++ b/src/wallet/wallet2.cpp +@@ -1192,6 +1192,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std + m_upper_transaction_weight_limit(0), + m_run(true), + m_callback(0), ++ m_refreshEnabled(false), + m_trusted_daemon(false), + m_nettype(nettype), + m_multisig_rounds_passed(0), +@@ -1412,6 +1413,14 @@ bool wallet2::set_daemon(std::string daemon_address, boost::optionalset_proxy(address); +@@ -4107,7 +4116,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo + // infer when we get an incoming output + + bool first = true, last = false; +- while(m_run.load(std::memory_order_relaxed) && blocks_fetched < max_blocks) ++ while(m_run.load(std::memory_order_relaxed) && blocks_fetched < max_blocks && m_refreshEnabled) + { + uint64_t next_blocks_start_height; + std::vector next_blocks; +diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h +index 2f4ad52f1..daad1e940 100644 +--- a/src/wallet/wallet2.h ++++ b/src/wallet/wallet2.h +@@ -1078,6 +1078,8 @@ private: + epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, + const std::string &proxy = ""); + bool set_proxy(const std::string &address); ++ bool get_refresh_enabled(); ++ void set_refresh_enabled(bool val); + + void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); } + +@@ -1989,6 +1991,7 @@ private: + + boost::recursive_mutex m_daemon_rpc_mutex; + ++ bool m_refreshEnabled; + bool m_trusted_daemon; + i_wallet2_callback* m_callback; + hw::device::device_type m_key_device_type; +-- +2.48.1 + diff --git a/patches/salvium/0003-uint64_t-missing-definition-fix.patch b/patches/salvium/0003-uint64_t-missing-definition-fix.patch new file mode 100644 index 0000000..1b6e305 --- /dev/null +++ b/patches/salvium/0003-uint64_t-missing-definition-fix.patch @@ -0,0 +1,25 @@ +From a74f616e3c1671a883182b0db1c6fc11a1242c01 Mon Sep 17 00:00:00 2001 +From: Czarek Nakamoto +Date: Mon, 2 Sep 2024 16:40:31 +0200 +Subject: [PATCH 03/14] uint64_t missing definition fix + +--- + contrib/epee/include/net/http_base.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/contrib/epee/include/net/http_base.h b/contrib/epee/include/net/http_base.h +index 4af4da790..ae4c0d05e 100644 +--- a/contrib/epee/include/net/http_base.h ++++ b/contrib/epee/include/net/http_base.h +@@ -28,7 +28,7 @@ + + #pragma once + #include "memwipe.h" +- ++#include + #include + + #include +-- +2.48.1 + diff --git a/patches/salvium/0004-use-proper-error-handling-in-get_seed.patch b/patches/salvium/0004-use-proper-error-handling-in-get_seed.patch new file mode 100644 index 0000000..33207f3 --- /dev/null +++ b/patches/salvium/0004-use-proper-error-handling-in-get_seed.patch @@ -0,0 +1,71 @@ +From f9b222f1611d7cfbaf0ac52cd6194724c7554def Mon Sep 17 00:00:00 2001 +From: Czarek Nakamoto +Date: Mon, 24 Jun 2024 10:49:12 +0200 +Subject: [PATCH 04/14] use proper error handling in get_seed + +--- + src/wallet/api/wallet.cpp | 17 ++++++++++++----- + src/wallet/wallet2.cpp | 5 ++++- + 2 files changed, 16 insertions(+), 6 deletions(-) + +diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp +index 67b170e3d..89df5c517 100644 +--- a/src/wallet/api/wallet.cpp ++++ b/src/wallet/api/wallet.cpp +@@ -826,12 +826,19 @@ bool WalletImpl::close(bool store) + + std::string WalletImpl::seed(const std::string& seed_offset) const + { +- if (checkBackgroundSync("cannot get seed")) ++ if (checkBackgroundSync("cannot get seed")) { ++ setStatusError("cannot get seed"); + return std::string(); +- epee::wipeable_string seed; +- if (m_wallet) +- m_wallet->get_seed(seed, seed_offset); +- return std::string(seed.data(), seed.size()); // TODO ++ } ++ try { ++ epee::wipeable_string seed; ++ if (m_wallet) ++ m_wallet->get_seed(seed, seed_offset); ++ return std::string(seed.data(), seed.size()); // TODO ++ } catch (const std::exception &e) { ++ setStatusError(e.what()); ++ return std::string(); ++ } + } + + std::string WalletImpl::getSeedLanguage() const +diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp +index c9c2dbc82..b827b826f 100644 +--- a/src/wallet/wallet2.cpp ++++ b/src/wallet/wallet2.cpp +@@ -1449,11 +1449,13 @@ bool wallet2::get_seed(epee::wipeable_string& electrum_words, const epee::wipeab + bool keys_deterministic = is_deterministic(); + if (!keys_deterministic) + { ++ THROW_WALLET_EXCEPTION(error::wallet_internal_error, "This is not a deterministic wallet"); + std::cout << "This is not a deterministic wallet" << std::endl; + return false; + } + if (seed_language.empty()) + { ++ THROW_WALLET_EXCEPTION(error::wallet_internal_error, "seed_language not set"); + std::cout << "seed_language not set" << std::endl; + return false; + } +@@ -1463,8 +1465,9 @@ bool wallet2::get_seed(epee::wipeable_string& electrum_words, const epee::wipeab + key = cryptonote::encrypt_key(key, passphrase); + if (!crypto::ElectrumWords::bytes_to_words(key, electrum_words, seed_language)) + { ++ THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Failed to create seed from key for language: "+seed_language+", falling back to English."); + std::cout << "Failed to create seed from key for language: " << seed_language << std::endl; +- return false; ++ crypto::ElectrumWords::bytes_to_words(key, electrum_words, "English"); + } + + return true; +-- +2.48.1 + diff --git a/patches/salvium/0005-UR-functions.patch b/patches/salvium/0005-UR-functions.patch new file mode 100644 index 0000000..c3cca26 --- /dev/null +++ b/patches/salvium/0005-UR-functions.patch @@ -0,0 +1,1010 @@ +From ff70c74c8b331758ace1f14df0ca107731dda49d Mon Sep 17 00:00:00 2001 +From: tobtoht +Date: Tue, 12 Mar 2024 10:09:50 +0100 +Subject: [PATCH 05/14] UR functions + +This commit adds UR functions for UR tasks, +I believe that the right place to get +UR strings is the wallet code itself, +especially because it allows us to +skip the part when we have to store +things to file to encode them later. +Now we are fully in memory + +Things broken in the commit +- ledger support. + AUTO_LOCK_CMD macro causes compile time + issues with this patch. I don't know why + just yet, this is a issue that I'll fix + later. However (considering the purpose + of this patch) it is not a dealbreaker. +--- + .gitmodules | 4 + + CMakeLists.txt | 4 +- + external/CMakeLists.txt | 1 + + external/bc-ur | 1 + + src/device/device_ledger.cpp | 5 +- + src/wallet/CMakeLists.txt | 1 + + src/wallet/api/pending_transaction.cpp | 33 +++ + src/wallet/api/pending_transaction.h | 1 + + src/wallet/api/unsigned_transaction.cpp | 42 ++++ + src/wallet/api/unsigned_transaction.h | 1 + + src/wallet/api/wallet.cpp | 309 +++++++++++++++++++++++- + src/wallet/api/wallet.h | 8 + + src/wallet/api/wallet2_api.h | 22 +- + src/wallet/wallet2.cpp | 141 +++++++---- + src/wallet/wallet2.h | 3 + + 15 files changed, 519 insertions(+), 57 deletions(-) + create mode 160000 external/bc-ur + +diff --git a/.gitmodules b/.gitmodules +index ffb73fe9a..72af74d55 100644 +--- a/.gitmodules ++++ b/.gitmodules +@@ -15,3 +15,7 @@ + path = external/supercop + url = https://github.com/monero-project/supercop + branch = monero ++[submodule "external/bc-ur"] ++ path = external/bc-ur ++ url = https://github.com/MrCyjaneK/bc-ur ++ branch = misc +diff --git a/CMakeLists.txt b/CMakeLists.txt +index db69b1b04..c73b813d8 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -96,7 +96,8 @@ enable_language(C ASM) + set(CMAKE_C_STANDARD 11) + set(CMAKE_C_STANDARD_REQUIRED ON) + set(CMAKE_C_EXTENSIONS OFF) +-set(CMAKE_CXX_STANDARD 14) ++set(CMAKE_CXX_STANDARD 17) ++add_definitions(-D_LIBCPP_ENABLE_CXX17_REMOVED_FEATURES) # boost: no template named 'unary_function' in namespace 'std'; did you mean '__unary_function'? + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) + +@@ -364,6 +365,7 @@ if(NOT MANUAL_SUBMODULES) + endfunction () + + message(STATUS "Checking submodules") ++# check_submodule(external/bc-ur) + check_submodule(external/miniupnp) + check_submodule(external/rapidjson) + check_submodule(external/trezor-common) +diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt +index 538e4d215..074e23f16 100644 +--- a/external/CMakeLists.txt ++++ b/external/CMakeLists.txt +@@ -70,4 +70,5 @@ endif() + add_subdirectory(db_drivers) + add_subdirectory(easylogging++) + add_subdirectory(qrcodegen) ++add_subdirectory(bc-ur) + add_subdirectory(randomx EXCLUDE_FROM_ALL) +diff --git a/external/bc-ur b/external/bc-ur +new file mode 160000 +index 000000000..d82e7c753 +--- /dev/null ++++ b/external/bc-ur +@@ -0,0 +1 @@ ++Subproject commit d82e7c753e710b8000706dc3383b498438795208 +diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp +index 5d0afe1ee..bb5b6f497 100644 +--- a/src/device/device_ledger.cpp ++++ b/src/device/device_ledger.cpp +@@ -313,12 +313,13 @@ namespace hw { + + /* ======================================================================= */ + /* LOCKER */ +- /* ======================================================================= */ ++ /* ======================================================================= */ + + //automatic lock one more level on device ensuring the current thread is allowed to use it ++ #pragma message ("Warning AUTO_LOCK_CMD is intentionally left broken. This is yet to be fixed.") + #define AUTO_LOCK_CMD() \ + /* lock both mutexes without deadlock*/ \ +- boost::lock(device_locker, command_locker); \ ++ /* boost::lock(device_locker, command_locker); */ \ + /* make sure both already-locked mutexes are unlocked at the end of scope */ \ + boost::lock_guard lock1(device_locker, boost::adopt_lock); \ + boost::lock_guard lock2(command_locker, boost::adopt_lock) +diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt +index 6095f99d5..b163212b7 100644 +--- a/src/wallet/CMakeLists.txt ++++ b/src/wallet/CMakeLists.txt +@@ -50,6 +50,7 @@ monero_add_library(wallet + target_link_libraries(wallet + PUBLIC + rpc_base ++ bc-ur + multisig + common + cryptonote_core +diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp +index 70a702796..9c3c26ee5 100644 +--- a/src/wallet/api/pending_transaction.cpp ++++ b/src/wallet/api/pending_transaction.cpp +@@ -42,6 +42,8 @@ + #include + #include + ++#include "bc-ur/src/bc-ur.hpp" ++ + using namespace std; + + namespace Monero { +@@ -162,6 +164,37 @@ bool PendingTransactionImpl::commit(const std::string &filename, bool overwrite) + return m_status == Status_Ok; + } + ++std::string PendingTransactionImpl::commitUR(int max_fragment_length) { ++ ++ LOG_PRINT_L3("m_pending_tx size: " << m_pending_tx.size()); ++ ++ try { ++ std::string ptx = m_wallet.m_wallet->dump_tx_to_str(m_pending_tx); ++ m_status = Status_Ok; ++ auto urMessage = ur::string_to_bytes(ptx); ++ ur::ByteVector cbor; ++ ur::CborLite::encodeBytes(cbor, urMessage); ++ std::string type; ++ if (m_wallet.watchOnly()) { ++ type = "xmr-txunsigned"; ++ } else { ++ type = "xmr-txsigned"; ++ } ++ ur::UR urData = ur::UR(type, cbor); ++ auto encoder = ur::UREncoder(urData, max_fragment_length); ++ std::string output; ++ for(size_t i = 0; i < encoder.seq_len(); i++) { ++ output.append("\n"+encoder.next_part()); ++ } ++ return output; ++ } catch (const std::exception &e) { ++ m_errorString = string(tr("Unknown exception: ")) + e.what(); ++ m_status = Status_Error; ++ return ""; ++ } ++} ++ ++ + uint64_t PendingTransactionImpl::amount() const + { + uint64_t result = 0; +diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h +index 0a9779c07..403bfe281 100644 +--- a/src/wallet/api/pending_transaction.h ++++ b/src/wallet/api/pending_transaction.h +@@ -46,6 +46,7 @@ public: + int status() const override; + std::string errorString() const override; + bool commit(const std::string &filename = "", bool overwrite = false) override; ++ std::string commitUR(int max_fragment_length = 130) override; + uint64_t amount() const override; + uint64_t dust() const override; + uint64_t fee() const override; +diff --git a/src/wallet/api/unsigned_transaction.cpp b/src/wallet/api/unsigned_transaction.cpp +index 6165a2240..fd03e959d 100644 +--- a/src/wallet/api/unsigned_transaction.cpp ++++ b/src/wallet/api/unsigned_transaction.cpp +@@ -40,6 +40,8 @@ + #include + #include + ++#include "bc-ur/src/bc-ur.hpp" ++ + using namespace std; + + namespace Monero { +@@ -96,6 +98,46 @@ bool UnsignedTransactionImpl::sign(const std::string &signedFileName) + return true; + } + ++std::string UnsignedTransactionImpl::signUR(int max_fragment_length) ++{ ++ if(m_wallet.watchOnly()) ++ { ++ m_errorString = tr("This is a watch only wallet"); ++ m_status = Status_Error; ++ return ""; ++ } ++ std::vector ptx; ++ try ++ { ++ tools::wallet2::signed_tx_set signed_txes; ++ std::string signedTx = m_wallet.m_wallet->sign_tx_dump_to_str(m_unsigned_tx_set, ptx, signed_txes); ++ if (signedTx.empty()) ++ { ++ m_errorString = tr("Failed to sign transaction"); ++ m_status = Status_Error; ++ return ""; ++ } ++ auto urMessage = ur::string_to_bytes(signedTx); ++ ur::ByteVector cbor; ++ ur::CborLite::encodeBytes(cbor, urMessage); ++ std::string type = "xmr-txsigned"; ++ ur::UR urData = ur::UR(type, cbor); ++ auto encoder = ur::UREncoder(urData, max_fragment_length); ++ std::string output; ++ for(size_t i = 0; i < encoder.seq_len(); i++) { ++ output.append("\n"+encoder.next_part()); ++ } ++ return output; ++ } ++ catch (const std::exception &e) ++ { ++ m_errorString = string(tr("Failed to sign transaction")) + e.what(); ++ m_status = Status_Error; ++ return ""; ++ } ++ return ""; ++} ++ + //---------------------------------------------------------------------------------------------------- + bool UnsignedTransactionImpl::checkLoadedTx(const std::function get_num_txes, const std::function &get_tx, const std::string &extra_message) + { +diff --git a/src/wallet/api/unsigned_transaction.h b/src/wallet/api/unsigned_transaction.h +index 30065a7fa..a94b23f75 100644 +--- a/src/wallet/api/unsigned_transaction.h ++++ b/src/wallet/api/unsigned_transaction.h +@@ -53,6 +53,7 @@ public: + uint64_t txCount() const override; + // sign txs and save to file + bool sign(const std::string &signedFileName) override; ++ std::string signUR(int max_fragment_length = 130) override; + std::string confirmationMessage() const override {return m_confirmationMessage;} + uint64_t minMixinCount() const override; + +diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp +index 89df5c517..3fcd6f332 100644 +--- a/src/wallet/api/wallet.cpp ++++ b/src/wallet/api/wallet.cpp +@@ -47,6 +47,7 @@ + + #include + #include ++#include "bc-ur/src/bc-ur.hpp" + + using namespace std; + using namespace cryptonote; +@@ -1066,6 +1067,24 @@ uint64_t WalletImpl::unlockedBalance(uint32_t accountIndex) const + return m_wallet->unlocked_balance(accountIndex, false); + } + ++uint64_t WalletImpl::viewOnlyBalance(uint32_t accountIndex, const std::vector &key_images) const ++{ ++ clearStatus(); ++ ++ std::vector kis; ++ for (const auto &key_image : key_images) { ++ crypto::key_image ki; ++ if (!epee::string_tools::hex_to_pod(key_image, ki)) ++ { ++ setStatusError(tr("failed to parse key image")); ++ return 0; ++ } ++ kis.push_back(ki); ++ } ++ ++ return m_wallet->view_only_balance(accountIndex, kis); ++} ++ + uint64_t WalletImpl::blockChainHeight() const + { + if(m_wallet->light_wallet()) { +@@ -1208,6 +1227,61 @@ UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_file + return transaction; + } + ++ ++UnsignedTransaction *WalletImpl::loadUnsignedTxUR(const std::string &input) { ++ clearStatus(); ++ UnsignedTransactionImpl * transaction = new UnsignedTransactionImpl(*this); ++ auto decoder = ur::URDecoder(); ++ ++ std::string delimiter = "\n"; ++ std::string inp = input; ++ size_t pos = 0; ++ std::string token; ++ while ((pos = inp.find(delimiter)) != std::string::npos) { ++ token = inp.substr(0, pos); ++ decoder.receive_part(token); ++ inp.erase(0, pos + delimiter.length()); ++ } ++ decoder.receive_part(inp); ++ ++ if (decoder.is_failure()) { ++ setStatusError(decoder.result_error().what()); ++ transaction->m_status = UnsignedTransaction::Status::Status_Error; ++ transaction->m_errorString = errorString(); ++ return transaction; ++ } ++ ++ if (!decoder.is_complete()) { ++ setStatusError("file ended but ur didn't complete"); ++ transaction->m_status = UnsignedTransaction::Status::Status_Error; ++ transaction->m_errorString = errorString(); ++ return transaction; ++ } ++ ++ std::string data; ++ auto cbor = decoder.result_ur().cbor(); ++ auto i = cbor.begin(); ++ auto end = cbor.end(); ++ ur::CborLite::decodeBytes(i, end, data); ++ ++ if (checkBackgroundSync("cannot load tx") || !m_wallet->parse_unsigned_tx_from_str(data, transaction->m_unsigned_tx_set)){ ++ setStatusError(tr("Failed to load unsigned transactions")); ++ transaction->m_status = UnsignedTransaction::Status::Status_Error; ++ transaction->m_errorString = errorString(); ++ ++ return transaction; ++ } ++ ++ // Check tx data and construct confirmation message ++ std::string extra_message; ++ if (!std::get<2>(transaction->m_unsigned_tx_set.transfers).empty()) ++ extra_message = (boost::format("%u outputs to import. ") % (unsigned)std::get<2>(transaction->m_unsigned_tx_set.transfers).size()).str(); ++ transaction->checkLoadedTx([&transaction](){return transaction->m_unsigned_tx_set.txes.size();}, [&transaction](size_t n)->const tools::wallet2::tx_construction_data&{return transaction->m_unsigned_tx_set.txes[n];}, extra_message); ++ setStatus(transaction->status(), transaction->errorString()); ++ ++ return transaction; ++} ++ + bool WalletImpl::submitTransaction(const string &fileName) { + clearStatus(); + if (checkBackgroundSync("cannot submit tx")) +@@ -1219,7 +1293,7 @@ bool WalletImpl::submitTransaction(const string &fileName) { + setStatus(Status_Ok, tr("Failed to load transaction from file")); + return false; + } +- ++ + if(!transaction->commit()) { + setStatusError(transaction->m_errorString); + return false; +@@ -1228,6 +1302,61 @@ bool WalletImpl::submitTransaction(const string &fileName) { + return true; + } + ++ ++bool WalletImpl::submitTransactionUR(const string &input) { ++ clearStatus(); ++ auto decoder = ur::URDecoder(); ++ ++ std::string delimiter = "\n"; ++ std::string inp = input; ++ size_t pos = 0; ++ std::string token; ++ while ((pos = inp.find(delimiter)) != std::string::npos) { ++ token = inp.substr(0, pos); ++ decoder.receive_part(token); ++ inp.erase(0, pos + delimiter.length()); ++ } ++ decoder.receive_part(inp); ++ ++ if (decoder.is_failure()) { ++ setStatusError(decoder.result_error().what()); ++ return false; ++ } ++ ++ if (!decoder.is_complete()) { ++ setStatusError("file ended but ur didn't complete"); ++ return false; ++ } ++ ++ std::string data; ++ auto cbor = decoder.result_ur().cbor(); ++ auto i = cbor.begin(); ++ auto end = cbor.end(); ++ ur::CborLite::decodeBytes(i, end, data); ++ if (checkBackgroundSync("cannot submit tx")) ++ return false; ++ std::unique_ptr transaction(new PendingTransactionImpl(*this)); ++ ++ bool r = m_wallet->parse_tx_from_str(data, transaction->m_pending_tx, NULL); ++ if (!r) { ++ setStatus(Status_Ok, tr("Failed to load transaction from file")); ++ return false; ++ } ++ ++ if(!transaction->commit()) { ++ setStatusError(transaction->m_errorString); ++ return false; ++ } ++ ++ return true; ++} ++ ++ ++bool WalletImpl::hasUnknownKeyImages() const ++{ ++ return m_wallet->has_unknown_key_images(); ++} ++ + bool WalletImpl::exportKeyImages(const string &filename, bool all) + { + if (m_wallet->watch_only()) +@@ -1255,6 +1384,39 @@ bool WalletImpl::exportKeyImages(const string &filename, bool all) + return true; + } + ++std::string WalletImpl::exportKeyImagesUR(size_t max_fragment_length, bool all) ++{ ++ if (m_wallet->watch_only()) ++ { ++ setStatusError(tr("Wallet is view only")); ++ return ""; ++ } ++ if (checkBackgroundSync("cannot export key images")) ++ return ""; ++ ++ try ++ { ++ std::string keyImages = m_wallet->export_key_images_str(all); ++ auto urMessage = ur::string_to_bytes(keyImages); ++ ur::ByteVector cbor; ++ ur::CborLite::encodeBytes(cbor, urMessage); ++ ur::UR urData = ur::UR("xmr-keyimage", cbor); ++ auto encoder = ur::UREncoder(urData, max_fragment_length); ++ std::string output; ++ for(size_t i = 0; i < encoder.seq_len(); i++) { ++ output.append("\n"+encoder.next_part()); ++ } ++ return output; ++ } ++ catch (const std::exception &e) ++ { ++ LOG_ERROR("Error exporting key images: " << e.what()); ++ setStatusError(e.what()); ++ return ""; ++ } ++ return ""; ++} ++ + bool WalletImpl::importKeyImages(const string &filename) + { + if (checkBackgroundSync("cannot import key images")) +@@ -1280,6 +1442,62 @@ bool WalletImpl::importKeyImages(const string &filename) + return true; + } + ++ ++bool WalletImpl::importKeyImagesUR(const string &input) ++{ ++ if (checkBackgroundSync("cannot import key images")) ++ return false; ++ if (!trustedDaemon()) { ++ setStatusError(tr("Key images can only be imported with a trusted daemon")); ++ return false; ++ } ++ try ++ { ++ auto decoder = ur::URDecoder(); ++ std::string delimiter = "\n"; ++ std::string inp = input; ++ size_t pos = 0; ++ std::string token; ++ while ((pos = inp.find(delimiter)) != std::string::npos) { ++ token = inp.substr(0, pos); ++ decoder.receive_part(token); ++ inp.erase(0, pos + delimiter.length()); ++ } ++ decoder.receive_part(inp); ++ ++ if (decoder.is_failure()) { ++ setStatusError(decoder.result_error().what()); ++ return false; ++ } ++ ++ if (!decoder.is_complete()) { ++ setStatusError("file ended but ur didn't complete"); ++ return false; ++ } ++ ++ std::string data; ++ auto cbor = decoder.result_ur().cbor(); ++ auto i = cbor.begin(); ++ auto end = cbor.end(); ++ ur::CborLite::decodeBytes(i, end, data); ++ ++ uint64_t spent = 0, unspent = 0; ++ ++ uint64_t height = m_wallet->import_key_images_str(data, spent, unspent); ++ LOG_PRINT_L2("Signed key images imported to height " << height << ", " ++ << print_money(spent) << " spent, " << print_money(unspent) << " unspent"); ++ } ++ catch (const std::exception &e) ++ { ++ LOG_ERROR("Error exporting key images: " << e.what()); ++ setStatusError(string(tr("Failed to import key images: ")) + e.what()); ++ return false; ++ } ++ ++ return true; ++} ++ ++ + bool WalletImpl::exportOutputs(const string &filename, bool all) + { + if (checkBackgroundSync("cannot export outputs")) +@@ -1312,6 +1530,40 @@ bool WalletImpl::exportOutputs(const string &filename, bool all) + return true; + } + ++std::string WalletImpl::exportOutputsUR(size_t max_fragment_length, bool all) ++{ ++ ++ if (checkBackgroundSync("cannot export outputs")) ++ return ""; ++ if (m_wallet->key_on_device()) ++ { ++ setStatusError(string(tr("Not supported on HW wallets."))); ++ return ""; ++ } ++ ++ try ++ { ++ std::string data = m_wallet->export_outputs_to_str(all); ++ auto urMessage = ur::string_to_bytes(data); ++ ur::ByteVector cbor; ++ ur::CborLite::encodeBytes(cbor, urMessage); ++ ur::UR urData = ur::UR("xmr-output", cbor); ++ auto encoder = ur::UREncoder(urData, max_fragment_length); ++ std::string output; ++ for(size_t i = 0; i < encoder.seq_len(); i++) { ++ output.append("\n"+encoder.next_part()); ++ } ++ return output; ++ } ++ catch (const std::exception &e) ++ { ++ LOG_ERROR("Error exporting outputs: " << e.what()); ++ setStatusError(string(tr("Error exporting outputs: ")) + e.what()); ++ return ""; ++ } ++} ++ ++ + bool WalletImpl::importOutputs(const string &filename) + { + if (checkBackgroundSync("cannot import outputs")) +@@ -1346,6 +1598,61 @@ bool WalletImpl::importOutputs(const string &filename) + return true; + } + ++ ++bool WalletImpl::importOutputsUR(const string &input) ++{ ++ if (checkBackgroundSync("cannot import outputs")) ++ return false; ++ if (m_wallet->key_on_device()) ++ { ++ setStatusError(string(tr("Not supported on HW wallets."))); ++ return false; ++ } ++ ++ try ++ { ++ auto decoder = ur::URDecoder(); ++ ++ std::string delimiter = "\n"; ++ std::string inp = input; ++ size_t pos = 0; ++ std::string token; ++ while ((pos = inp.find(delimiter)) != std::string::npos) { ++ token = inp.substr(0, pos); ++ decoder.receive_part(token); ++ inp.erase(0, pos + delimiter.length()); ++ } ++ decoder.receive_part(inp); ++ ++ if (decoder.is_failure()) { ++ setStatusError(decoder.result_error().what()); ++ return false; ++ } ++ ++ if (!decoder.is_complete()) { ++ setStatusError("file ended but ur didn't complete"); ++ return false; ++ } ++ ++ std::string data; ++ auto cbor = decoder.result_ur().cbor(); ++ auto i = cbor.begin(); ++ auto end = cbor.end(); ++ ur::CborLite::decodeBytes(i, end, data); ++ size_t n_outputs = m_wallet->import_outputs_from_str(std::string(data)); ++ LOG_PRINT_L2(std::to_string(n_outputs) << " outputs imported"); ++ } ++ catch (const std::exception &e) ++ { ++ LOG_ERROR("Failed to import outputs: " << e.what()); ++ setStatusError(string(tr("Failed to import outputs: ")) + e.what()); ++ return false; ++ } ++ ++ return true; ++} ++ ++ + bool WalletImpl::scanTransactions(const std::vector &txids) + { + if (checkBackgroundSync("cannot scan transactions")) +diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h +index ac7ce2f6a..edf8bb8ce 100644 +--- a/src/wallet/api/wallet.h ++++ b/src/wallet/api/wallet.h +@@ -112,6 +112,7 @@ public: + bool setProxy(const std::string &address) override; + uint64_t balance(uint32_t accountIndex = 0) const override; + uint64_t unlockedBalance(uint32_t accountIndex = 0) const override; ++ uint64_t viewOnlyBalance(uint32_t accountIndex, const std::vector &key_images) const override; + uint64_t blockChainHeight() const override; + uint64_t approximateBlockChainHeight() const override; + uint64_t estimateBlockChainHeight() const override; +@@ -164,11 +165,18 @@ public: + std::set subaddr_indices = {}) override; + virtual PendingTransaction * createSweepUnmixableTransaction() override; + bool submitTransaction(const std::string &fileName) override; ++ bool submitTransactionUR(const std::string &input) override; + virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override; ++ virtual UnsignedTransaction * loadUnsignedTxUR(const std::string &input) override; ++ bool hasUnknownKeyImages() const override; + bool exportKeyImages(const std::string &filename, bool all = false) override; ++ std::string exportKeyImagesUR(size_t max_fragment_length, bool all = false) override; + bool importKeyImages(const std::string &filename) override; ++ bool importKeyImagesUR(const std::string &input) override; + bool exportOutputs(const std::string &filename, bool all = false) override; ++ std::string exportOutputsUR(size_t max_fragment_length, bool all) override; + bool importOutputs(const std::string &filename) override; ++ bool importOutputsUR(const std::string &filename) override; + bool scanTransactions(const std::vector &txids) override; + + bool setupBackgroundSync(const BackgroundSyncType background_sync_type, const std::string &wallet_password, const optional &background_cache_password = optional()) override; +diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h +index e349df176..764adbfbf 100644 +--- a/src/wallet/api/wallet2_api.h ++++ b/src/wallet/api/wallet2_api.h +@@ -91,6 +91,7 @@ struct PendingTransaction + virtual std::string errorString() const = 0; + // commit transaction or save to file if filename is provided. + virtual bool commit(const std::string &filename = "", bool overwrite = false) = 0; ++ virtual std::string commitUR(int max_fragment_length = 130) = 0; + virtual uint64_t amount() const = 0; + virtual uint64_t dust() const = 0; + virtual uint64_t fee() const = 0; +@@ -160,7 +161,8 @@ struct UnsignedTransaction + * @param signedFileName + * return - true on success + */ +- virtual bool sign(const std::string &signedFileName) = 0; ++ virtual bool sign(const std::string &signedFileName) = 0; ++ virtual std::string signUR(int max_fragment_length = 130) = 0; + }; + + /** +@@ -626,6 +628,7 @@ struct Wallet + result += unlockedBalance(i); + return result; + } ++ virtual uint64_t viewOnlyBalance(uint32_t accountIndex, const std::vector &key_images = {}) const = 0; + + /** + * @brief watchOnly - checks if wallet is watch only +@@ -884,13 +887,15 @@ struct Wallet + * after object returned + */ + virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) = 0; +- +- /*! ++ virtual UnsignedTransaction * loadUnsignedTxUR(const std::string &input) = 0; ++ ++ /*! + * \brief submitTransaction - submits transaction in signed tx file + * \return - true on success + */ + virtual bool submitTransaction(const std::string &fileName) = 0; +- ++ virtual bool submitTransactionUR(const std::string &input) = 0; ++ + + /*! + * \brief disposeTransaction - destroys transaction object +@@ -906,6 +911,8 @@ struct Wallet + virtual uint64_t estimateTransactionFee(const std::vector> &destinations, + PendingTransaction::Priority priority) const = 0; + ++ virtual bool hasUnknownKeyImages() const = 0; ++ + /*! + * \brief exportKeyImages - exports key images to file + * \param filename +@@ -913,20 +920,22 @@ struct Wallet + * \return - true on success + */ + virtual bool exportKeyImages(const std::string &filename, bool all = false) = 0; +- ++ virtual std::string exportKeyImagesUR(size_t max_fragment_length, bool all = false) = 0; + /*! + * \brief importKeyImages - imports key images from file + * \param filename + * \return - true on success + */ + virtual bool importKeyImages(const std::string &filename) = 0; ++ virtual bool importKeyImagesUR(const std::string &input) = 0; + + /*! +- * \brief importOutputs - exports outputs to file ++ * \brief exportOutputs - exports outputs to file + * \param filename + * \return - true on success + */ + virtual bool exportOutputs(const std::string &filename, bool all = false) = 0; ++ virtual std::string exportOutputsUR(size_t max_fragment_length, bool all = false) = 0; + + /*! + * \brief importOutputs - imports outputs from file +@@ -934,6 +943,7 @@ struct Wallet + * \return - true on success + */ + virtual bool importOutputs(const std::string &filename) = 0; ++ virtual bool importOutputsUR(const std::string &filename) = 0; + + /*! + * \brief scanTransactions - scan a list of transaction ids, this operation may reveal the txids to the remote node and affect your privacy +diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp +index b827b826f..765cefb32 100644 +--- a/src/wallet/wallet2.cpp ++++ b/src/wallet/wallet2.cpp +@@ -948,6 +948,16 @@ uint32_t get_subaddress_clamped_sum(uint32_t idx, uint32_t extra) + return idx + extra; + } + ++bool is_preferred_input(const std::vector& preferred_input_list, const crypto::key_image& input) { ++ if (!preferred_input_list.empty()) { ++ auto it = std::find(preferred_input_list.begin(), preferred_input_list.end(), input); ++ if (it == preferred_input_list.end()) { ++ return false; ++ } ++ } ++ return true; ++} ++ + static void setup_shim(hw::wallet_shim * shim, tools::wallet2 * wallet) + { + shim->get_tx_pub_key_from_received_outs = std::bind(&tools::wallet2::get_tx_pub_key_from_received_outs, wallet, std::placeholders::_1); +@@ -6997,6 +7007,25 @@ uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t * + return amount; + } + //---------------------------------------------------------------------------------------------------- ++uint64_t wallet2::view_only_balance(uint32_t index_major, const std::vector& selected_inputs) ++{ ++ uint64_t amount = 0; ++ for (const auto &td : m_transfers) { ++ if (is_preferred_input(selected_inputs, td.m_key_image) && ++ !is_spent(td, false) && ++ !td.m_frozen && ++ !td.m_key_image_partial && ++ td.m_key_image_known && ++ td.is_rct() && ++ is_transfer_unlocked(td) && ++ td.m_subaddr_index.major == index_major) ++ { ++ amount += td.m_amount; ++ } ++ } ++ return amount; ++} ++//---------------------------------------------------------------------------------------------------- + std::map wallet2::balance_per_subaddress(uint32_t index_major, bool strict) const + { + std::map amount_per_subaddr; +@@ -7848,9 +7877,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector additional_derivations; + +- // compute public keys from out secret keys +- crypto::public_key tx_pub_key; +- crypto::secret_key_to_public_key(txs[n].tx_key, tx_pub_key); ++ crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); + std::vector additional_tx_pub_keys; + for (const crypto::secret_key &skey: txs[n].additional_tx_keys) + { +@@ -11246,7 +11273,7 @@ std::vector wallet2::create_transactions_2(std::vector m_ignore_outputs_above || td.amount() < m_ignore_outputs_below) + { +@@ -11296,9 +11323,15 @@ std::vector wallet2::create_transactions_2(std::vector(); ++ // use tobotoht's code path on view-only wallet, otherwise default to upstream ++ bool throwOnNoEnotes = m_account.get_device().device_protocol() == hw::device::PROTOCOL_COLD || m_watch_only || m_multisig || m_is_background_wallet; + ++ if (throwOnNoEnotes) { ++ THROW_WALLET_EXCEPTION_IF(unused_dust_indices_per_subaddr.empty() && unused_transfers_indices_per_subaddr.empty(), error::wallet_internal_error, "No enotes available to spend") ++ } else { ++ if (unused_dust_indices_per_subaddr.empty() && unused_transfers_indices_per_subaddr.empty()) ++ return std::vector(); ++ } + // if empty, put dummy entry so that the front can be referenced later in the loop + if (unused_dust_indices_per_subaddr.empty()) + unused_dust_indices_per_subaddr.push_back({}); +@@ -13934,33 +13967,40 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle + + bool wallet2::export_key_images(const std::string &filename, bool all) const + { +- PERF_TIMER(export_key_images); +- std::pair>> ski = export_key_images(all); +- std::string magic(KEY_IMAGE_EXPORT_FILE_MAGIC, strlen(KEY_IMAGE_EXPORT_FILE_MAGIC)); +- const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address; +- const uint32_t offset = ski.first; ++ std::string data = export_key_images_str(all); ++ return save_to_file(filename, data); ++} + +- std::string data; +- data.reserve(4 + ski.second.size() * (sizeof(crypto::key_image) + sizeof(crypto::signature)) + 2 * sizeof(crypto::public_key)); +- data.resize(4); +- data[0] = offset & 0xff; +- data[1] = (offset >> 8) & 0xff; +- data[2] = (offset >> 16) & 0xff; +- data[3] = (offset >> 24) & 0xff; +- data += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key)); +- data += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key)); +- for (const auto &i: ski.second) +- { +- data += std::string((const char *)&i.first, sizeof(crypto::key_image)); +- data += std::string((const char *)&i.second, sizeof(crypto::signature)); +- } ++std::string wallet2::export_key_images_str(bool all) const ++{ ++ PERF_TIMER(export_key_images); ++ std::pair>> ski = export_key_images(all); ++ std::string magic(KEY_IMAGE_EXPORT_FILE_MAGIC, strlen(KEY_IMAGE_EXPORT_FILE_MAGIC)); ++ const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address; ++ const uint32_t offset = ski.first; + +- // encrypt data, keep magic plaintext +- PERF_TIMER(export_key_images_encrypt); +- std::string ciphertext = encrypt_with_view_secret_key(data); +- return save_to_file(filename, magic + ciphertext); ++ std::string data; ++ data.reserve(4 + ski.second.size() * (sizeof(crypto::key_image) + sizeof(crypto::signature)) + 2 * sizeof(crypto::public_key)); ++ data.resize(4); ++ data[0] = offset & 0xff; ++ data[1] = (offset >> 8) & 0xff; ++ data[2] = (offset >> 16) & 0xff; ++ data[3] = (offset >> 24) & 0xff; ++ data += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key)); ++ data += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key)); ++ for (const auto &i: ski.second) ++ { ++ data += std::string((const char *)&i.first, sizeof(crypto::key_image)); ++ data += std::string((const char *)&i.second, sizeof(crypto::signature)); ++ } ++ ++ // encrypt data, keep magic plaintext ++ PERF_TIMER(export_key_images_encrypt); ++ std::string ciphertext = encrypt_with_view_secret_key(data); ++ return magic + ciphertext; + } + ++ + //---------------------------------------------------------------------------------------------------- + std::pair>> wallet2::export_key_images(bool all) const + { +@@ -14015,53 +14055,60 @@ std::pair> + return std::make_pair(offset, ski); + } + +-uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent) ++uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent) { ++ std::string data; ++ ++ bool r = load_from_file(filename, data); ++ ++ THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, std::string(tr("failed to read file ")) + filename); ++ ++ return import_key_images_str(data, spent, unspent); ++} ++ ++uint64_t wallet2::import_key_images_str(const std::string &data, uint64_t &spent, uint64_t &unspent) + { + PERF_TIMER(import_key_images_fsu); +- std::string data; +- bool r = load_from_file(filename, data); +- +- THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, std::string(tr("failed to read file ")) + filename); ++ std::string data_local = data; + + const size_t magiclen = strlen(KEY_IMAGE_EXPORT_FILE_MAGIC); + if (data.size() < magiclen || memcmp(data.data(), KEY_IMAGE_EXPORT_FILE_MAGIC, magiclen)) + { +- THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad key image export file magic in ") + filename); ++ THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad key image export file magic")); + } + + try + { + PERF_TIMER(import_key_images_decrypt); +- data = decrypt_with_view_secret_key(std::string(data, magiclen)); ++ data_local = decrypt_with_view_secret_key(std::string(data, magiclen)); + } + catch (const std::exception &e) + { +- THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to decrypt ") + filename + ": " + e.what()); ++ THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to decrypt ") + ": " + e.what()); + } + + const size_t headerlen = 4 + 2 * sizeof(crypto::public_key); +- THROW_WALLET_EXCEPTION_IF(data.size() < headerlen, error::wallet_internal_error, std::string("Bad data size from file ") + filename); +- const uint32_t offset = (uint8_t)data[0] | (((uint8_t)data[1]) << 8) | (((uint8_t)data[2]) << 16) | (((uint8_t)data[3]) << 24); +- const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[4]; +- const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[4 + sizeof(crypto::public_key)]; ++ THROW_WALLET_EXCEPTION_IF(data_local.size() < headerlen, error::wallet_internal_error, std::string("Bad data size from file ")); ++ const uint32_t offset = (uint8_t)data_local[0] | (((uint8_t)data_local[1]) << 8) | (((uint8_t)data_local[2]) << 16) | (((uint8_t)data_local[3]) << 24); ++ const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data_local[4]; ++ const crypto::public_key &public_view_key = *(const crypto::public_key*)&data_local[4 + sizeof(crypto::public_key)]; + const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address; + if (public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key) + { +- THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string( "Key images from ") + filename + " are for a different account"); ++ THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string( "Key images from ") + " are for a different account"); + } + THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error, "Offset larger than known outputs"); + + const size_t record_size = sizeof(crypto::key_image) + sizeof(crypto::signature); +- THROW_WALLET_EXCEPTION_IF((data.size() - headerlen) % record_size, +- error::wallet_internal_error, std::string("Bad data size from file ") + filename); +- size_t nki = (data.size() - headerlen) / record_size; ++ THROW_WALLET_EXCEPTION_IF((data_local.size() - headerlen) % record_size, ++ error::wallet_internal_error, std::string("Bad data size from file ")); ++ size_t nki = (data_local.size() - headerlen) / record_size; + + std::vector> ski; + ski.reserve(nki); + for (size_t n = 0; n < nki; ++n) + { +- crypto::key_image key_image = *reinterpret_cast(&data[headerlen + n * record_size]); +- crypto::signature signature = *reinterpret_cast(&data[headerlen + n * record_size + sizeof(crypto::key_image)]); ++ crypto::key_image key_image = *reinterpret_cast(&data_local[headerlen + n * record_size]); ++ crypto::signature signature = *reinterpret_cast(&data_local[headerlen + n * record_size + sizeof(crypto::key_image)]); + + ski.push_back(std::make_pair(key_image, signature)); + } +diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h +index daad1e940..a752f15b9 100644 +--- a/src/wallet/wallet2.h ++++ b/src/wallet/wallet2.h +@@ -1157,6 +1157,7 @@ private: + // locked & unlocked balance of given or current subaddress account + uint64_t balance(uint32_t subaddr_index_major, bool strict) const; + uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL); ++ uint64_t view_only_balance(uint32_t index_major, const std::vector& selected_inputs = {}); + // locked & unlocked balance per subaddress of given or current subaddress account + std::map balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const; + std::map>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict); +@@ -1631,9 +1632,11 @@ private: + std::tuple> export_blockchain() const; + void import_blockchain(const std::tuple> &bc); + bool export_key_images(const std::string &filename, bool all = false) const; ++ std::string export_key_images_str(bool all) const; + std::pair>> export_key_images(bool all = false) const; + uint64_t import_key_images(const std::vector> &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent = true); + uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent); ++ uint64_t import_key_images_str(const std::string &data, uint64_t &spent, uint64_t &unspent); + bool import_key_images(std::vector key_images, size_t offset=0, boost::optional> selected_transfers=boost::none); + bool import_key_images(signed_tx_set & signed_tx, size_t offset=0, bool only_selected_transfers=false); + crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const; +-- +2.48.1 + diff --git a/patches/salvium/0006-add-dummy-device-for-ledger.patch b/patches/salvium/0006-add-dummy-device-for-ledger.patch new file mode 100644 index 0000000..22ee249 --- /dev/null +++ b/patches/salvium/0006-add-dummy-device-for-ledger.patch @@ -0,0 +1,604 @@ +From 904fe95204ba02d1a8c81fc46c1423ba1685c94f Mon Sep 17 00:00:00 2001 +From: Czarek Nakamoto +Date: Wed, 26 Jun 2024 15:04:38 +0200 +Subject: [PATCH 06/14] add dummy device for ledger + +--- + CMakeLists.txt | 6 +- + src/device/CMakeLists.txt | 6 +- + src/device/device.cpp | 10 ++- + src/device/device.hpp | 12 +-- + src/device/device_io_dummy.cpp | 133 ++++++++++++++++++++++++++++++ + src/device/device_io_dummy.hpp | 74 +++++++++++++++++ + src/device/device_ledger.cpp | 6 +- + src/device/device_ledger.hpp | 7 +- + src/wallet/api/wallet.cpp | 94 +++++++++++++++++++++ + src/wallet/api/wallet.h | 18 ++++ + src/wallet/api/wallet2_api.h | 12 +++ + src/wallet/api/wallet_manager.cpp | 12 ++- + 12 files changed, 365 insertions(+), 25 deletions(-) + create mode 100644 src/device/device_io_dummy.cpp + create mode 100644 src/device/device_io_dummy.hpp + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index c73b813d8..5c0f31cb8 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -692,8 +692,12 @@ include_directories(${LMDB_INCLUDE}) + include_directories(${LIBUNWIND_INCLUDE}) + link_directories(${LIBUNWIND_LIBRARY_DIRS}) + ++if (HIDAPI_DUMMY) ++ add_definitions(-DHIDAPI_DUMMY) ++endif() ++ + # Final setup for hid +-if (HIDAPI_FOUND) ++if (HIDAPI_FOUND) + message(STATUS "Using HIDAPI include dir at ${HIDAPI_INCLUDE_DIR}") + add_definitions(-DHAVE_HIDAPI) + include_directories(${HIDAPI_INCLUDE_DIR}) +diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt +index e4f1159b5..14d398f87 100644 +--- a/src/device/CMakeLists.txt ++++ b/src/device/CMakeLists.txt +@@ -29,10 +29,11 @@ + set(device_sources + device.cpp + device_default.cpp ++ device_io_dummy.cpp + log.cpp + ) + +-if(HIDAPI_FOUND) ++if(HIDAPI_FOUND OR HIDAPI_DUMMY) + set(device_sources + ${device_sources} + device_ledger.cpp +@@ -45,10 +46,11 @@ set(device_headers + device_io.hpp + device_default.hpp + device_cold.hpp ++ device_io_dummy.hpp + log.hpp + ) + +-if(HIDAPI_FOUND) ++if(HIDAPI_FOUND OR HIDAPI_DUMMY) + set(device_headers + ${device_headers} + device_ledger.hpp +diff --git a/src/device/device.cpp b/src/device/device.cpp +index e6cd358b6..dd0701e0c 100644 +--- a/src/device/device.cpp ++++ b/src/device/device.cpp +@@ -29,7 +29,7 @@ + + #include "device.hpp" + #include "device_default.hpp" +-#ifdef WITH_DEVICE_LEDGER ++#if defined(WITH_DEVICE_LEDGER) || defined(HIDAPI_DUMMY) + #include "device_ledger.hpp" + #endif + #include "misc_log_ex.h" +@@ -57,7 +57,7 @@ namespace hw { + + device_registry::device_registry(){ + hw::core::register_all(registry); +- #ifdef WITH_DEVICE_LEDGER ++ #if defined(WITH_DEVICE_LEDGER) || defined(HIDAPI_DUMMY) + hw::ledger::register_all(registry); + #endif + atexit(clear_device_registry); +@@ -83,11 +83,13 @@ namespace hw { + + auto device = registry.find(device_descriptor_lookup); + if (device == registry.end()) { +- MERROR("Device not found in registry: '" << device_descriptor << "'. Known devices: "); ++ std::stringstream ss("Device not found in registry: '" + device_descriptor + "'. Known devices: "); ++ MERROR("Device not found in registry: '" << device_descriptor << "'. Known devices: \n"); + for( const auto& sm_pair : registry ) { ++ ss << "\n- " + sm_pair.first; + MERROR(" - " << sm_pair.first); + } +- throw std::runtime_error("device not found: " + device_descriptor); ++ throw std::runtime_error("device not found: " + device_descriptor + "\n" + ss.str()); + } + return *device->second; + } +diff --git a/src/device/device.hpp b/src/device/device.hpp +index 392703a24..ffd419779 100644 +--- a/src/device/device.hpp ++++ b/src/device/device.hpp +@@ -34,17 +34,7 @@ + #include "ringct/rctTypes.h" + #include "cryptonote_config.h" + +- +-#ifndef USE_DEVICE_LEDGER +-#define USE_DEVICE_LEDGER 1 +-#endif +- +-#if !defined(HAVE_HIDAPI) +-#undef USE_DEVICE_LEDGER +-#define USE_DEVICE_LEDGER 0 +-#endif +- +-#if USE_DEVICE_LEDGER ++#if defined(HAVE_HIDAPI) || defined(HIDAPI_DUMMY) + #define WITH_DEVICE_LEDGER + #endif + +diff --git a/src/device/device_io_dummy.cpp b/src/device/device_io_dummy.cpp +new file mode 100644 +index 000000000..edb4beea3 +--- /dev/null ++++ b/src/device/device_io_dummy.cpp +@@ -0,0 +1,133 @@ ++// Copyright (c) 2017-2022, The Monero Project ++// ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without modification, are ++// permitted provided that the following conditions are met: ++// ++// 1. Redistributions of source code must retain the above copyright notice, this list of ++// conditions and the following disclaimer. ++// ++// 2. Redistributions in binary form must reproduce the above copyright notice, this list ++// of conditions and the following disclaimer in the documentation and/or other ++// materials provided with the distribution. ++// ++// 3. Neither the name of the copyright holder nor the names of its contributors may be ++// used to endorse or promote products derived from this software without specific ++// prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY ++// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF ++// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++// device_io_dummy ++// Main goal of device_io_dummy is to emulate a hw::io::device_io without the need to actually ++// connect a device. ++// Many operating systems do not support giving raw USB access to a process (android), or don't ++// support that at all (hi iOS), therefore other means of connection can be used, either USB ++// abstraction provided by the OS (monerujo), or BLE (also monerujo). ++// Monerujo implementation is written in Java, which makes it a nice fit for iOS, but makes the ++// code extremely unportable, so for this reason the code in here is written in CPP. ++// Data transport is made available in wallet2_api.h, so wallet developers can easily plug their ++// own USB/BLE/other transport layer. ++ ++#if defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI) ++#include ++#include "log.hpp" ++#include "device_io_dummy.hpp" ++#include "device_ledger.hpp" ++ ++ ++bool hw::io::device_io_dummy::stateIsConnected = false; ++unsigned char* hw::io::device_io_dummy::sendToDevice = {}; ++size_t hw::io::device_io_dummy::sendToDeviceLength = 0; ++unsigned char* hw::io::device_io_dummy::receivedFromDevice = {}; ++size_t hw::io::device_io_dummy::receivedFromDeviceLength = 0; ++bool hw::io::device_io_dummy::waitsForDeviceSend = false; ++bool hw::io::device_io_dummy::waitsForDeviceReceive = false; ++ ++namespace hw { ++ namespace io { ++ ++#undef MONERO_DEFAULT_LOG_CATEGORY ++#define MONERO_DEFAULT_LOG_CATEGORY "device.io_dummy" ++ device_io_dummy::device_io_dummy(int a, int b, int c, int d) { ++ MDEBUG("device_io_dummy(a: " << a << ", b: " << b << ", c: " << c << ", d: " << d <<")"); ++ } ++ ++ void device_io_dummy::init() { ++ MDEBUG("init()"); ++ } ++ ++ void device_io_dummy::connect(void *params) { ++ MDEBUG("connect(" << params << ")"); ++ stateIsConnected = true; ++ } ++ ++ void device_io_dummy::connect(const std::vector& known_devices) { ++ MDEBUG("connect(["); ++ for (const auto &item: known_devices) { ++ MDEBUG("{ interface_number: " << item.interface_number); ++ MDEBUG(" pid : " << item.pid); ++ MDEBUG(" usage_page : " << item.usage_page); ++ MDEBUG(" vid : " << item.vid << " },"); ++ } ++ MDEBUG("])"); ++ stateIsConnected = true; ++ } ++ ++ bool device_io_dummy::connected() const { ++ MDEBUG("connected()"); ++ return stateIsConnected; ++ } ++ ++ int device_io_dummy::exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len, bool user_input) { ++ MDEBUG("exchange(): locking mutex"); ++ boost::unique_lock lock(mutex); ++ sendToDevice = command; ++ sendToDeviceLength = cmd_len; ++ waitsForDeviceSend = true; ++ waitsForDeviceReceive = true; ++ MDEBUG("exchange(): waitsForDeviceSend"); ++ // NOTE: waitsForDeviceSend should be changed by external code ++ while (waitsForDeviceSend) { ++ usleep(1000); ++ MDEBUG("exchange(): waitsForDeviceSend (still)"); ++ } ++ ++ MDEBUG("exchange(): waitsForDeviceReceive"); ++ while (waitsForDeviceReceive) { ++ usleep(1000); ++ MDEBUG("exchange(): waitsForDeviceReceive (still)"); ++ } ++ ++ if (receivedFromDeviceLength > max_resp_len) { ++ MDEBUG("exchange(): receivedFromDeviceLength ("<& known_devices); ++ void disconnect(); ++ bool connected() const; ++ ++ int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len, bool user_input); ++ }; ++ }; ++}; ++ ++#endif // HAVE_HIDAPI +diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp +index bb5b6f497..046201a1e 100644 +--- a/src/device/device_ledger.cpp ++++ b/src/device/device_ledger.cpp +@@ -41,7 +41,7 @@ namespace hw { + + namespace ledger { + +- #ifdef WITH_DEVICE_LEDGER ++ #if defined(WITH_DEVICE_LEDGER) || defined(HIDAPI_DUMMY) + + #undef MONERO_DEFAULT_LOG_CATEGORY + #define MONERO_DEFAULT_LOG_CATEGORY "device.ledger" +@@ -299,7 +299,7 @@ namespace hw { + + device_ledger::device_ledger(): hw_device(0x0101, 0x05, 64, 2000) { + this->id = device_id++; +- this->reset_buffer(); ++ this->reset_buffer(); + this->mode = NONE; + this->has_view_key = false; + this->tx_in_progress = false; +@@ -533,7 +533,9 @@ namespace hw { + + bool device_ledger::connect(void) { + this->disconnect(); ++ #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)) + hw_device.connect(known_devices); ++ #endif + this->reset(); + #ifdef DEBUG_HWDEVICE + cryptonote::account_public_address pubkey; +diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp +index 03058c4f1..39454ca6d 100644 +--- a/src/device/device_ledger.hpp ++++ b/src/device/device_ledger.hpp +@@ -35,6 +35,7 @@ + #include "device.hpp" + #include "log.hpp" + #include "device_io_hid.hpp" ++#include "device_io_dummy.hpp" + #include + #include + +@@ -56,7 +57,7 @@ namespace hw { + + void register_all(std::map> ®istry); + +- #ifdef WITH_DEVICE_LEDGER ++ #if defined(WITH_DEVICE_LEDGER) || defined(HIDAPI_DUMMY) + + // Origin: https://github.com/LedgerHQ/ledger-app-monero/blob/master/src/monero_types.h + #define SW_OK 0x9000 +@@ -148,7 +149,11 @@ namespace hw { + mutable boost::mutex command_locker; + + //IO ++#if defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI) ++ hw::io::device_io_dummy hw_device; ++#else + hw::io::device_io_hid hw_device; ++#endif + unsigned int length_send; + unsigned char buffer_send[BUFFER_SEND_SIZE]; + unsigned int length_recv; +diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp +index 3fcd6f332..25ade04a7 100644 +--- a/src/wallet/api/wallet.cpp ++++ b/src/wallet/api/wallet.cpp +@@ -48,6 +48,9 @@ + #include + #include + #include "bc-ur/src/bc-ur.hpp" ++#if defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI) ++#include "device/device_io_dummy.hpp" ++#endif + + using namespace std; + using namespace cryptonote; +@@ -3178,4 +3181,95 @@ uint64_t WalletImpl::getBytesSent() + return m_wallet->get_bytes_sent(); + } + ++ ++// HIDAPI_DUMMY ++bool WalletImpl::getStateIsConnected() { ++ #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)) ++ setStatusError("MONERO compiled with #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI))"); ++ return false; ++ #else ++ return hw::io::device_io_dummy::stateIsConnected; ++ #endif ++} ++ ++unsigned char* WalletImpl::getSendToDevice() { ++ #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)) ++ setStatusError("MONERO compiled with #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI))"); ++ return {}; ++ #else ++ return hw::io::device_io_dummy::sendToDevice; ++ #endif ++} ++ ++size_t WalletImpl::getSendToDeviceLength() { ++ #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)) ++ setStatusError("MONERO compiled with #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI))"); ++ return -1; ++ #else ++ return hw::io::device_io_dummy::sendToDeviceLength; ++ #endif ++} ++ ++unsigned char* WalletImpl::getReceivedFromDevice() { ++ #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)) ++ setStatusError("MONERO compiled with #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI))"); ++ return {}; ++ #else ++ return hw::io::device_io_dummy::receivedFromDevice; ++ #endif ++} ++ ++size_t WalletImpl::getReceivedFromDeviceLength() { ++ #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)) ++ setStatusError("MONERO compiled with #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI))"); ++ return -1; ++ #else ++ return hw::io::device_io_dummy::receivedFromDeviceLength; ++ #endif ++} ++ ++bool WalletImpl::getWaitsForDeviceSend() { ++ #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)) ++ setStatusError("MONERO compiled with #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI))"); ++ return false; ++ #else ++ return hw::io::device_io_dummy::receivedFromDeviceLength; ++ #endif ++} ++ ++bool WalletImpl::getWaitsForDeviceReceive() { ++ #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)) ++ setStatusError("MONERO compiled with #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI))"); ++ return false; ++ #else ++ return hw::io::device_io_dummy::waitsForDeviceReceive; ++ #endif ++} ++ ++void WalletImpl::setDeviceReceivedData(unsigned char* data, size_t len) { ++ #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)) ++ setStatusError("MONERO compiled with #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI))"); ++ return; ++ #else ++ hw::io::device_io_dummy::receivedFromDevice = static_cast(malloc(len)); ++ hw::io::device_io_dummy::receivedFromDeviceLength = len; ++ memset(hw::io::device_io_dummy::receivedFromDevice, 0, len); ++ memcpy(hw::io::device_io_dummy::receivedFromDevice, data, len); ++ hw::io::device_io_dummy::waitsForDeviceReceive = false; ++ #endif ++} ++ ++void WalletImpl::setDeviceSendData(unsigned char* data, size_t len) { ++ #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)) ++ setStatusError("MONERO compiled with #if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI))"); ++ return; ++ #else ++ hw::io::device_io_dummy::sendToDevice = static_cast(malloc(len)); ++ hw::io::device_io_dummy::sendToDeviceLength = len; ++ memset(hw::io::device_io_dummy::sendToDevice, 0, len); ++ memcpy(hw::io::device_io_dummy::sendToDevice, data, len); ++ hw::io::device_io_dummy::waitsForDeviceSend = false; ++ #endif ++} ++ + } // namespace +diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h +index edf8bb8ce..4e9c21ecb 100644 +--- a/src/wallet/api/wallet.h ++++ b/src/wallet/api/wallet.h +@@ -301,6 +301,24 @@ private: + // cache connection status to avoid unnecessary RPC calls + mutable std::atomic m_is_connected; + boost::optional m_daemon_login{}; ++ ++ bool getStateIsConnected(); ++ ++ unsigned char *getSendToDevice(); ++ ++ size_t getSendToDeviceLength(); ++ ++ unsigned char *getReceivedFromDevice(); ++ ++ size_t getReceivedFromDeviceLength(); ++ ++ bool getWaitsForDeviceSend(); ++ ++ bool getWaitsForDeviceReceive(); ++ ++ void setDeviceReceivedData(unsigned char *data, size_t len); ++ ++ void setDeviceSendData(unsigned char *data, size_t len); + }; + + +diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h +index 764adbfbf..53ec4abfc 100644 +--- a/src/wallet/api/wallet2_api.h ++++ b/src/wallet/api/wallet2_api.h +@@ -1150,6 +1150,18 @@ struct Wallet + + //! get bytes sent + virtual uint64_t getBytesSent() = 0; ++ ++ // HIDAPI_DUMMY ++ virtual bool getStateIsConnected() = 0; ++ virtual unsigned char* getSendToDevice() = 0; ++ virtual size_t getSendToDeviceLength() = 0; ++ virtual unsigned char* getReceivedFromDevice() = 0; ++ virtual size_t getReceivedFromDeviceLength() = 0; ++ virtual bool getWaitsForDeviceSend() = 0; ++ virtual bool getWaitsForDeviceReceive() = 0; ++ ++ virtual void setDeviceReceivedData(unsigned char* data, size_t len) = 0; ++ virtual void setDeviceSendData(unsigned char* data, size_t len) = 0; + }; + + /** +diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp +index e81b8f83a..277be6ac9 100644 +--- a/src/wallet/api/wallet_manager.cpp ++++ b/src/wallet/api/wallet_manager.cpp +@@ -188,10 +188,14 @@ bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, + + bool WalletManagerImpl::queryWalletDevice(Wallet::Device& device_type, const std::string &keys_file_name, const std::string &password, uint64_t kdf_rounds) const + { +- hw::device::device_type type; +- bool r = tools::wallet2::query_device(type, keys_file_name, password, kdf_rounds); +- device_type = static_cast(type); +- return r; ++ try { ++ hw::device::device_type type; ++ bool r = tools::wallet2::query_device(type, keys_file_name, password, kdf_rounds); ++ device_type = static_cast(type); ++ return r; ++ } catch (...) { ++ return false; ++ } + } + + std::vector WalletManagerImpl::findWallets(const std::string &path) +-- +2.48.1 + diff --git a/patches/salvium/0007-polyseed.patch b/patches/salvium/0007-polyseed.patch new file mode 100644 index 0000000..b590a33 --- /dev/null +++ b/patches/salvium/0007-polyseed.patch @@ -0,0 +1,1286 @@ +From c54ab3f0984159bd47c63b78074caaaac082727a Mon Sep 17 00:00:00 2001 +From: tobtoht +Date: Tue, 12 Mar 2024 09:42:37 +0100 +Subject: [PATCH 07/14] polyseed + +Co-authored-by: Czarek Nakamoto +--- + .gitmodules | 6 + + CMakeLists.txt | 4 +- + contrib/epee/include/wipeable_string.h | 7 + + contrib/epee/src/wipeable_string.cpp | 10 ++ + external/CMakeLists.txt | 2 + + external/polyseed | 1 + + external/utf8proc | 1 + + src/CMakeLists.txt | 1 + + src/cryptonote_basic/CMakeLists.txt | 1 + + src/cryptonote_basic/account.cpp | 23 +++- + src/cryptonote_basic/account.h | 6 + + src/cryptonote_config.h | 2 + + src/polyseed/CMakeLists.txt | 25 ++++ + src/polyseed/pbkdf2.c | 85 ++++++++++++ + src/polyseed/pbkdf2.h | 46 +++++++ + src/polyseed/polyseed.cpp | 182 +++++++++++++++++++++++++ + src/polyseed/polyseed.hpp | 167 +++++++++++++++++++++++ + src/wallet/api/wallet.cpp | 70 ++++++++++ + src/wallet/api/wallet.h | 10 ++ + src/wallet/api/wallet2_api.h | 25 ++++ + src/wallet/api/wallet_manager.cpp | 9 ++ + src/wallet/api/wallet_manager.h | 10 ++ + src/wallet/wallet2.cpp | 100 ++++++++++++-- + src/wallet/wallet2.h | 30 +++- + 24 files changed, 805 insertions(+), 18 deletions(-) + create mode 160000 external/polyseed + create mode 160000 external/utf8proc + create mode 100644 src/polyseed/CMakeLists.txt + create mode 100644 src/polyseed/pbkdf2.c + create mode 100644 src/polyseed/pbkdf2.h + create mode 100644 src/polyseed/polyseed.cpp + create mode 100644 src/polyseed/polyseed.hpp + +diff --git a/.gitmodules b/.gitmodules +index 72af74d55..b838e84e0 100644 +--- a/.gitmodules ++++ b/.gitmodules +@@ -11,6 +11,12 @@ + path = external/randomx + url = https://github.com/MrCyjaneK/RandomX + branch = cyjan-fix-ios ++[submodule "external/utf8proc"] ++ path = external/utf8proc ++ url = https://github.com/JuliaStrings/utf8proc.git ++[submodule "external/polyseed"] ++ path = external/polyseed ++ url = https://github.com/tevador/polyseed.git + [submodule "external/supercop"] + path = external/supercop + url = https://github.com/monero-project/supercop +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 5c0f31cb8..f0630ef9b 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -371,6 +371,8 @@ if(NOT MANUAL_SUBMODULES) + check_submodule(external/trezor-common) + check_submodule(external/randomx) + check_submodule(external/supercop) ++ check_submodule(external/polyseed) ++ check_submodule(external/utf8proc) + endif() + endif() + +@@ -460,7 +462,7 @@ endif() + # elseif(CMAKE_SYSTEM_NAME MATCHES ".*BSDI.*") + # set(BSDI TRUE) + +-include_directories(external/rapidjson/include external/easylogging++ src contrib/epee/include external external/supercop/include) ++include_directories(external/rapidjson/include external/easylogging++ src contrib/epee/include external external/supercop/include external/polyseed/include external/utf8proc) + + if(APPLE) + cmake_policy(SET CMP0042 NEW) +diff --git a/contrib/epee/include/wipeable_string.h b/contrib/epee/include/wipeable_string.h +index 65977cd97..594e15de4 100644 +--- a/contrib/epee/include/wipeable_string.h ++++ b/contrib/epee/include/wipeable_string.h +@@ -34,6 +34,7 @@ + #include + #include "memwipe.h" + #include "fnv1.h" ++#include "serialization/keyvalue_serialization.h" + + namespace epee + { +@@ -75,6 +76,12 @@ namespace epee + bool operator!=(const wipeable_string &other) const noexcept { return buffer != other.buffer; } + wipeable_string &operator=(wipeable_string &&other); + wipeable_string &operator=(const wipeable_string &other); ++ char& operator[](size_t idx); ++ const char& operator[](size_t idx) const; ++ ++ BEGIN_KV_SERIALIZE_MAP() ++ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(buffer) ++ END_KV_SERIALIZE_MAP() + + private: + void grow(size_t sz, size_t reserved = 0); +diff --git a/contrib/epee/src/wipeable_string.cpp b/contrib/epee/src/wipeable_string.cpp +index b016f2f48..f2f365b1b 100644 +--- a/contrib/epee/src/wipeable_string.cpp ++++ b/contrib/epee/src/wipeable_string.cpp +@@ -261,4 +261,14 @@ wipeable_string &wipeable_string::operator=(const wipeable_string &other) + return *this; + } + ++char& wipeable_string::operator[](size_t idx) { ++ CHECK_AND_ASSERT_THROW_MES(idx < buffer.size(), "Index out of bounds"); ++ return buffer[idx]; ++} ++ ++const char& wipeable_string::operator[](size_t idx) const { ++ CHECK_AND_ASSERT_THROW_MES(idx < buffer.size(), "Index out of bounds"); ++ return buffer[idx]; ++} ++ + } +diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt +index 074e23f16..f7e35f98f 100644 +--- a/external/CMakeLists.txt ++++ b/external/CMakeLists.txt +@@ -70,5 +70,7 @@ endif() + add_subdirectory(db_drivers) + add_subdirectory(easylogging++) + add_subdirectory(qrcodegen) ++add_subdirectory(polyseed EXCLUDE_FROM_ALL) ++add_subdirectory(utf8proc EXCLUDE_FROM_ALL) + add_subdirectory(bc-ur) + add_subdirectory(randomx EXCLUDE_FROM_ALL) +diff --git a/external/polyseed b/external/polyseed +new file mode 160000 +index 000000000..bd79f5014 +--- /dev/null ++++ b/external/polyseed +@@ -0,0 +1 @@ ++Subproject commit bd79f5014c331273357277ed8a3d756fb61b9fa1 +diff --git a/external/utf8proc b/external/utf8proc +new file mode 160000 +index 000000000..3de4596fb +--- /dev/null ++++ b/external/utf8proc +@@ -0,0 +1 @@ ++Subproject commit 3de4596fbe28956855df2ecb3c11c0bbc3535838 +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index 3335d3c21..06b708cf0 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -95,6 +95,7 @@ add_subdirectory(net) + add_subdirectory(hardforks) + add_subdirectory(blockchain_db) + add_subdirectory(mnemonics) ++add_subdirectory(polyseed) + add_subdirectory(rpc) + if(NOT IOS) + add_subdirectory(serialization) +diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt +index 1414be1b2..414936a05 100644 +--- a/src/cryptonote_basic/CMakeLists.txt ++++ b/src/cryptonote_basic/CMakeLists.txt +@@ -71,6 +71,7 @@ target_link_libraries(cryptonote_basic + checkpoints + cryptonote_format_utils_basic + device ++ polyseed_wrapper + ${Boost_DATE_TIME_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_SERIALIZATION_LIBRARY} +diff --git a/src/cryptonote_basic/account.cpp b/src/cryptonote_basic/account.cpp +index 4e87d4477..2d556f285 100644 +--- a/src/cryptonote_basic/account.cpp ++++ b/src/cryptonote_basic/account.cpp +@@ -87,12 +87,16 @@ DISABLE_VS_WARNINGS(4244 4345) + void account_keys::xor_with_key_stream(const crypto::chacha_key &key) + { + // encrypt a large enough byte stream with chacha20 +- epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (2 + m_multisig_keys.size())); ++ epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (3 + m_multisig_keys.size()) + m_passphrase.size()); + const char *ptr = key_stream.data(); + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) + m_spend_secret_key.data[i] ^= *ptr++; + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) + m_view_secret_key.data[i] ^= *ptr++; ++ for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) ++ m_polyseed.data[i] ^= *ptr++; ++ for (size_t i = 0; i < m_passphrase.size(); ++i) ++ m_passphrase.data()[i] ^= *ptr++; + for (crypto::secret_key &k: m_multisig_keys) + { + for (size_t i = 0; i < sizeof(crypto::secret_key); ++i) +@@ -150,6 +154,8 @@ DISABLE_VS_WARNINGS(4244 4345) + { + m_keys.m_spend_secret_key = crypto::secret_key(); + m_keys.m_multisig_keys.clear(); ++ m_keys.m_polyseed = crypto::secret_key(); ++ m_keys.m_passphrase.wipe(); + } + //----------------------------------------------------------------- + void account_base::set_spend_key(const crypto::secret_key& spend_secret_key) +@@ -255,6 +261,21 @@ DISABLE_VS_WARNINGS(4244 4345) + create_from_keys(address, fake, viewkey); + } + //----------------------------------------------------------------- ++ void account_base::create_from_polyseed(const polyseed::data& seed, const epee::wipeable_string &passphrase) ++ { ++ crypto::secret_key secret_key; ++ seed.keygen(&secret_key, sizeof(secret_key)); ++ ++ if (!passphrase.empty()) { ++ secret_key = cryptonote::decrypt_key(secret_key, passphrase); ++ } ++ ++ generate(secret_key, true, false); ++ ++ seed.save(m_keys.m_polyseed.data); ++ m_keys.m_passphrase = passphrase; ++ } ++ //----------------------------------------------------------------- + bool account_base::make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector &multisig_keys) + { + m_keys.m_account_address.m_spend_public_key = spend_public_key; +diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h +index 93d1d28f0..1f76febce 100644 +--- a/src/cryptonote_basic/account.h ++++ b/src/cryptonote_basic/account.h +@@ -33,6 +33,7 @@ + #include "cryptonote_basic.h" + #include "crypto/crypto.h" + #include "serialization/keyvalue_serialization.h" ++#include "polyseed/polyseed.hpp" + + namespace cryptonote + { +@@ -45,6 +46,8 @@ namespace cryptonote + std::vector m_multisig_keys; + hw::device *m_device = &hw::get_device("default"); + crypto::chacha_iv m_encryption_iv; ++ crypto::secret_key m_polyseed; ++ epee::wipeable_string m_passphrase; // Only used with polyseed + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_account_address) +@@ -53,6 +56,8 @@ namespace cryptonote + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys) + const crypto::chacha_iv default_iv{{0, 0, 0, 0, 0, 0, 0, 0}}; + KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(m_encryption_iv, default_iv) ++ KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_polyseed) ++ KV_SERIALIZE(m_passphrase) + END_KV_SERIALIZE_MAP() + + void encrypt(const crypto::chacha_key &key); +@@ -79,6 +84,7 @@ namespace cryptonote + void create_from_device(hw::device &hwdev); + void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey); + void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey); ++ void create_from_polyseed(const polyseed::data &polyseed, const epee::wipeable_string &passphrase); + bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector &multisig_keys); + const account_keys& get_keys() const; + std::string get_public_address_str(network_type nettype) const; +diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h +index 82891b9de..26200bf34 100644 +--- a/src/cryptonote_config.h ++++ b/src/cryptonote_config.h +@@ -211,6 +211,8 @@ + + #define DNS_BLOCKLIST_LIFETIME (86400 * 8) + ++#define POLYSEED_COIN POLYSEED_MONERO ++ + //The limit is enough for the mandatory transaction content with 16 outputs (547 bytes), + //a custom tag (1 byte) and up to 32 bytes of custom data for each recipient. + // (1+32) + (1+1+16*32) + (1+16*32) = 1060 +diff --git a/src/polyseed/CMakeLists.txt b/src/polyseed/CMakeLists.txt +new file mode 100644 +index 000000000..cca4eb746 +--- /dev/null ++++ b/src/polyseed/CMakeLists.txt +@@ -0,0 +1,25 @@ ++set(polyseed_sources ++ pbkdf2.c ++ polyseed.cpp ++) ++ ++monero_find_all_headers(polyseed_private_headers "${CMAKE_CURRENT_SOURCE_DIR}") ++ ++monero_private_headers(polyseed_wrapper ++ ${polyseed_private_headers} ++) ++ ++monero_add_library(polyseed_wrapper ++ ${polyseed_sources} ++ ${polyseed_headers} ++ ${polyseed_private_headers} ++) ++ ++target_link_libraries(polyseed_wrapper ++PUBLIC ++ polyseed ++ utf8proc ++ ${SODIUM_LIBRARY} ++ PRIVATE ++ ${EXTRA_LIBRARIES} ++) +diff --git a/src/polyseed/pbkdf2.c b/src/polyseed/pbkdf2.c +new file mode 100644 +index 000000000..1c45f4708 +--- /dev/null ++++ b/src/polyseed/pbkdf2.c +@@ -0,0 +1,85 @@ ++// Copyright (c) 2023, The Monero Project ++// Copyright (c) 2021, tevador ++// Copyright (c) 2005,2007,2009 Colin Percival ++// ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// 1. Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// 2. Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in the ++// documentation and/or other materials provided with the distribution. ++// ++// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++// SUCH DAMAGE. ++ ++#include ++ ++#include ++#include ++ ++static inline void ++store32_be(uint8_t dst[4], uint32_t w) ++{ ++ dst[3] = (uint8_t) w; w >>= 8; ++ dst[2] = (uint8_t) w; w >>= 8; ++ dst[1] = (uint8_t) w; w >>= 8; ++ dst[0] = (uint8_t) w; ++} ++ ++void ++crypto_pbkdf2_sha256(const uint8_t* passwd, size_t passwdlen, ++ const uint8_t* salt, size_t saltlen, uint64_t c, ++ uint8_t* buf, size_t dkLen) ++{ ++ crypto_auth_hmacsha256_state Phctx, PShctx, hctx; ++ size_t i; ++ uint8_t ivec[4]; ++ uint8_t U[32]; ++ uint8_t T[32]; ++ uint64_t j; ++ int k; ++ size_t clen; ++ ++ crypto_auth_hmacsha256_init(&Phctx, passwd, passwdlen); ++ PShctx = Phctx; ++ crypto_auth_hmacsha256_update(&PShctx, salt, saltlen); ++ ++ for (i = 0; i * 32 < dkLen; i++) { ++ store32_be(ivec, (uint32_t)(i + 1)); ++ hctx = PShctx; ++ crypto_auth_hmacsha256_update(&hctx, ivec, 4); ++ crypto_auth_hmacsha256_final(&hctx, U); ++ ++ memcpy(T, U, 32); ++ for (j = 2; j <= c; j++) { ++ hctx = Phctx; ++ crypto_auth_hmacsha256_update(&hctx, U, 32); ++ crypto_auth_hmacsha256_final(&hctx, U); ++ ++ for (k = 0; k < 32; k++) { ++ T[k] ^= U[k]; ++ } ++ } ++ ++ clen = dkLen - i * 32; ++ if (clen > 32) { ++ clen = 32; ++ } ++ memcpy(&buf[i * 32], T, clen); ++ } ++ sodium_memzero((void*)&Phctx, sizeof Phctx); ++ sodium_memzero((void*)&PShctx, sizeof PShctx); ++} +\ No newline at end of file +diff --git a/src/polyseed/pbkdf2.h b/src/polyseed/pbkdf2.h +new file mode 100644 +index 000000000..f6253b9d7 +--- /dev/null ++++ b/src/polyseed/pbkdf2.h +@@ -0,0 +1,46 @@ ++// Copyright (c) 2023, The Monero Project ++// Copyright (c) 2021, tevador ++// ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// 1. Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// 2. Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in the ++// documentation and/or other materials provided with the distribution. ++// ++// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++// SUCH DAMAGE. ++ ++#ifndef PBKDF2_H ++#define PBKDF2_H ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++void ++crypto_pbkdf2_sha256(const uint8_t* passwd, size_t passwdlen, ++ const uint8_t* salt, size_t saltlen, uint64_t c, ++ uint8_t* buf, size_t dkLen); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +\ No newline at end of file +diff --git a/src/polyseed/polyseed.cpp b/src/polyseed/polyseed.cpp +new file mode 100644 +index 000000000..231a48a94 +--- /dev/null ++++ b/src/polyseed/polyseed.cpp +@@ -0,0 +1,182 @@ ++// Copyright (c) 2023, The Monero Project ++// Copyright (c) 2021, tevador ++// ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// 1. Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// 2. Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in the ++// documentation and/or other materials provided with the distribution. ++// ++// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++// SUCH DAMAGE. ++ ++#include "polyseed.hpp" ++#include "pbkdf2.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++namespace polyseed { ++ ++ inline size_t utf8_norm(const char* str, polyseed_str norm, utf8proc_option_t options) { ++ utf8proc_int32_t buffer[POLYSEED_STR_SIZE]; ++ utf8proc_ssize_t result; ++ ++ result = utf8proc_decompose(reinterpret_cast(str), 0, buffer, POLYSEED_STR_SIZE, options); ++ if (result < 0 || result > (POLYSEED_STR_SIZE - 1)) { ++ throw std::runtime_error("Unicode normalization failed"); ++ } ++ ++ result = utf8proc_reencode(buffer, result, options); ++ if (result < 0 || result > POLYSEED_STR_SIZE) { ++ throw std::runtime_error("Unicode normalization failed"); ++ } ++ ++ strcpy(norm, reinterpret_cast(buffer)); ++ sodium_memzero(buffer, POLYSEED_STR_SIZE); ++ return result; ++ } ++ ++ static size_t utf8_nfc(const char* str, polyseed_str norm) { ++ // Note: UTF8PROC_LUMP is used here to replace the ideographic space with a regular space for Japanese phrases ++ // to allow wallets to split on ' '. ++ return utf8_norm(str, norm, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_COMPOSE | UTF8PROC_STRIPNA)); ++ } ++ ++ static size_t utf8_nfkd(const char* str, polyseed_str norm) { ++ return utf8_norm(str, norm, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT | UTF8PROC_STRIPNA)); ++ } ++ ++ struct dependency { ++ dependency(); ++ std::vector languages; ++ }; ++ ++ static dependency deps; ++ ++ dependency::dependency() { ++ if (sodium_init() == -1) { ++ throw std::runtime_error("sodium_init failed"); ++ } ++ ++ polyseed_dependency pd; ++ pd.randbytes = &randombytes_buf; ++ pd.pbkdf2_sha256 = &crypto_pbkdf2_sha256; ++ pd.memzero = &sodium_memzero; ++ pd.u8_nfc = &utf8_nfc; ++ pd.u8_nfkd = &utf8_nfkd; ++ pd.time = nullptr; ++ pd.alloc = nullptr; ++ pd.free = nullptr; ++ ++ polyseed_inject(&pd); ++ ++ for (int i = 0; i < polyseed_get_num_langs(); ++i) { ++ languages.push_back(language(polyseed_get_lang(i))); ++ } ++ } ++ ++ static language invalid_lang; ++ ++ const std::vector& get_langs() { ++ return deps.languages; ++ } ++ ++ const language& get_lang_by_name(const std::string& name) { ++ for (auto& lang : deps.languages) { ++ if (name == lang.name_en()) { ++ return lang; ++ } ++ if (name == lang.name()) { ++ return lang; ++ } ++ } ++ return invalid_lang; ++ } ++ ++ inline void data::check_init() const { ++ if (valid()) { ++ throw std::runtime_error("already initialized"); ++ } ++ } ++ ++ static std::array error_desc = { ++ "Success", ++ "Wrong number of words in the phrase", ++ "Unknown language or unsupported words", ++ "Checksum mismatch", ++ "Unsupported seed features", ++ "Invalid seed format", ++ "Memory allocation failure", ++ "Unicode normalization failed" ++ }; ++ ++ static error get_error(polyseed_status status) { ++ if (status > 0 && status < sizeof(error_desc) / sizeof(const char*)) { ++ return error(error_desc[(int)status], status); ++ } ++ return error("Unknown error", status); ++ } ++ ++ void data::create(feature_type features) { ++ check_init(); ++ auto status = polyseed_create(features, &m_data); ++ if (status != POLYSEED_OK) { ++ throw get_error(status); ++ } ++ } ++ ++ void data::split(const language& lang, polyseed_phrase& words) { ++ check_init(); ++ if (!lang.valid()) { ++ throw std::runtime_error("invalid language"); ++ } ++ } ++ ++ void data::load(polyseed_storage storage) { ++ check_init(); ++ auto status = polyseed_load(storage, &m_data); ++ if (status != POLYSEED_OK) { ++ throw get_error(status); ++ } ++ } ++ ++ void data::load(const crypto::secret_key &key) { ++ polyseed_storage d; ++ memcpy(&d, &key.data, 32); ++ auto status = polyseed_load(d, &m_data); ++ if (status != POLYSEED_OK) { ++ throw get_error(status); ++ } ++ } ++ ++ language data::decode(const char* phrase) { ++ check_init(); ++ const polyseed_lang* lang; ++ auto status = polyseed_decode(phrase, m_coin, &lang, &m_data); ++ if (status != POLYSEED_OK) { ++ throw get_error(status); ++ } ++ return language(lang); ++ } ++} +diff --git a/src/polyseed/polyseed.hpp b/src/polyseed/polyseed.hpp +new file mode 100644 +index 000000000..2c8c777a7 +--- /dev/null ++++ b/src/polyseed/polyseed.hpp +@@ -0,0 +1,167 @@ ++// Copyright (c) 2023, The Monero Project ++// Copyright (c) 2021, tevador ++// ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// 1. Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// 2. Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in the ++// documentation and/or other materials provided with the distribution. ++// ++// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++// SUCH DAMAGE. ++ ++#ifndef POLYSEED_HPP ++#define POLYSEED_HPP ++ ++#include ++#include ++#include ++#include ++#include ++#include "crypto/crypto.h" ++ ++namespace polyseed { ++ ++ class data; ++ ++ class language { ++ public: ++ language() : m_lang(nullptr) {} ++ language(const language&) = default; ++ language(const polyseed_lang* lang) : m_lang(lang) {} ++ const char* name() const { ++ return polyseed_get_lang_name(m_lang); ++ } ++ const char* name_en() const { ++ return polyseed_get_lang_name_en(m_lang); ++ } ++ const char* separator() const { ++ return m_lang->separator; ++ } ++ bool valid() const { ++ return m_lang != nullptr; ++ } ++ ++ const polyseed_lang* m_lang; ++ private: ++ ++ friend class data; ++ }; ++ ++ const std::vector& get_langs(); ++ const language& get_lang_by_name(const std::string& name); ++ ++ class error : public std::runtime_error { ++ public: ++ error(const char* msg, polyseed_status status) ++ : std::runtime_error(msg), m_status(status) ++ { ++ } ++ polyseed_status status() const { ++ return m_status; ++ } ++ private: ++ polyseed_status m_status; ++ }; ++ ++ using feature_type = unsigned int; ++ ++ inline int enable_features(feature_type features) { ++ return polyseed_enable_features(features); ++ } ++ ++ class data { ++ public: ++ data(const data&) = delete; ++ data(polyseed_coin coin) : m_data(nullptr), m_coin(coin) {} ++ ~data() { ++ polyseed_free(m_data); ++ } ++ ++ void create(feature_type features); ++ ++ void load(polyseed_storage storage); ++ ++ void load(const crypto::secret_key &key); ++ ++ language decode(const char* phrase); ++ ++ template ++ void encode(const language& lang, str_type& str) const { ++ check_valid(); ++ if (!lang.valid()) { ++ throw std::runtime_error("invalid language"); ++ } ++ str.resize(POLYSEED_STR_SIZE); ++ auto size = polyseed_encode(m_data, lang.m_lang, m_coin, &str[0]); ++ str.resize(size); ++ } ++ ++ void split(const language& lang, polyseed_phrase& words); ++ ++ void save(polyseed_storage storage) const { ++ check_valid(); ++ polyseed_store(m_data, storage); ++ } ++ ++ void save(void *storage) const { ++ check_valid(); ++ polyseed_store(m_data, (uint8_t*)storage); ++ } ++ ++ void crypt(const char* password) { ++ check_valid(); ++ polyseed_crypt(m_data, password); ++ } ++ ++ void keygen(void* ptr, size_t key_size) const { ++ check_valid(); ++ polyseed_keygen(m_data, m_coin, key_size, (uint8_t*)ptr); ++ } ++ ++ bool valid() const { ++ return m_data != nullptr; ++ } ++ ++ bool encrypted() const { ++ check_valid(); ++ return polyseed_is_encrypted(m_data); ++ } ++ ++ uint64_t birthday() const { ++ check_valid(); ++ return polyseed_get_birthday(m_data); ++ } ++ ++ bool has_feature(feature_type feature) const { ++ check_valid(); ++ return polyseed_get_feature(m_data, feature) != 0; ++ } ++ private: ++ void check_valid() const { ++ if (m_data == nullptr) { ++ throw std::runtime_error("invalid object"); ++ } ++ } ++ void check_init() const; ++ ++ polyseed_data* m_data; ++ polyseed_coin m_coin; ++ }; ++} ++ ++#endif //POLYSEED_HPP +\ No newline at end of file +diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp +index 25ade04a7..51911bf99 100644 +--- a/src/wallet/api/wallet.cpp ++++ b/src/wallet/api/wallet.cpp +@@ -728,6 +728,28 @@ bool WalletImpl::recoverFromDevice(const std::string &path, const std::string &p + return true; + } + ++bool WalletImpl::createFromPolyseed(const std::string &path, const std::string &password, const std::string &seed, ++ const std::string &passphrase, bool newWallet, uint64_t restoreHeight) ++{ ++ clearStatus(); ++ m_recoveringFromSeed = !newWallet; ++ m_recoveringFromDevice = false; ++ ++ polyseed::data polyseed(POLYSEED_COIN); ++ ++ try { ++ auto lang = polyseed.decode(seed.data()); ++ m_wallet->set_seed_language(lang.name()); ++ m_wallet->generate(path, password, polyseed, passphrase, !newWallet); ++ } ++ catch (const std::exception &e) { ++ setStatusError(e.what()); ++ return false; ++ } ++ ++ return true; ++} ++ + Wallet::Device WalletImpl::getDeviceType() const + { + return static_cast(m_wallet->get_device_type()); +@@ -845,6 +867,54 @@ std::string WalletImpl::seed(const std::string& seed_offset) const + } + } + ++bool WalletImpl::getPolyseed(std::string &seed_words, std::string &passphrase) const ++{ ++ epee::wipeable_string seed_words_epee(seed_words.c_str(), seed_words.size()); ++ epee::wipeable_string passphrase_epee(passphrase.c_str(), passphrase.size()); ++ clearStatus(); ++ ++ if (!m_wallet) { ++ return false; ++ } ++ ++ bool result = m_wallet->get_polyseed(seed_words_epee, passphrase_epee); ++ ++ seed_words.assign(seed_words_epee.data(), seed_words_epee.size()); ++ passphrase.assign(passphrase_epee.data(), passphrase_epee.size()); ++ ++ return result; ++} ++ ++std::vector> Wallet::getPolyseedLanguages() ++ { ++ std::vector> languages; ++ ++ auto langs = polyseed::get_langs(); ++ for (const auto &lang : langs) { ++ languages.emplace_back(std::pair(lang.name_en(), lang.name())); ++ } ++ ++ return languages; ++} ++ ++bool Wallet::createPolyseed(std::string &seed_words, std::string &err, const std::string &language) ++{ ++ epee::wipeable_string seed_words_epee(seed_words.c_str(), seed_words.size()); ++ ++ try { ++ polyseed::data polyseed(POLYSEED_COIN); ++ polyseed.create(0); ++ polyseed.encode(polyseed::get_lang_by_name(language), seed_words_epee); ++ ++ seed_words.assign(seed_words_epee.data(), seed_words_epee.size()); ++ } ++ catch (const std::exception &e) { ++ err = e.what(); ++ return false; ++ } ++ ++ return true; ++} + std::string WalletImpl::getSeedLanguage() const + { + return m_wallet->get_seed_language(); +diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h +index 4e9c21ecb..32e12284b 100644 +--- a/src/wallet/api/wallet.h ++++ b/src/wallet/api/wallet.h +@@ -79,9 +79,19 @@ public: + bool recoverFromDevice(const std::string &path, + const std::string &password, + const std::string &device_name); ++ ++ bool createFromPolyseed(const std::string &path, ++ const std::string &password, ++ const std::string &seed, ++ const std::string &passphrase = "", ++ bool newWallet = true, ++ uint64_t restoreHeight = 0); ++ + Device getDeviceType() const override; + bool close(bool store = true); + std::string seed(const std::string& seed_offset = "") const override; ++ bool getPolyseed(std::string &seed_words, std::string &passphrase) const override; ++ + std::string getSeedLanguage() const override; + void setSeedLanguage(const std::string &arg) override; + // void setListener(Listener *) {} +diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h +index 53ec4abfc..be1c3704e 100644 +--- a/src/wallet/api/wallet2_api.h ++++ b/src/wallet/api/wallet2_api.h +@@ -709,6 +709,10 @@ struct Wallet + static void warning(const std::string &category, const std::string &str); + static void error(const std::string &category, const std::string &str); + ++ virtual bool getPolyseed(std::string &seed, std::string &passphrase) const = 0; ++ static bool createPolyseed(std::string &seed_words, std::string &err, const std::string &language = "English"); ++ static std::vector> getPolyseedLanguages(); ++ + /** + * @brief StartRefresh - Start/resume refresh thread (refresh every 10 seconds) + */ +@@ -1320,6 +1324,27 @@ struct WalletManager + uint64_t kdf_rounds = 1, + WalletListener * listener = nullptr) = 0; + ++ /*! ++ * \brief creates a wallet from a polyseed mnemonic phrase ++ * \param path Name of the wallet file to be created ++ * \param password Password of wallet file ++ * \param nettype Network type ++ * \param mnemonic Polyseed mnemonic ++ * \param passphrase Optional seed offset passphrase ++ * \param newWallet Whether it is a new wallet ++ * \param restoreHeight Override the embedded restore height ++ * \param kdf_rounds Number of rounds for key derivation function ++ * @return ++ */ ++ virtual Wallet * createWalletFromPolyseed(const std::string &path, ++ const std::string &password, ++ NetworkType nettype, ++ const std::string &mnemonic, ++ const std::string &passphrase = "", ++ bool newWallet = true, ++ uint64_t restore_height = 0, ++ uint64_t kdf_rounds = 1) = 0; ++ + /*! + * \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted + * \param wallet previously opened / created wallet instance +diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp +index 277be6ac9..da2056d8a 100644 +--- a/src/wallet/api/wallet_manager.cpp ++++ b/src/wallet/api/wallet_manager.cpp +@@ -156,6 +156,15 @@ Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path, + return wallet; + } + ++Wallet *WalletManagerImpl::createWalletFromPolyseed(const std::string &path, const std::string &password, NetworkType nettype, ++ const std::string &mnemonic, const std::string &passphrase, ++ bool newWallet, uint64_t restoreHeight, uint64_t kdf_rounds) ++{ ++ WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds); ++ wallet->createFromPolyseed(path, password, mnemonic, passphrase, newWallet, restoreHeight); ++ return wallet; ++} ++ + bool WalletManagerImpl::closeWallet(Wallet *wallet, bool store) + { + WalletImpl * wallet_ = dynamic_cast(wallet); +diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h +index a223e1df9..28fcd36c9 100644 +--- a/src/wallet/api/wallet_manager.h ++++ b/src/wallet/api/wallet_manager.h +@@ -75,6 +75,16 @@ public: + const std::string &subaddressLookahead = "", + uint64_t kdf_rounds = 1, + WalletListener * listener = nullptr) override; ++ ++ virtual Wallet * createWalletFromPolyseed(const std::string &path, ++ const std::string &password, ++ NetworkType nettype, ++ const std::string &mnemonic, ++ const std::string &passphrase, ++ bool newWallet = true, ++ uint64_t restore_height = 0, ++ uint64_t kdf_rounds = 1) override; ++ + virtual bool closeWallet(Wallet *wallet, bool store = true) override; + bool walletExists(const std::string &path) override; + bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const override; +diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp +index 765cefb32..806de969a 100644 +--- a/src/wallet/wallet2.cpp ++++ b/src/wallet/wallet2.cpp +@@ -92,6 +92,7 @@ using namespace epee; + #include "device/device_cold.hpp" + #include "device_trezor/device_trezor.hpp" + #include "net/socks_connect.h" ++#include "polyseed/include/polyseed.h" + + extern "C" + { +@@ -1278,7 +1279,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std + m_enable_multisig(false), + m_pool_info_query_time(0), + m_has_ever_refreshed_from_node(false), +- m_allow_mismatched_daemon_version(false) ++ m_allow_mismatched_daemon_version(false), ++ m_polyseed(false) + { + set_rpc_client_secret_key(rct::rct2sk(rct::skGen())); + } +@@ -1483,6 +1485,20 @@ bool wallet2::get_seed(epee::wipeable_string& electrum_words, const epee::wipeab + return true; + } + //---------------------------------------------------------------------------------------------------- ++ ++bool wallet2::get_polyseed(epee::wipeable_string& polyseed, epee::wipeable_string& passphrase) const ++{ ++ if (!m_polyseed) { ++ return false; ++ } ++ ++ polyseed::data data(POLYSEED_COIN); ++ data.load(get_account().get_keys().m_polyseed); ++ data.encode(polyseed::get_lang_by_name(seed_language), polyseed); ++ passphrase = get_account().get_keys().m_passphrase; ++ return true; ++} ++//---------------------------------------------------------------------------------------------------- + bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeable_string &passphrase) const + { + bool ready; +@@ -4800,6 +4816,9 @@ boost::optional wallet2::get_keys_file_data(const crypt + value2.SetInt(m_enable_multisig ? 1 : 0); + json.AddMember("enable_multisig", value2, json.GetAllocator()); + ++ value2.SetInt(m_polyseed ? 1 : 0); ++ json.AddMember("polyseed", value2, json.GetAllocator()); ++ + if (m_background_sync_type == BackgroundSyncCustomPassword && !background_keys_file && m_custom_background_key) + { + value.SetString(reinterpret_cast(m_custom_background_key.get().data()), m_custom_background_key.get().size()); +@@ -5039,6 +5058,7 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st + m_enable_multisig = false; + m_allow_mismatched_daemon_version = false; + m_custom_background_key = boost::none; ++ m_polyseed = false; + } + else if(json.IsObject()) + { +@@ -5279,6 +5299,9 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, background_sync_type, BackgroundSyncType, Int, false, BackgroundSyncOff); + m_background_sync_type = field_background_sync_type; + ++ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, polyseed, int, Int, false, false); ++ m_polyseed = field_polyseed; ++ + // Load encryption key used to encrypt background cache + crypto::chacha_key custom_background_key; + m_custom_background_key = boost::none; +@@ -5598,6 +5621,48 @@ void wallet2::init_type(hw::device::device_type device_type) + m_key_device_type = device_type; + } + ++/*! ++ * \brief Generates a polyseed wallet or restores one. ++ * \param wallet_ Name of wallet file ++ * \param password Password of wallet file ++ * \param passphrase Seed offset passphrase ++ * \param recover Whether it is a restore ++ * \param seed_words If it is a restore, the polyseed ++ * \param create_address_file Whether to create an address file ++ * \return The secret key of the generated wallet ++ */ ++void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password, ++ const polyseed::data &seed, const epee::wipeable_string& passphrase, bool recover, uint64_t restoreHeight, bool create_address_file) ++{ ++ clear(); ++ prepare_file_names(wallet_); ++ ++ if (!wallet_.empty()) { ++ boost::system::error_code ignored_ec; ++ THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file); ++ THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file); ++ } ++ ++ m_account.create_from_polyseed(seed, passphrase); ++ ++ init_type(hw::device::device_type::SOFTWARE); ++ m_polyseed = true; ++ setup_keys(password); ++ ++ if (recover) { ++ m_refresh_from_block_height = estimate_blockchain_height(restoreHeight > 0 ? restoreHeight : seed.birthday()); ++ } else { ++ m_refresh_from_block_height = estimate_blockchain_height(); ++ } ++ ++ create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file); ++ ++ setup_new_blockchain(); ++ ++ if (!wallet_.empty()) ++ store(); ++} ++ + /*! + * \brief Generates a wallet or restores one. Assumes the multisig setup + * has already completed for the provided multisig info. +@@ -5725,7 +5790,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip + return retval; + } + +- uint64_t wallet2::estimate_blockchain_height() ++ uint64_t wallet2::estimate_blockchain_height(uint64_t time) + { + // -1 month for fluctuations in block time and machine date/time setup. + // avg seconds per block +@@ -5749,7 +5814,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip + // the daemon is currently syncing. + // If we use the approximate height we subtract one month as + // a safety margin. +- height = get_approximate_blockchain_height(); ++ height = get_approximate_blockchain_height(time); + uint64_t target_height = get_daemon_blockchain_target_height(err); + if (err.empty()) { + if (target_height < height) +@@ -13646,7 +13711,7 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err) + return target_height; + } + +-uint64_t wallet2::get_approximate_blockchain_height() const ++uint64_t wallet2::get_approximate_blockchain_height(uint64_t t) const + { + // time of v2 fork + const time_t fork_time = m_nettype == TESTNET ? 1448285909 : m_nettype == STAGENET ? 1520937818 : 1458748658; +@@ -13655,7 +13720,7 @@ uint64_t wallet2::get_approximate_blockchain_height() const + // avg seconds per block + const int seconds_per_block = DIFFICULTY_TARGET_V2; + // Calculated blockchain height +- uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block; ++ uint64_t approx_blockchain_height = fork_block + ((t > 0 ? t : time(NULL)) - fork_time)/seconds_per_block; + // testnet and stagenet got some huge rollbacks, so the estimation is way off + static const uint64_t approximate_rolled_back_blocks = m_nettype == TESTNET ? 342100 : m_nettype == STAGENET ? 60000 : 30000; + if ((m_nettype == TESTNET || m_nettype == STAGENET) && approx_blockchain_height > approximate_rolled_back_blocks) +@@ -15794,15 +15859,6 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin + //---------------------------------------------------------------------------------------------------- + uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day) + { +- uint32_t version; +- if (!check_connection(&version)) +- { +- throw std::runtime_error("failed to connect to daemon: " + get_daemon_address()); +- } +- if (version < MAKE_CORE_RPC_VERSION(1, 6)) +- { +- throw std::runtime_error("this function requires RPC version 1.6 or higher"); +- } + std::tm date = { 0, 0, 0, 0, 0, 0, 0, 0 }; + date.tm_year = year - 1900; + date.tm_mon = month - 1; +@@ -15811,7 +15867,23 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui + { + throw std::runtime_error("month or day out of range"); + } ++ + uint64_t timestamp_target = std::mktime(&date); ++ ++ return get_blockchain_height_by_timestamp(timestamp_target); ++} ++ ++uint64_t wallet2::get_blockchain_height_by_timestamp(uint64_t timestamp_target) { ++ uint32_t version; ++ if (!check_connection(&version)) ++ { ++ throw std::runtime_error("failed to connect to daemon: " + get_daemon_address()); ++ } ++ if (version < MAKE_CORE_RPC_VERSION(1, 6)) ++ { ++ throw std::runtime_error("this function requires RPC version 1.6 or higher"); ++ } ++ + std::string err; + uint64_t height_min = 0; + uint64_t height_max = get_daemon_blockchain_height(err) - 1; +diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h +index a752f15b9..a619bdd15 100644 +--- a/src/wallet/wallet2.h ++++ b/src/wallet/wallet2.h +@@ -72,6 +72,7 @@ + #include "message_store.h" + #include "wallet_light_rpc.h" + #include "wallet_rpc_helpers.h" ++#include "polyseed/polyseed.hpp" + + #undef MONERO_DEFAULT_LOG_CATEGORY + #define MONERO_DEFAULT_LOG_CATEGORY "wallet.wallet2" +@@ -921,6 +922,20 @@ private: + void generate(const std::string& wallet_, const epee::wipeable_string& password, + const epee::wipeable_string& multisig_data, bool create_address_file = false); + ++ /*! ++ * \brief Generates a wallet from a polyseed. ++ * @param wallet_ Name of wallet file ++ * @param password Password of wallet file ++ * @param seed Polyseed data ++ * @param passphrase Optional seed offset passphrase ++ * @param recover Whether it is a restore ++ * @param restoreHeight Override the embedded restore height ++ * @param create_address_file Whether to create an address file ++ */ ++ void generate(const std::string& wallet_, const epee::wipeable_string& password, ++ const polyseed::data &seed, const epee::wipeable_string& passphrase = "", ++ bool recover = false, uint64_t restoreHeight = 0, bool create_address_file = false); ++ + /*! + * \brief Generates a wallet or restores one. + * \param wallet_ Name of wallet file +@@ -1095,6 +1110,15 @@ private: + bool is_deterministic() const; + bool get_seed(epee::wipeable_string& electrum_words, const epee::wipeable_string &passphrase = epee::wipeable_string()) const; + ++ /*! ++ * \brief get_polyseed Gets the polyseed (if available) and passphrase (if set) needed to recover the wallet. ++ * @param seed Polyseed mnemonic phrase ++ * @param passphrase Seed offset passphrase that was used to restore the wallet ++ * @return Returns true if the wallet has a polyseed. ++ * Note: both the mnemonic phrase and the passphrase are needed to recover the wallet ++ */ ++ bool get_polyseed(epee::wipeable_string& seed, epee::wipeable_string &passphrase) const; ++ + /*! + * \brief Checks if light wallet. A light wallet sends view key to a server where the blockchain is scanned. + */ +@@ -1562,8 +1586,8 @@ private: + /*! + * \brief Calculates the approximate blockchain height from current date/time. + */ +- uint64_t get_approximate_blockchain_height() const; +- uint64_t estimate_blockchain_height(); ++ uint64_t get_approximate_blockchain_height(uint64_t time = 0) const; ++ uint64_t estimate_blockchain_height(uint64_t time = 0); + std::vector select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct); + std::vector select_available_outputs(const std::function &f); + std::vector select_available_unmixable_outputs(); +@@ -1657,6 +1681,7 @@ private: + bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error); + + uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31 ++ uint64_t get_blockchain_height_by_timestamp(uint64_t timestamp); + + bool is_synced(); + +@@ -2003,6 +2028,7 @@ private: + std::string seed_language; /*!< Language of the mnemonics (seed). */ + bool is_old_file_format; /*!< Whether the wallet file is of an old file format */ + bool m_watch_only; /*!< no spend key */ ++ bool m_polyseed; + bool m_multisig; /*!< if > 1 spend secret key will not match spend public key */ + uint32_t m_multisig_threshold; + std::vector m_multisig_signers; +-- +2.48.1 + diff --git a/patches/salvium/0008-coin-control.patch b/patches/salvium/0008-coin-control.patch new file mode 100644 index 0000000..442921d --- /dev/null +++ b/patches/salvium/0008-coin-control.patch @@ -0,0 +1,1099 @@ +From 753d7eee48d8e9ab5950e48dc984cc1038c11dd1 Mon Sep 17 00:00:00 2001 +From: tobtoht +Date: Tue, 12 Mar 2024 11:07:57 +0100 +Subject: [PATCH 08/14] coin control + +--- + src/simplewallet/simplewallet.cpp | 2 +- + src/wallet/api/CMakeLists.txt | 8 +- + src/wallet/api/coins.cpp | 186 ++++++++++++++++++++++++++++++ + src/wallet/api/coins.h | 40 +++++++ + src/wallet/api/coins_info.cpp | 122 ++++++++++++++++++++ + src/wallet/api/coins_info.h | 71 ++++++++++++ + src/wallet/api/wallet.cpp | 170 +++++++++++++++++++++------ + src/wallet/api/wallet.h | 10 +- + src/wallet/api/wallet2_api.h | 52 ++++++++- + src/wallet/wallet2.cpp | 46 +++++++- + src/wallet/wallet2.h | 11 +- + 11 files changed, 667 insertions(+), 51 deletions(-) + create mode 100644 src/wallet/api/coins.cpp + create mode 100644 src/wallet/api/coins.h + create mode 100644 src/wallet/api/coins_info.cpp + create mode 100644 src/wallet/api/coins_info.h + +diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp +index 89691e9f7..b26817e52 100644 +--- a/src/simplewallet/simplewallet.cpp ++++ b/src/simplewallet/simplewallet.cpp +@@ -6930,7 +6930,7 @@ bool simple_wallet::transfer_main(const std::vector &args_, bool ca + { + // figure out what tx will be necessary + auto ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, priority, extra, +- m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs); ++ m_current_subaddress_account, subaddr_indices, {}, subtract_fee_from_outputs); + + if (ptx_vector.empty()) + { +diff --git a/src/wallet/api/CMakeLists.txt b/src/wallet/api/CMakeLists.txt +index af7948d8a..bb740e2ac 100644 +--- a/src/wallet/api/CMakeLists.txt ++++ b/src/wallet/api/CMakeLists.txt +@@ -40,7 +40,9 @@ set(wallet_api_sources + address_book.cpp + subaddress.cpp + subaddress_account.cpp +- unsigned_transaction.cpp) ++ unsigned_transaction.cpp ++ coins.cpp ++ coins_info.cpp) + + set(wallet_api_headers + wallet2_api.h) +@@ -55,7 +57,9 @@ set(wallet_api_private_headers + address_book.h + subaddress.h + subaddress_account.h +- unsigned_transaction.h) ++ unsigned_transaction.h ++ coins.h ++ coins_info.h) + + monero_private_headers(wallet_api + ${wallet_api_private_headers}) +diff --git a/src/wallet/api/coins.cpp b/src/wallet/api/coins.cpp +new file mode 100644 +index 000000000..ef12141cf +--- /dev/null ++++ b/src/wallet/api/coins.cpp +@@ -0,0 +1,186 @@ ++#include "coins.h" ++#include "coins_info.h" ++#include "wallet.h" ++#include "crypto/hash.h" ++#include "wallet/wallet2.h" ++#include "common_defines.h" ++ ++#include ++#include ++ ++using namespace epee; ++ ++namespace Monero { ++ ++Coins::~Coins() = default; ++ ++CoinsImpl::CoinsImpl(WalletImpl *wallet) ++ : m_wallet(wallet) {} ++ ++CoinsImpl::~CoinsImpl() ++{ ++ for (auto t : m_rows) ++ delete t; ++} ++ ++int CoinsImpl::count() const ++{ ++ boost::shared_lock lock(m_rowsMutex); ++ int result = m_rows.size(); ++ return result; ++} ++ ++CoinsInfo *CoinsImpl::coin(int index) const ++{ ++ boost::shared_lock lock(m_rowsMutex); ++ // sanity check ++ if (index < 0) ++ return nullptr; ++ auto index_ = static_cast(index); ++ return index_ < m_rows.size() ? m_rows[index_] : nullptr; ++} ++ ++std::vector CoinsImpl::getAll() const ++{ ++ boost::shared_lock lock(m_rowsMutex); ++ return m_rows; ++} ++ ++ ++void CoinsImpl::refresh() ++{ ++ LOG_PRINT_L2("Refreshing coins"); ++ ++ boost::unique_lock lock(m_rowsMutex); ++ boost::shared_lock transfers_lock(m_wallet->m_wallet->m_transfers_mutex); ++ ++ // delete old outputs; ++ for (auto t : m_rows) ++ delete t; ++ m_rows.clear(); ++ ++ for (size_t i = 0; i < m_wallet->m_wallet->get_num_transfer_details(); ++i) ++ { ++ const tools::wallet2::transfer_details &td = m_wallet->m_wallet->get_transfer_details(i); ++ ++ auto ci = new CoinsInfoImpl(); ++ ci->m_blockHeight = td.m_block_height; ++ ci->m_hash = string_tools::pod_to_hex(td.m_txid); ++ ci->m_internalOutputIndex = td.m_internal_output_index; ++ ci->m_globalOutputIndex = td.m_global_output_index; ++ ci->m_spent = td.m_spent; ++ ci->m_frozen = td.m_frozen; ++ ci->m_spentHeight = td.m_spent_height; ++ ci->m_amount = td.m_amount; ++ ci->m_rct = td.m_rct; ++ ci->m_keyImageKnown = td.m_key_image_known; ++ ci->m_pkIndex = td.m_pk_index; ++ ci->m_subaddrIndex = td.m_subaddr_index.minor; ++ ci->m_subaddrAccount = td.m_subaddr_index.major; ++ ci->m_address = m_wallet->m_wallet->get_subaddress_as_str(td.m_subaddr_index); // todo: this is expensive, cache maybe? ++ ci->m_addressLabel = m_wallet->m_wallet->get_subaddress_label(td.m_subaddr_index); ++ ci->m_keyImage = string_tools::pod_to_hex(td.m_key_image); ++ ci->m_unlockTime = td.m_tx.unlock_time; ++ ci->m_unlocked = m_wallet->m_wallet->is_transfer_unlocked(td); ++ ci->m_pubKey = string_tools::pod_to_hex(td.get_public_key()); ++ ci->m_coinbase = td.m_tx.vin.size() == 1 && td.m_tx.vin[0].type() == typeid(cryptonote::txin_gen); ++ ci->m_description = m_wallet->m_wallet->get_tx_note(td.m_txid); ++ ++ m_rows.push_back(ci); ++ } ++} ++ ++void CoinsImpl::setFrozen(std::string public_key) ++{ ++ crypto::public_key pk; ++ if (!epee::string_tools::hex_to_pod(public_key, pk)) ++ { ++ LOG_ERROR("Invalid public key: " << public_key); ++ return; ++ } ++ ++ try ++ { ++ m_wallet->m_wallet->freeze(pk); ++ refresh(); ++ } ++ catch (const std::exception& e) ++ { ++ LOG_ERROR("setFrozen: " << e.what()); ++ } ++} ++ ++void CoinsImpl::setFrozen(int index) ++{ ++ try ++ { ++ LOG_ERROR("Freezing coin: " << index); ++ m_wallet->m_wallet->freeze(index); ++ refresh(); ++ } ++ catch (const std::exception& e) ++ { ++ LOG_ERROR("setLabel: " << e.what()); ++ } ++} ++ ++void CoinsImpl::thaw(std::string public_key) ++{ ++ crypto::public_key pk; ++ if (!epee::string_tools::hex_to_pod(public_key, pk)) ++ { ++ LOG_ERROR("Invalid public key: " << public_key); ++ return; ++ } ++ ++ try ++ { ++ m_wallet->m_wallet->thaw(pk); ++ refresh(); ++ } ++ catch (const std::exception& e) ++ { ++ LOG_ERROR("thaw: " << e.what()); ++ } ++} ++ ++void CoinsImpl::thaw(int index) ++{ ++ try ++ { ++ m_wallet->m_wallet->thaw(index); ++ refresh(); ++ } ++ catch (const std::exception& e) ++ { ++ LOG_ERROR("thaw: " << e.what()); ++ } ++} ++ ++bool CoinsImpl::isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) { ++ return m_wallet->m_wallet->is_transfer_unlocked(unlockTime, blockHeight); ++} ++ ++void CoinsImpl::setDescription(const std::string &public_key, const std::string &description) ++{ ++ crypto::public_key pk; ++ if (!epee::string_tools::hex_to_pod(public_key, pk)) ++ { ++ LOG_ERROR("Invalid public key: " << public_key); ++ return; ++ } ++ ++ try ++ { ++ const size_t index = m_wallet->m_wallet->get_transfer_details(pk); ++ const tools::wallet2::transfer_details &td = m_wallet->m_wallet->get_transfer_details(index); ++ m_wallet->m_wallet->set_tx_note(td.m_txid, description); ++ refresh(); ++ } ++ catch (const std::exception& e) ++ { ++ LOG_ERROR("setDescription: " << e.what()); ++ } ++} ++ ++} // namespace +diff --git a/src/wallet/api/coins.h b/src/wallet/api/coins.h +new file mode 100644 +index 000000000..b7a0a8642 +--- /dev/null ++++ b/src/wallet/api/coins.h +@@ -0,0 +1,40 @@ ++#ifndef FEATHER_COINS_H ++#define FEATHER_COINS_H ++ ++#include "wallet/api/wallet2_api.h" ++#include "wallet/wallet2.h" ++ ++namespace Monero { ++ ++class WalletImpl; ++ ++class CoinsImpl : public Coins ++{ ++public: ++ explicit CoinsImpl(WalletImpl * wallet); ++ ~CoinsImpl() override; ++ int count() const override; ++ CoinsInfo * coin(int index) const override; ++ std::vector getAll() const override; ++ void refresh() override; ++ ++ void setFrozen(std::string public_key) override; ++ void setFrozen(int index) override; ++ void thaw(std::string public_key) override; ++ void thaw(int index) override; ++ ++ bool isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) override; ++ ++ void setDescription(const std::string &public_key, const std::string &description) override; ++ ++private: ++ WalletImpl *m_wallet; ++ std::vector m_rows; ++ mutable boost::shared_mutex m_rowsMutex; ++}; ++ ++} ++ ++namespace Bitmonero = Monero; ++ ++#endif //FEATHER_COINS_H +diff --git a/src/wallet/api/coins_info.cpp b/src/wallet/api/coins_info.cpp +new file mode 100644 +index 000000000..5f2c4e1e4 +--- /dev/null ++++ b/src/wallet/api/coins_info.cpp +@@ -0,0 +1,122 @@ ++#include "coins_info.h" ++ ++using namespace std; ++ ++namespace Monero { ++ ++CoinsInfo::~CoinsInfo() = default; ++ ++CoinsInfoImpl::CoinsInfoImpl() ++ : m_blockHeight(0) ++ , m_internalOutputIndex(0) ++ , m_globalOutputIndex(0) ++ , m_spent(false) ++ , m_frozen(false) ++ , m_spentHeight(0) ++ , m_amount(0) ++ , m_rct(false) ++ , m_keyImageKnown(false) ++ , m_pkIndex(0) ++ , m_subaddrAccount(0) ++ , m_subaddrIndex(0) ++ , m_unlockTime(0) ++ , m_unlocked(false) ++{ ++ ++} ++ ++CoinsInfoImpl::~CoinsInfoImpl() = default; ++ ++uint64_t CoinsInfoImpl::blockHeight() const ++{ ++ return m_blockHeight; ++} ++ ++string CoinsInfoImpl::hash() const ++{ ++ return m_hash; ++} ++ ++size_t CoinsInfoImpl::internalOutputIndex() const { ++ return m_internalOutputIndex; ++} ++ ++uint64_t CoinsInfoImpl::globalOutputIndex() const ++{ ++ return m_globalOutputIndex; ++} ++ ++bool CoinsInfoImpl::spent() const ++{ ++ return m_spent; ++} ++ ++bool CoinsInfoImpl::frozen() const ++{ ++ return m_frozen; ++} ++ ++uint64_t CoinsInfoImpl::spentHeight() const ++{ ++ return m_spentHeight; ++} ++ ++uint64_t CoinsInfoImpl::amount() const ++{ ++ return m_amount; ++} ++ ++bool CoinsInfoImpl::rct() const { ++ return m_rct; ++} ++ ++bool CoinsInfoImpl::keyImageKnown() const { ++ return m_keyImageKnown; ++} ++ ++size_t CoinsInfoImpl::pkIndex() const { ++ return m_pkIndex; ++} ++ ++uint32_t CoinsInfoImpl::subaddrIndex() const { ++ return m_subaddrIndex; ++} ++ ++uint32_t CoinsInfoImpl::subaddrAccount() const { ++ return m_subaddrAccount; ++} ++ ++string CoinsInfoImpl::address() const { ++ return m_address; ++} ++ ++string CoinsInfoImpl::addressLabel() const { ++ return m_addressLabel; ++} ++ ++string CoinsInfoImpl::keyImage() const { ++ return m_keyImage; ++} ++ ++uint64_t CoinsInfoImpl::unlockTime() const { ++ return m_unlockTime; ++} ++ ++bool CoinsInfoImpl::unlocked() const { ++ return m_unlocked; ++} ++ ++string CoinsInfoImpl::pubKey() const { ++ return m_pubKey; ++} ++ ++bool CoinsInfoImpl::coinbase() const { ++ return m_coinbase; ++} ++ ++string CoinsInfoImpl::description() const { ++ return m_description; ++} ++} // namespace ++ ++namespace Bitmonero = Monero; +diff --git a/src/wallet/api/coins_info.h b/src/wallet/api/coins_info.h +new file mode 100644 +index 000000000..c43e45abd +--- /dev/null ++++ b/src/wallet/api/coins_info.h +@@ -0,0 +1,71 @@ ++#ifndef FEATHER_COINS_INFO_H ++#define FEATHER_COINS_INFO_H ++ ++#include "wallet/api/wallet2_api.h" ++#include ++#include ++ ++namespace Monero { ++ ++class CoinsImpl; ++ ++class CoinsInfoImpl : public CoinsInfo ++{ ++public: ++ CoinsInfoImpl(); ++ ~CoinsInfoImpl(); ++ ++ virtual uint64_t blockHeight() const override; ++ virtual std::string hash() const override; ++ virtual size_t internalOutputIndex() const override; ++ virtual uint64_t globalOutputIndex() const override; ++ virtual bool spent() const override; ++ virtual bool frozen() const override; ++ virtual uint64_t spentHeight() const override; ++ virtual uint64_t amount() const override; ++ virtual bool rct() const override; ++ virtual bool keyImageKnown() const override; ++ virtual size_t pkIndex() const override; ++ virtual uint32_t subaddrIndex() const override; ++ virtual uint32_t subaddrAccount() const override; ++ virtual std::string address() const override; ++ virtual std::string addressLabel() const override; ++ virtual std::string keyImage() const override; ++ virtual uint64_t unlockTime() const override; ++ virtual bool unlocked() const override; ++ virtual std::string pubKey() const override; ++ virtual bool coinbase() const override; ++ virtual std::string description() const override; ++ ++private: ++ uint64_t m_blockHeight; ++ std::string m_hash; ++ size_t m_internalOutputIndex; ++ uint64_t m_globalOutputIndex; ++ bool m_spent; ++ bool m_frozen; ++ uint64_t m_spentHeight; ++ uint64_t m_amount; ++ bool m_rct; ++ bool m_keyImageKnown; ++ size_t m_pkIndex; ++ uint32_t m_subaddrIndex; ++ uint32_t m_subaddrAccount; ++ std::string m_address; ++ std::string m_addressLabel; ++ std::string m_keyImage; ++ uint64_t m_unlockTime; ++ bool m_unlocked; ++ std::string m_pubKey; ++ bool m_coinbase; ++ std::string m_description; ++ ++ friend class CoinsImpl; ++ ++}; ++ ++} // namespace ++ ++namespace Bitmonero = Monero; ++ ++#endif //FEATHER_COINS_INFO_H +diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp +index 51911bf99..933cc2531 100644 +--- a/src/wallet/api/wallet.cpp ++++ b/src/wallet/api/wallet.cpp +@@ -35,6 +35,7 @@ + #include "transaction_history.h" + #include "address_book.h" + #include "subaddress.h" ++#include "coins.h" + #include "subaddress_account.h" + #include "common_defines.h" + #include "common/util.h" +@@ -473,6 +474,7 @@ WalletImpl::WalletImpl(NetworkType nettype, uint64_t kdf_rounds) + m_wallet->set_refresh_enabled(false); + m_addressBook.reset(new AddressBookImpl(this)); + m_subaddress.reset(new SubaddressImpl(this)); ++ m_coins.reset(new CoinsImpl(this)); + m_subaddressAccount.reset(new SubaddressAccountImpl(this)); + + +@@ -2046,7 +2048,7 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat + // - unconfirmed_transfer_details; + // - confirmed_transfer_details) + +-PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector &dst_addr, const string &payment_id, optional> amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices) ++PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector &dst_addr, const string &payment_id, optional> amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices, const std::set &preferred_inputs) + + { + clearStatus(); +@@ -2083,57 +2085,116 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vectornettype(), dst_addr[i])) { +- // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 +- setStatusError(tr("Invalid destination address")); +- error = true; +- break; +- } +- if (info.has_payment_id) { +- if (!extra_nonce.empty()) { +- setStatusError(tr("a single transaction cannot use more than one payment id")); ++ uint64_t max_coin_control_input = 0; ++ uint64_t max_frozen_input = 0; ++ try { ++ bool error = false; ++ uint64_t amountSum = 0; ++ for (size_t i = 0; i < dst_addr.size() && !error; i++) { ++ if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), dst_addr[i])) { ++ // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 ++ setStatusError(tr("Invalid destination address")); + error = true; + break; + } +- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id); ++ if (info.has_payment_id) { ++ if (!extra_nonce.empty()) { ++ setStatusError(tr("a single transaction cannot use more than one payment id")); ++ error = true; ++ break; ++ } ++ set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id); ++ } ++ ++ if (amount) { ++ cryptonote::tx_destination_entry de; ++ de.original = dst_addr[i]; ++ de.addr = info.address; ++ de.amount = (*amount)[i]; ++ amountSum += (*amount)[i]; ++ de.is_subaddress = info.is_subaddress; ++ de.is_integrated = info.has_payment_id; ++ dsts.push_back(de); ++ } else { ++ if (subaddr_indices.empty()) { ++ for (uint32_t index = 0; index < m_wallet->get_num_subaddresses(subaddr_account); ++index) ++ subaddr_indices.insert(index); ++ } ++ } + } ++ // uint64_t maxAllowedSpend = m_wallet->unlocked_balance(subaddr_account, true); ++ // if (maxAllowedSpend < amountSum) { ++ // error = true; ++ // setStatusError(tr("Amount you are trying to spend is larger than unlocked amount")); ++ // break; ++ // } ++ std::vector preferred_input_list; ++ if (!preferred_inputs.empty()) { ++ LOG_ERROR("not empty"); ++ ++ for (const auto &public_key : preferred_inputs) { ++ crypto::key_image keyImage; ++ bool r = epee::string_tools::hex_to_pod(public_key, keyImage); ++ if (!r) { ++ error = true; ++ setStatusError(tr("failed to parse key image")); ++ break; ++ } ++ if (m_wallet->frozen(keyImage)) { ++ error = true; ++ setStatusError(tr("refusing to spend frozen coin")); ++ break; ++ } + +- if (amount) { +- cryptonote::tx_destination_entry de; +- de.original = dst_addr[i]; +- de.addr = info.address; +- de.amount = (*amount)[i]; +- de.is_subaddress = info.is_subaddress; +- de.is_integrated = info.has_payment_id; +- dsts.push_back(de); ++ for (size_t i = 0; i < m_wallet->get_num_transfer_details(); ++i) { ++ const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(i); ++ if (td.m_key_image == keyImage) { ++ max_coin_control_input += td.amount(); ++ } ++ if (td.m_frozen) { ++ max_frozen_input += td.amount(); ++ } ++ } ++ ++ preferred_input_list.push_back(keyImage); ++ } + } else { +- if (subaddr_indices.empty()) { +- for (uint32_t index = 0; index < m_wallet->get_num_subaddresses(subaddr_account); ++index) +- subaddr_indices.insert(index); ++ LOG_ERROR("not empty"); ++ ++ boost::shared_lock transfers_lock(m_wallet->m_transfers_mutex); ++ for (size_t i = 0; i < m_wallet->get_num_transfer_details(); ++i) { ++ const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(i); ++ LOG_ERROR("COIN: " << i << ": " << td.amount() << "; "<frozen(td)); ++ if (td.m_spent) continue; ++ LOG_ERROR("is frozen"); ++ if (!td.m_frozen) { ++ LOG_ERROR("isn't:"); ++ LOG_ERROR("hash: " << td.m_key_image << "; " << td.amount()); ++ preferred_input_list.push_back(td.m_key_image); ++ } + } + } +- } +- if (error) { +- break; +- } +- if (!extra_nonce.empty() && !add_extra_nonce_to_tx_extra(extra, extra_nonce)) { +- setStatusError(tr("failed to set up payment id, though it was decoded correctly")); +- break; +- } +- try { ++ for (const auto &de : preferred_input_list) { ++ LOG_ERROR("preferred input: " << de); ++ } ++ if (error) { ++ break; ++ } ++ if (!extra_nonce.empty() && !add_extra_nonce_to_tx_extra(extra, extra_nonce)) { ++ setStatusError(tr("failed to set up payment id, though it was decoded correctly")); ++ break; ++ } + size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin(); + fake_outs_count = m_wallet->adjust_mixin(mixin_count); + + if (amount) { + transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, + adjusted_priority, +- extra, subaddr_account, subaddr_indices); ++ extra, subaddr_account, subaddr_indices, preferred_input_list); + } else { + transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count, + adjusted_priority, +- extra, subaddr_account, subaddr_indices); ++ extra, subaddr_account, subaddr_indices, preferred_input_list); + } + pendingTxPostProcess(transaction); + +@@ -2157,6 +2218,16 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector amount, uint32_t mixin_count, +- PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices) ++ PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices, const std::set &preferred_inputs) + + { +- return createTransactionMultDest(std::vector {dst_addr}, payment_id, amount ? (std::vector {*amount}) : (optional>()), mixin_count, priority, subaddr_account, subaddr_indices); ++ return createTransactionMultDest(std::vector {dst_addr}, payment_id, amount ? (std::vector {*amount}) : (optional>()), mixin_count, priority, subaddr_account, subaddr_indices, preferred_inputs); + } + + PendingTransaction *WalletImpl::createSweepUnmixableTransaction() +@@ -2342,6 +2433,11 @@ AddressBook *WalletImpl::addressBook() + return m_addressBook.get(); + } + ++Coins *WalletImpl::coins() ++{ ++ return m_coins.get(); ++} ++ + Subaddress *WalletImpl::subaddress() + { + return m_subaddress.get(); +diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h +index 32e12284b..a82f270e4 100644 +--- a/src/wallet/api/wallet.h ++++ b/src/wallet/api/wallet.h +@@ -46,6 +46,7 @@ class PendingTransactionImpl; + class UnsignedTransactionImpl; + class AddressBookImpl; + class SubaddressImpl; ++class CoinsImpl; + class SubaddressAccountImpl; + struct Wallet2CallbackImpl; + +@@ -167,12 +168,14 @@ public: + optional> amount, uint32_t mixin_count, + PendingTransaction::Priority priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, +- std::set subaddr_indices = {}) override; ++ std::set subaddr_indices = {}, ++ const std::set &preferred_inputs = {}) override; + PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, + optional amount, uint32_t mixin_count, + PendingTransaction::Priority priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, +- std::set subaddr_indices = {}) override; ++ std::set subaddr_indices = {}, ++ const std::set &preferred_inputs = {}) override; + virtual PendingTransaction * createSweepUnmixableTransaction() override; + bool submitTransaction(const std::string &fileName) override; + bool submitTransactionUR(const std::string &input) override; +@@ -201,6 +204,7 @@ public: + PendingTransaction::Priority priority) const override; + virtual TransactionHistory * history() override; + virtual AddressBook * addressBook() override; ++ virtual Coins * coins() override; + virtual Subaddress * subaddress() override; + virtual SubaddressAccount * subaddressAccount() override; + virtual void setListener(WalletListener * l) override; +@@ -272,6 +276,7 @@ private: + friend class TransactionHistoryImpl; + friend struct Wallet2CallbackImpl; + friend class AddressBookImpl; ++ friend class CoinsImpl; + friend class SubaddressImpl; + friend class SubaddressAccountImpl; + +@@ -288,6 +293,7 @@ private: + std::unique_ptr m_wallet2Callback; + std::unique_ptr m_addressBook; + std::unique_ptr m_subaddress; ++ std::unique_ptr m_coins; + std::unique_ptr m_subaddressAccount; + + // multi-threaded refresh stuff +diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h +index be1c3704e..013b5bcba 100644 +--- a/src/wallet/api/wallet2_api.h ++++ b/src/wallet/api/wallet2_api.h +@@ -263,6 +263,51 @@ struct AddressBook + virtual int lookupPaymentID(const std::string &payment_id) const = 0; + }; + ++/** ++ * @brief The CoinsInfo - interface for displaying coins information ++ */ ++struct CoinsInfo ++{ ++ virtual ~CoinsInfo() = 0; ++ ++ virtual uint64_t blockHeight() const = 0; ++ virtual std::string hash() const = 0; ++ virtual size_t internalOutputIndex() const = 0; ++ virtual uint64_t globalOutputIndex() const = 0; ++ virtual bool spent() const = 0; ++ virtual bool frozen() const = 0; ++ virtual uint64_t spentHeight() const = 0; ++ virtual uint64_t amount() const = 0; ++ virtual bool rct() const = 0; ++ virtual bool keyImageKnown() const = 0; ++ virtual size_t pkIndex() const = 0; ++ virtual uint32_t subaddrIndex() const = 0; ++ virtual uint32_t subaddrAccount() const = 0; ++ virtual std::string address() const = 0; ++ virtual std::string addressLabel() const = 0; ++ virtual std::string keyImage() const = 0; ++ virtual uint64_t unlockTime() const = 0; ++ virtual bool unlocked() const = 0; ++ virtual std::string pubKey() const = 0; ++ virtual bool coinbase() const = 0; ++ virtual std::string description() const = 0; ++}; ++ ++struct Coins ++{ ++ virtual ~Coins() = 0; ++ virtual int count() const = 0; ++ virtual CoinsInfo * coin(int index) const = 0; ++ virtual std::vector getAll() const = 0; ++ virtual void refresh() = 0; ++ virtual void setFrozen(std::string public_key) = 0; ++ virtual void setFrozen(int index) = 0; ++ virtual void thaw(std::string public_key) = 0; ++ virtual void thaw(int index) = 0; ++ virtual bool isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) = 0; ++ virtual void setDescription(const std::string &public_key, const std::string &description) = 0; ++}; ++ + struct SubaddressRow { + public: + SubaddressRow(std::size_t _rowId, const std::string &_address, const std::string &_label): +@@ -856,7 +901,8 @@ struct Wallet + optional> amount, uint32_t mixin_count, + PendingTransaction::Priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, +- std::set subaddr_indices = {}) = 0; ++ std::set subaddr_indices = {}, ++ const std::set &preferred_inputs = {}) = 0; + + /*! + * \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored +@@ -875,7 +921,8 @@ struct Wallet + optional amount, uint32_t mixin_count, + PendingTransaction::Priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, +- std::set subaddr_indices = {}) = 0; ++ std::set subaddr_indices = {}, ++ const std::set &preferred_inputs = {}) = 0; + + /*! + * \brief createSweepUnmixableTransaction creates transaction with unmixable outputs. +@@ -994,6 +1041,7 @@ struct Wallet + + virtual TransactionHistory * history() = 0; + virtual AddressBook * addressBook() = 0; ++ virtual Coins * coins() = 0; + virtual Subaddress * subaddress() = 0; + virtual SubaddressAccount * subaddressAccount() = 0; + virtual void setListener(WalletListener *) = 0; +diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp +index 806de969a..8720e18b1 100644 +--- a/src/wallet/wallet2.cpp ++++ b/src/wallet/wallet2.cpp +@@ -2103,12 +2103,21 @@ bool wallet2::frozen(const multisig_tx_set& txs) const + + return false; + } ++void wallet2::freeze(const crypto::public_key &pk) ++{ ++ freeze(get_transfer_details(pk)); ++} + //---------------------------------------------------------------------------------------------------- + void wallet2::freeze(const crypto::key_image &ki) + { + freeze(get_transfer_details(ki)); + } + //---------------------------------------------------------------------------------------------------- ++void wallet2::thaw(const crypto::public_key &pk) ++{ ++ thaw(get_transfer_details(pk)); ++} ++//---------------------------------------------------------------------------------------------------- + void wallet2::thaw(const crypto::key_image &ki) + { + thaw(get_transfer_details(ki)); +@@ -2119,6 +2128,18 @@ bool wallet2::frozen(const crypto::key_image &ki) const + return frozen(get_transfer_details(ki)); + } + //---------------------------------------------------------------------------------------------------- ++size_t wallet2::get_transfer_details(const crypto::public_key &pk) const ++{ ++ for (size_t idx = 0; idx < m_transfers.size(); ++idx) ++ { ++ const transfer_details &td = m_transfers[idx]; ++ if (td.get_public_key() == pk) { ++ return idx; ++ } ++ } ++ CHECK_AND_ASSERT_THROW_MES(false, "Public key not found"); ++} ++//---------------------------------------------------------------------------------------------------- + size_t wallet2::get_transfer_details(const crypto::key_image &ki) const + { + for (size_t idx = 0; idx < m_transfers.size(); ++idx) +@@ -2530,6 +2551,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote + uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount; + if (!pool) + { ++ boost::unique_lock lock(m_transfers_mutex); + m_transfers.push_back(transfer_details{}); + transfer_details& td = m_transfers.back(); + td.m_block_height = height; +@@ -2633,6 +2655,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote + uint64_t extra_amount = amount - burnt; + if (!pool) + { ++ boost::unique_lock lock(m_transfers_mutex); + transfer_details &td = m_transfers[kit->second]; + td.m_block_height = height; + td.m_internal_output_index = o; +@@ -10511,7 +10534,7 @@ void wallet2::transfer_selected_rct(std::vector wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set &subaddr_indices) ++std::vector wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set &subaddr_indices, const std::vector& preferred_input_list) + { + std::vector picks; + float current_output_relatdness = 1.0f; +@@ -10522,6 +10545,9 @@ std::vector wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui + for (size_t i = 0; i < m_transfers.size(); ++i) + { + const transfer_details& td = m_transfers[i]; ++ if (!is_preferred_input(preferred_input_list, td.m_key_image)) { ++ continue; ++ } + if (!is_spent(td, false) && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) + { + if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below) +@@ -10542,6 +10568,9 @@ std::vector wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui + for (size_t i = 0; i < m_transfers.size(); ++i) + { + const transfer_details& td = m_transfers[i]; ++ if (!is_preferred_input(preferred_input_list, td.m_key_image)) { ++ continue; ++ } + if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) + { + if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below) +@@ -10553,6 +10582,9 @@ std::vector wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui + for (size_t j = i + 1; j < m_transfers.size(); ++j) + { + const transfer_details& td2 = m_transfers[j]; ++ if (!is_preferred_input(preferred_input_list, td2.m_key_image)) { ++ continue; ++ } + if (td2.amount() > m_ignore_outputs_above || td2.amount() < m_ignore_outputs_below) + { + MDEBUG("Ignoring output " << j << " of amount " << print_money(td2.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]"); +@@ -11125,7 +11157,7 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image, + // This system allows for sending (almost) the entire balance, since it does + // not generate spurious change in all txes, thus decreasing the instantaneous + // usable balance. +-std::vector wallet2::create_transactions_2(std::vector dsts, const size_t fake_outs_count, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, const unique_index_container& subtract_fee_from_outputs) ++std::vector wallet2::create_transactions_2(std::vector dsts, const size_t fake_outs_count, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, const std::vector& preferred_input_list, const unique_index_container& subtract_fee_from_outputs) + { + //ensure device is let in NONE mode in any case + hw::device &hwdev = m_account.get_device(); +@@ -11333,6 +11365,9 @@ std::vector wallet2::create_transactions_2(std::vector wallet2::create_transactions_2(std::vector &ptx_vector, c + return true; + } + +-std::vector wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices) ++std::vector wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, const std::vector& preferred_input_list) + { + std::vector unused_transfers_indices; + std::vector unused_dust_indices; +@@ -11932,6 +11967,9 @@ std::vector wallet2::create_transactions_all(uint64_t below + for (size_t i = 0; i < m_transfers.size(); ++i) + { + const transfer_details& td = m_transfers[i]; ++ if (!is_preferred_input(preferred_input_list, td.m_key_image)) { ++ continue; ++ } + if (m_ignore_fractional_outputs && td.amount() < fractional_threshold) + { + MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold)); +diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h +index a619bdd15..4f324c238 100644 +--- a/src/wallet/wallet2.h ++++ b/src/wallet/wallet2.h +@@ -1216,8 +1216,8 @@ private: + bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const; + bool load_tx(const std::string &signed_filename, std::vector &ptx, std::function accept_func = NULL); + bool parse_tx_from_str(const std::string &signed_tx_st, std::vector &ptx, std::function accept_func); +- std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose +- std::vector create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices); ++ std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, const std::vector& preferred_input_list = {}, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose ++ std::vector create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, const std::vector& preferred_input_list = {}); + std::vector create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector& extra); + std::vector create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector unused_transfers_indices, std::vector unused_dust_indices, const size_t fake_outs_count, uint32_t priority, const std::vector& extra); + bool sanity_check(const std::vector &ptx_vector, const std::vector& dsts, const unique_index_container& subtract_fee_from_outputs = {}) const; +@@ -1569,6 +1569,7 @@ private: + uint64_t get_num_rct_outputs(); + size_t get_num_transfer_details() const { return m_transfers.size(); } + const transfer_details &get_transfer_details(size_t idx) const; ++ size_t get_transfer_details(const crypto::public_key &pk) const; + + uint8_t get_current_hard_fork(); + void get_hard_fork_info(uint8_t version, uint64_t &earliest_height); +@@ -1800,7 +1801,9 @@ private: + void freeze(size_t idx); + void thaw(size_t idx); + bool frozen(size_t idx) const; ++ void freeze(const crypto::public_key &pk); + void freeze(const crypto::key_image &ki); ++ void thaw(const crypto::public_key &pk); + void thaw(const crypto::key_image &ki); + bool frozen(const crypto::key_image &ki) const; + bool frozen(const transfer_details &td) const; +@@ -1841,6 +1844,8 @@ private: + + static std::string get_default_daemon_address() { CRITICAL_REGION_LOCAL(default_daemon_address_lock); return default_daemon_address; } + ++ boost::shared_mutex m_transfers_mutex; ++ + private: + /*! + * \brief Stores wallet information to wallet file. +@@ -1912,7 +1917,7 @@ private: + std::vector get_unspent_amounts_vector(bool strict); + uint64_t get_dynamic_base_fee_estimate(); + float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const; +- std::vector pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set &subaddr_indices); ++ std::vector pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set &subaddr_indices, const std::vector& preferred_input_list); + void set_spent(size_t idx, uint64_t height); + void set_unspent(size_t idx); + bool is_spent(const transfer_details &td, bool strict = true) const; +-- +2.48.1 + diff --git a/patches/salvium/0009-Add-hex-encoding-and-tx-key-getter-for-PendingTransc.patch b/patches/salvium/0009-Add-hex-encoding-and-tx-key-getter-for-PendingTransc.patch new file mode 100644 index 0000000..9e04787 --- /dev/null +++ b/patches/salvium/0009-Add-hex-encoding-and-tx-key-getter-for-PendingTransc.patch @@ -0,0 +1,68 @@ +From 0ba0339b11d8f7f66f2d5cd27075d438a76351b4 Mon Sep 17 00:00:00 2001 +From: M +Date: Fri, 21 Apr 2023 15:43:47 -0400 +Subject: [PATCH 09/14] Add hex encoding and tx key getter for + PendingTransction in wallet api. + +--- + src/wallet/api/pending_transaction.cpp | 16 ++++++++++++++++ + src/wallet/api/pending_transaction.h | 2 ++ + src/wallet/api/wallet2_api.h | 2 ++ + 3 files changed, 20 insertions(+) + +diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp +index 9c3c26ee5..1f714d229 100644 +--- a/src/wallet/api/pending_transaction.cpp ++++ b/src/wallet/api/pending_transaction.cpp +@@ -80,6 +80,22 @@ std::vector PendingTransactionImpl::txid() const + return txid; + } + ++std::vector PendingTransactionImpl::hex() const ++{ ++ std::vector hexs; ++ for (const auto &pt: m_pending_tx) ++ hexs.push_back(epee::string_tools::buff_to_hex_nodelimer(cryptonote::tx_to_blob(pt.tx))); ++ return hexs; ++} ++ ++std::vector PendingTransactionImpl::txKey() const ++{ ++ std::vector keys; ++ for (const auto& pt: m_pending_tx) ++ keys.push_back(epee::string_tools::pod_to_hex(pt.tx_key)); ++ return keys; ++} ++ + bool PendingTransactionImpl::commit(const std::string &filename, bool overwrite) + { + +diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h +index 403bfe281..0cc6c58e9 100644 +--- a/src/wallet/api/pending_transaction.h ++++ b/src/wallet/api/pending_transaction.h +@@ -59,6 +59,8 @@ public: + std::string multisigSignData() override; + void signMultisigTx() override; + std::vector signersKeys() const override; ++ std::vector hex() const override; ++ std::vector txKey() const override; + + private: + friend class WalletImpl; +diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h +index 013b5bcba..f421fdc05 100644 +--- a/src/wallet/api/wallet2_api.h ++++ b/src/wallet/api/wallet2_api.h +@@ -127,6 +127,8 @@ struct PendingTransaction + * @return vector of base58-encoded signers' public keys + */ + virtual std::vector signersKeys() const = 0; ++ virtual std::vector hex() const = 0; ++ virtual std::vector txKey() const = 0; + }; + + /** +-- +2.48.1 + diff --git a/patches/salvium/0010-Add-recoverDeterministicWalletFromSpendKey.patch b/patches/salvium/0010-Add-recoverDeterministicWalletFromSpendKey.patch new file mode 100644 index 0000000..022604d --- /dev/null +++ b/patches/salvium/0010-Add-recoverDeterministicWalletFromSpendKey.patch @@ -0,0 +1,153 @@ +From cb02355313d504e6a44f8f70b8eb2be64167ffd4 Mon Sep 17 00:00:00 2001 +From: Konstantin Ullrich +Date: Wed, 11 Oct 2023 16:47:59 +0200 +Subject: [PATCH 10/14] Add recoverDeterministicWalletFromSpendKey + +This function is used by Cake Wallet to enable polyseed (dart implementation) +support. + +Sourced from the following commit: +https://github.com/cake-tech/monero/commit/cb6fb5ab218878702ed151c0e3d5d68eb2732788 + +Co-authored-by: Godwin Asuquo +--- + src/wallet/api/wallet.cpp | 29 +++++++++++++++++++++++++++++ + src/wallet/api/wallet.h | 4 ++++ + src/wallet/api/wallet2_api.h | 19 +++++++++++++++++++ + src/wallet/api/wallet_manager.cpp | 16 ++++++++++++++++ + src/wallet/api/wallet_manager.h | 7 +++++++ + 5 files changed, 75 insertions(+) + +diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp +index 933cc2531..d8fe108b4 100644 +--- a/src/wallet/api/wallet.cpp ++++ b/src/wallet/api/wallet.cpp +@@ -824,6 +824,35 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c + return status() == Status_Ok; + } + ++bool WalletImpl::recoverDeterministicWalletFromSpendKey(const std::string &path, const std::string &password, const std::string &language, const std::string &spendkey_string) ++{ ++ clearStatus(); ++ m_errorString.clear(); ++ ++ m_recoveringFromSeed = true; ++ m_recoveringFromDevice = false; ++ ++ // parse spend key ++ crypto::secret_key spendkey; ++ if (!spendkey_string.empty()) { ++ cryptonote::blobdata spendkey_data; ++ if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data) || spendkey_data.size() != sizeof(crypto::secret_key)) ++ { ++ setStatusError(tr("failed to parse secret spend key")); ++ return false; ++ } ++ spendkey = *reinterpret_cast(spendkey_data.data()); ++ } ++ ++ try { ++ m_wallet->generate(path, password, spendkey, true, false); ++ setSeedLanguage(language); ++ } catch (const std::exception &e) { ++ setStatusCritical(e.what()); ++ } ++ return status() == Status_Ok; ++} ++ + bool WalletImpl::close(bool store) + { + +diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h +index a82f270e4..9e1fbb40b 100644 +--- a/src/wallet/api/wallet.h ++++ b/src/wallet/api/wallet.h +@@ -77,6 +77,10 @@ public: + const std::string &address_string, + const std::string &viewkey_string, + const std::string &spendkey_string = ""); ++ bool recoverDeterministicWalletFromSpendKey(const std::string &path, ++ const std::string &password, ++ const std::string &language, ++ const std::string &spendkey_string); + bool recoverFromDevice(const std::string &path, + const std::string &password, + const std::string &device_name); +diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h +index f421fdc05..c8d6bb179 100644 +--- a/src/wallet/api/wallet2_api.h ++++ b/src/wallet/api/wallet2_api.h +@@ -1323,6 +1323,25 @@ struct WalletManager + return createWalletFromKeys(path, password, language, testnet ? TESTNET : MAINNET, restoreHeight, addressString, viewKeyString, spendKeyString); + } + ++ /*! ++ * \brief recover deterministic wallet from spend key. ++ * \param path Name of wallet file to be created ++ * \param password Password of wallet file ++ * \param language language ++ * \param nettype Network type ++ * \param restoreHeight restore from start height ++ * \param spendKeyString spend key ++ * \param kdf_rounds Number of rounds for key derivation function ++ * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) ++ */ ++ virtual Wallet * createDeterministicWalletFromSpendKey(const std::string &path, ++ const std::string &password, ++ const std::string &language, ++ NetworkType nettype, ++ uint64_t restoreHeight, ++ const std::string &spendKeyString, ++ uint64_t kdf_rounds = 1) = 0; ++ + /*! + * \deprecated this method creates a wallet WITHOUT a passphrase, use createWalletFromKeys(..., password, ...) instead + * \brief recovers existing wallet using keys. Creates a view only wallet if spend key is omitted +diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp +index da2056d8a..c200f52ae 100644 +--- a/src/wallet/api/wallet_manager.cpp ++++ b/src/wallet/api/wallet_manager.cpp +@@ -127,6 +127,22 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path, + return wallet; + } + ++Wallet *WalletManagerImpl::createDeterministicWalletFromSpendKey(const std::string &path, ++ const std::string &password, ++ const std::string &language, ++ NetworkType nettype, ++ uint64_t restoreHeight, ++ const std::string &spendkey_string, ++ uint64_t kdf_rounds) ++{ ++ WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds); ++ if(restoreHeight > 0){ ++ wallet->setRefreshFromBlockHeight(restoreHeight); ++ } ++ wallet->recoverDeterministicWalletFromSpendKey(path, password, language, spendkey_string); ++ return wallet; ++} ++ + Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path, + const std::string &password, + NetworkType nettype, +diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h +index 28fcd36c9..be3ff8184 100644 +--- a/src/wallet/api/wallet_manager.h ++++ b/src/wallet/api/wallet_manager.h +@@ -67,6 +67,13 @@ public: + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString = "") override; ++ virtual Wallet * createDeterministicWalletFromSpendKey(const std::string &path, ++ const std::string &password, ++ const std::string &language, ++ NetworkType nettype, ++ uint64_t restoreHeight, ++ const std::string &spendkey_string, ++ uint64_t kdf_rounds) override; + virtual Wallet * createWalletFromDevice(const std::string &path, + const std::string &password, + NetworkType nettype, +-- +2.48.1 + diff --git a/patches/salvium/0011-add-monero-submodule-support.patch b/patches/salvium/0011-add-monero-submodule-support.patch new file mode 100644 index 0000000..cbe6f35 --- /dev/null +++ b/patches/salvium/0011-add-monero-submodule-support.patch @@ -0,0 +1,65 @@ +From 846d3f60093add6653d9102d841288066fc08311 Mon Sep 17 00:00:00 2001 +From: cyan +Date: Thu, 7 Nov 2024 16:46:24 +0000 +Subject: [PATCH 11/14] add monero submodule support + +--- + CMakeLists.txt | 6 +++--- + cmake/CheckLinkerFlag.cmake | 2 +- + src/wallet/wallet_rpc_server.cpp | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f0630ef9b..9406e57b4 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -223,9 +223,9 @@ function(forbid_undefined_symbols) + cmake_minimum_required(VERSION 3.1) + project(test) + option(EXPECT_SUCCESS "" ON) +-file(WRITE "${CMAKE_SOURCE_DIR}/incorrect_source.cpp" "void undefined_symbol(); void symbol() { undefined_symbol(); }") ++file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/incorrect_source.cpp" "void undefined_symbol(); void symbol() { undefined_symbol(); }") + if (EXPECT_SUCCESS) +- file(APPEND "${CMAKE_SOURCE_DIR}/incorrect_source.cpp" " void undefined_symbol() {}; ") ++ file(APPEND "${CMAKE_CURRENT_SOURCE_DIR}/incorrect_source.cpp" " void undefined_symbol() {}; ") + endif() + add_library(l0 SHARED incorrect_source.cpp) + add_library(l1 MODULE incorrect_source.cpp) +@@ -390,7 +390,7 @@ else() + endif() + + list(INSERT CMAKE_MODULE_PATH 0 +- "${CMAKE_SOURCE_DIR}/cmake") ++ "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + + if (NOT DEFINED ENV{DEVELOPER_LOCAL_TOOLS}) + message(STATUS "Could not find DEVELOPER_LOCAL_TOOLS in env (not required)") +diff --git a/cmake/CheckLinkerFlag.cmake b/cmake/CheckLinkerFlag.cmake +index 7ecf5f610..89fb9d167 100644 +--- a/cmake/CheckLinkerFlag.cmake ++++ b/cmake/CheckLinkerFlag.cmake +@@ -6,7 +6,7 @@ macro(CHECK_LINKER_FLAG flag VARIABLE) + message(STATUS "Looking for ${flag} linker flag") + endif() + +- set(_cle_source ${CMAKE_SOURCE_DIR}/cmake/CheckLinkerFlag.c) ++ set(_cle_source ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckLinkerFlag.c) + + set(saved_CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) + set(CMAKE_C_FLAGS "${flag}") +diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp +index 3188c88db..9fbdb3c05 100644 +--- a/src/wallet/wallet_rpc_server.cpp ++++ b/src/wallet/wallet_rpc_server.cpp +@@ -1184,7 +1184,7 @@ namespace tools + { + uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); + uint32_t priority = m_wallet->adjust_priority(req.priority); +- std::vector ptx_vector = m_wallet->create_transactions_2(dsts, mixin, priority, extra, req.account_index, req.subaddr_indices, req.subtract_fee_from_outputs); ++ std::vector ptx_vector = m_wallet->create_transactions_2(dsts, mixin, priority, extra, req.account_index, req.subaddr_indices, {}, req.subtract_fee_from_outputs); + + if (ptx_vector.empty()) + { +-- +2.48.1 + diff --git a/patches/salvium/0012-fix-iOS-depends-build.patch b/patches/salvium/0012-fix-iOS-depends-build.patch new file mode 100644 index 0000000..dcf7c86 --- /dev/null +++ b/patches/salvium/0012-fix-iOS-depends-build.patch @@ -0,0 +1,104 @@ +From 53cc0482e55a39b5dbf2261fea11fcb160778800 Mon Sep 17 00:00:00 2001 +From: Czarek Nakamoto +Date: Thu, 21 Nov 2024 06:05:03 -0500 +Subject: [PATCH 12/14] fix iOS depends build + +--- + CMakeLists.txt | 4 ---- + src/checkpoints/CMakeLists.txt | 6 +++++- + src/cryptonote_basic/CMakeLists.txt | 6 +++++- + src/cryptonote_basic/miner.cpp | 8 ++++---- + 4 files changed, 14 insertions(+), 10 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 9406e57b4..1eac121db 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -39,10 +39,6 @@ include(CheckLibraryExists) + include(CheckFunctionExists) + include(FindPythonInterp) + +-if (IOS) +- INCLUDE(CmakeLists_IOS.txt) +-endif() +- + cmake_minimum_required(VERSION 3.5) + message(STATUS "CMake version ${CMAKE_VERSION}") + +diff --git a/src/checkpoints/CMakeLists.txt b/src/checkpoints/CMakeLists.txt +index 665441f62..841df3256 100644 +--- a/src/checkpoints/CMakeLists.txt ++++ b/src/checkpoints/CMakeLists.txt +@@ -28,7 +28,11 @@ + + if(APPLE) + if(DEPENDS) +- list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework ApplicationServices -framework AppKit -framework IOKit") ++ if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS") ++ list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework IOKit") ++ else() ++ list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework ApplicationServices -framework AppKit -framework IOKit") ++ endif() + else() + find_library(IOKIT_LIBRARY IOKit) + mark_as_advanced(IOKIT_LIBRARY) +diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt +index 414936a05..81c81767f 100644 +--- a/src/cryptonote_basic/CMakeLists.txt ++++ b/src/cryptonote_basic/CMakeLists.txt +@@ -28,7 +28,11 @@ + + if(APPLE) + if(DEPENDS) +- list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework ApplicationServices -framework AppKit -framework IOKit") ++ if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS") ++ list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework IOKit") ++ else() ++ list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework ApplicationServices -framework AppKit -framework IOKit") ++ endif() + else() + find_library(IOKIT_LIBRARY IOKit) + mark_as_advanced(IOKIT_LIBRARY) +diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp +index 71b8f78cc..0f53f024e 100644 +--- a/src/cryptonote_basic/miner.cpp ++++ b/src/cryptonote_basic/miner.cpp +@@ -45,7 +45,7 @@ + #include "boost/logic/tribool.hpp" + #include + +-#ifdef __APPLE__ ++#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE) + #include + #include + #include +@@ -883,7 +883,7 @@ namespace cryptonote + + return true; + +- #elif defined(__APPLE__) ++ #elif defined(__APPLE__) && !defined(TARGET_OS_IPHONE) + + mach_msg_type_number_t count; + kern_return_t status; +@@ -949,7 +949,7 @@ namespace cryptonote + return true; + } + +- #elif (defined(__linux__) && defined(_SC_CLK_TCK)) || defined(__APPLE__) || defined(__FreeBSD__) ++ #elif (defined(__linux__) && defined(_SC_CLK_TCK)) || (defined(__APPLE__) && !defined(TARGET_OS_IPHONE)) || defined(__FreeBSD__) + + struct tms tms; + if ( times(&tms) != (clock_t)-1 ) +@@ -978,7 +978,7 @@ namespace cryptonote + return boost::logic::tribool(power_status.ACLineStatus != 1); + } + +- #elif defined(__APPLE__) ++ #elif defined(__APPLE__) && !defined(TARGET_OS_IPHONE) + + #if TARGET_OS_MAC && (!defined(MAC_OS_X_VERSION_MIN_REQUIRED) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7) + return boost::logic::tribool(IOPSGetTimeRemainingEstimate() != kIOPSTimeRemainingUnlimited); +-- +2.48.1 + diff --git a/patches/salvium/0013-include-locale-only-when-targeting-WIN32.patch b/patches/salvium/0013-include-locale-only-when-targeting-WIN32.patch new file mode 100644 index 0000000..64ef6aa --- /dev/null +++ b/patches/salvium/0013-include-locale-only-when-targeting-WIN32.patch @@ -0,0 +1,45 @@ +From 1eacd30724559749be5adeb31d763f44c3f221f9 Mon Sep 17 00:00:00 2001 +From: Czarek Nakamoto +Date: Mon, 18 Nov 2024 10:57:37 -0500 +Subject: [PATCH 13/14] include locale only when targeting WIN32 + + +--- + CMakeLists.txt | 6 +++++- + src/wallet/api/wallet.cpp | 2 ++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 1eac121db..3a4e8f7e1 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1089,7 +1089,11 @@ if(NOT Boost_FOUND) + elseif(Boost_FOUND) + message(STATUS "Found Boost Version: ${Boost_VERSION_STRING}") + +- set(BOOST_COMPONENTS filesystem thread date_time chrono serialization program_options locale) ++ set(BOOST_COMPONENTS filesystem thread date_time chrono serialization program_options) ++ ++ if(WIN32) ++ list(APPEND BOOST_COMPONENTS locale) ++ endif() + + # Boost System is header-only since 1.69 + if (Boost_VERSION_STRING VERSION_LESS 1.69.0) +diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp +index d8fe108b4..e3e838b13 100644 +--- a/src/wallet/api/wallet.cpp ++++ b/src/wallet/api/wallet.cpp +@@ -46,7 +46,9 @@ + #include + #include + ++#ifdef WIN32 + #include ++#endif + #include + #include "bc-ur/src/bc-ur.hpp" + #if defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI) +-- +2.48.1 + diff --git a/patches/salvium/0014-change-earliest-fork-height-message.patch b/patches/salvium/0014-change-earliest-fork-height-message.patch new file mode 100644 index 0000000..e73f776 --- /dev/null +++ b/patches/salvium/0014-change-earliest-fork-height-message.patch @@ -0,0 +1,25 @@ +From 2d31234e859bff817d30d91b21d9412375668aae Mon Sep 17 00:00:00 2001 +From: Czarek Nakamoto +Date: Wed, 29 Jan 2025 16:13:28 +0100 +Subject: [PATCH 14/14] change earliest fork height message + +--- + src/wallet/wallet2.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp +index 8720e18b1..69da11d9c 100644 +--- a/src/wallet/wallet2.cpp ++++ b/src/wallet/wallet2.cpp +@@ -12365,7 +12365,7 @@ bool wallet2::use_fork_rules(uint8_t version, int64_t early_blocks) + boost::optional result = m_node_rpc_proxy.get_height(height); + THROW_WALLET_EXCEPTION_IF(result, error::wallet_internal_error, "Failed to get height"); + result = m_node_rpc_proxy.get_earliest_height(version, earliest_height); +- THROW_WALLET_EXCEPTION_IF(result, error::wallet_internal_error, "Failed to get earliest fork height"); ++ THROW_WALLET_EXCEPTION_IF(result, error::wallet_internal_error, "Failed to get earliest fork height. Please check your connection and/or switch node you are connected to currently."); + + bool close_enough = (int64_t)height >= (int64_t)earliest_height - early_blocks && earliest_height != std::numeric_limits::max(); // start using the rules that many blocks beforehand + if (close_enough) +-- +2.48.1 + diff --git a/patches/salvium/0015-remove-trivially_copyable-assert.patch b/patches/salvium/0015-remove-trivially_copyable-assert.patch new file mode 100644 index 0000000..d78268f --- /dev/null +++ b/patches/salvium/0015-remove-trivially_copyable-assert.patch @@ -0,0 +1,24 @@ +From 71cf45cfbd571ec58e8b2a1d408ff74804bf7e1d Mon Sep 17 00:00:00 2001 +From: Czarek Nakamoto +Date: Thu, 20 Feb 2025 08:36:28 +0100 +Subject: [PATCH] remove trivially_copyable assert + +--- + contrib/epee/include/span.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/contrib/epee/include/span.h b/contrib/epee/include/span.h +index 01dc387d6..2ad733a2f 100644 +--- a/contrib/epee/include/span.h ++++ b/contrib/epee/include/span.h +@@ -162,7 +162,6 @@ namespace epee + { + static_assert(!std::is_empty(), "empty types will not work -> sizeof == 1"); + static_assert(std::is_standard_layout(), "type must have standard layout"); +- static_assert(std::is_trivially_copyable(), "type must be trivially copyable"); + static_assert(alignof(T) == 1, "type may have padding"); + return {reinterpret_cast(std::addressof(src)), sizeof(T)}; + } +-- +2.48.1 + diff --git a/salvium b/salvium new file mode 160000 index 0000000..4208240 --- /dev/null +++ b/salvium @@ -0,0 +1 @@ +Subproject commit 420824005ea835d39cd61bfaef570d0c0e74344c diff --git a/salvium_libwallet2_api_c/CMakeLists.txt b/salvium_libwallet2_api_c/CMakeLists.txt new file mode 100644 index 0000000..876d2d4 --- /dev/null +++ b/salvium_libwallet2_api_c/CMakeLists.txt @@ -0,0 +1,172 @@ +cmake_minimum_required(VERSION 3.5) +project(wallet2_api_c) +message(STATUS ABI_INFO = ${HOST_ABI}) + +set(MD_LIBRARY "") + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +# set(CMAKE_INTERPROCEDURAL_OPTIMIZATION FALSE) +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-lto") + +if(${HOST_ABI} STREQUAL "x86_64-w64-mingw32") + set(CMAKE_SYSTEM_NAME Windows) + set(CMAKE_LINKER "x86_64-w64-mingw32-ld") + set(TARGET "x86_64-w64-mingw32") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lssp") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lssp") +elseif(${HOST_ABI} STREQUAL "i686-w64-mingw32") + set(CMAKE_SYSTEM_NAME Windows) + set(CMAKE_LINKER "i686-w64-mingw32-ld") + set(TARGET "i686-w64-mingw32") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lssp") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lssp") +elseif(${HOST_ABI} STREQUAL "host-apple-ios" OR + ${HOST_ABI} STREQUAL "aarch64-apple-ios") + set(CMAKE_SYSTEM_NAME iOS) +elseif(${HOST_ABI} STREQUAL "host-apple-darwin" OR + ${HOST_ABI} STREQUAL "x86_64-host-apple-darwin" OR + ${HOST_ABI} STREQUAL "aarch64-host-apple-darwin") + set(CMAKE_SYSTEM_NAME Darwin) +endif() + +if (${HOST_ABI} STREQUAL "host-apple-darwin" OR + ${HOST_ABI} STREQUAL "x86_64-host-apple-darwin" OR + ${HOST_ABI} STREQUAL "aarch64-host-apple-darwin") + EXECUTE_PROCESS( COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE ) + if (NOT ${ARCHITECTURE} STREQUAL arm64) + set(CMAKE_OSX_ARCHITECTURES x86_64) + endif() +endif() + +if(${HOST_ABI} STREQUAL "x86_64-linux-android" OR + ${HOST_ABI} STREQUAL "i686-linux-android" OR + ${HOST_ABI} STREQUAL "aarch64-linux-android" OR + ${HOST_ABI} STREQUAL "armv7a-linux-androideabi") + add_link_options(-stdlib=libc++ -static-libstdc++) + set(EXTRA_LIBS_ANDROID log) +endif() + +add_library( wallet2_api_c + SHARED + src/main/cpp/helpers.cpp + src/main/cpp/wallet2_api_c.cpp ) + +if(${HOST_ABI} STREQUAL "x86_64-linux-android" OR + ${HOST_ABI} STREQUAL "i686-linux-android" OR + ${HOST_ABI} STREQUAL "aarch64-linux-android" OR + ${HOST_ABI} STREQUAL "armv7a-linux-androideabi") + set_target_properties(wallet2_api_c PROPERTIES LINK_FLAGS "-Wl,-z,noexecstack") +endif() + +if(${HOST_ABI} STREQUAL "x86_64-linux-gnu" OR + ${HOST_ABI} STREQUAL "i686-linux-gnu" OR + ${HOST_ABI} STREQUAL "aarch64-linux-gnu" OR + ${HOST_ABI} STREQUAL "armv7a-linux-gnu") + set_target_properties(wallet2_api_c PROPERTIES LINK_FLAGS "-Wl,-z,noexecstack") +endif() + + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") + + + +set(MONERO_DIR ${CMAKE_SOURCE_DIR}/../${MONERO_FLAVOR}) +set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../contrib/depends/${HOST_ABI}) + +if (${HOST_ABI} STREQUAL "x86_64-apple-darwin11" OR ${HOST_ABI} STREQUAL "aarch64-apple-darwin11") + set(EXTRA_LIBS_APPLE "-framework IOKit" "-framework CoreFoundation" "-framework Cocoa" hidapi) +# set_target_properties(wallet2_api_c PROPERTIES LINK_FLAGS "-Wl,-F/Library/Frameworks") +elseif(${HOST_ABI} STREQUAL "host-apple-darwin" OR + ${HOST_ABI} STREQUAL "x86_64-host-apple-darwin" OR + ${HOST_ABI} STREQUAL "aarch64-host-apple-darwin") + set(EXTRA_LIBS_APPLE "-framework IOKit" "-framework CoreFoundation" "-framework Cocoa" apple_nghttp2) +elseif(${HOST_ABI} STREQUAL "host-apple-ios" OR ${HOST_ABI} STREQUAL "aarch64-apple-ios" OR ${HOST_ABI} STREQUAL "arm64-apple-ios" OR ${HOST_ABI} STREQUAL "arm64-apple-iossimulator" OR ${HOST_ABI} STREQUAL "x86_64-apple-iossimulator") + set(EXTRA_LIBS_APPLE "-framework IOKit" "-framework CoreFoundation" iconv ) +endif() + +if(${HOST_ABI} STREQUAL "x86_64-w64-mingw32" OR ${HOST_ABI} STREQUAL "i686-w64-mingw32") + target_link_options(wallet2_api_c PRIVATE -static-libgcc -static-libstdc++) +endif() + +if(${HOST_ABI} STREQUAL "x86_64-apple-darwin11" OR ${HOST_ABI} STREQUAL "aarch64-apple-darwin11" OR ${HOST_ABI} STREQUAL "host-apple-darwin" OR ${HOST_ABI} STREQUAL "x86_64-host-apple-darwin" OR ${HOST_ABI} STREQUAL "aarch64-host-apple-darwin" OR ${HOST_ABI} STREQUAL "host-apple-ios" OR ${HOST_ABI} STREQUAL "aarch64-apple-ios" OR ${HOST_ABI} STREQUAL "arm64-apple-iossimulator" OR ${HOST_ABI} STREQUAL "x86_64-apple-iossimulator") + set_target_properties(wallet2_api_c PROPERTIES SUFFIX ".dylib") + + set_target_properties(wallet2_api_c PROPERTIES NO_SONAME 1) +endif() + +if (${MONERO_FLAVOR} STREQUAL "monero") + target_compile_definitions(wallet2_api_c PRIVATE FLAVOR_MONERO) + set(BCUR_ENABLED bc-ur) +elseif(${MONERO_FLAVOR} STREQUAL "wownero") + target_compile_definitions(wallet2_api_c PRIVATE FLAVOR_WOWNERO) +elseif(${MONERO_FLAVOR} STREQUAL "zano") + target_compile_definitions(wallet2_api_c PRIVATE FLAVOR_ZANO) +endif() + +if(NOT ${HOST_ABI} STREQUAL "x86_64-apple-darwin11" AND NOT ${HOST_ABI} STREQUAL "aarch64-apple-darwin11" AND NOT ${HOST_ABI} STREQUAL "aarch64-apple-darwin" AND NOT ${HOST_ABI} STREQUAL "x86_64-apple-darwin" AND NOT ${HOST_ABI} STREQUAL "host-apple-darwin" AND NOT ${HOST_ABI} STREQUAL "x86_64-host-apple-darwin" AND NOT ${HOST_ABI} STREQUAL "aarch64-host-apple-darwin" AND NOT ${HOST_ABI} STREQUAL "host-apple-ios" AND NOT ${HOST_ABI} STREQUAL "aarch64-apple-ios" AND NOT ${HOST_ABI} STREQUAL "aarch64-apple-iossimulator" AND NOT ${HOST_ABI} STREQUAL "x86_64-apple-iossimulator") + set_target_properties(wallet2_api_c PROPERTIES LINK_FLAGS "-Wl,--exclude-libs,ALL") +endif() + +if (${MONERO_FLAVOR} STREQUAL "zano") + include_directories( + ${CMAKE_SOURCE_DIR}/build/${HOST_ABI}/zano_build/contrib/zlib + ) +endif() + +add_subdirectory("${CMAKE_SOURCE_DIR}/../${MONERO_FLAVOR}" ${CMAKE_BINARY_DIR}/${MONERO_FLAVOR}_build EXCLUDE_FROM_ALL) +if(${HOST_ABI} STREQUAL "x86_64-apple-darwin11" OR ${HOST_ABI} STREQUAL "aarch64-apple-darwin11" OR ${HOST_ABI} STREQUAL "x86_64-apple-darwin" OR ${HOST_ABI} STREQUAL "aarch64-apple-darwin" OR ${HOST_ABI} STREQUAL "host-apple-darwin" OR ${HOST_ABI} STREQUAL "x86_64-host-apple-darwin" OR ${HOST_ABI} STREQUAL "aarch64-host-apple-darwin" OR ${HOST_ABI} STREQUAL "host-apple-ios" OR ${HOST_ABI} STREQUAL "aarch64-apple-ios" OR ${HOST_ABI} STREQUAL "aarch64-apple-iossimulator" OR ${HOST_ABI} STREQUAL "x86_64-apple-iossimulator") + if (${MONERO_FLAVOR} STREQUAL "monero") + set(EXPORTED_SYMBOLS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/monero_libwallet2_api_c.exp) + elseif(${MONERO_FLAVOR} STREQUAL "wownero") + set(EXPORTED_SYMBOLS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/wownero_libwallet2_api_c.exp) + elseif(${MONERO_FLAVOR} STREQUAL "zano") + set(EXPORTED_SYMBOLS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/zano_libwallet2_api_c.exp) + endif() + + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -exported_symbols_list ${EXPORTED_SYMBOLS_FILE}") + set_target_properties(${TARGET} PROPERTIES LINK_DEPENDS ${EXPORTED_SYMBOLS_FILE}) +endif() + +if (${MONERO_FLAVOR} STREQUAL "monero") + set(WALLET_TARGETS wallet_api ${wallet_api_LIB_DEPENDS}) # wallet_api_LIB_DEPENDS +elseif(${MONERO_FLAVOR} STREQUAL "wownero") + set(WALLET_TARGETS wallet_api ${wallet_api_LIB_DEPENDS}) # wallet_api_LIB_DEPENDS +elseif(${MONERO_FLAVOR} STREQUAL "zano") + find_package(Boost 1.71 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options) + find_package(OpenSSL REQUIRED) + set(WALLET_TARGETS + wallet + general + tor-connect + crypto + currency_core + common + zlibstatic + + ${Boost_LIBRARIES} + ${OpenSSL_LIBRARIES}) +endif() + +if(${MONERO_FLAVOR} STREQUAL "wownero") + add_subdirectory(wownero-seed EXCLUDE_FROM_ALL) + set(EXTRA_LIBS_WOWNEROSEED wownero-seed) +endif() + +#get_cmake_property(_variableNames VARIABLES) +#list (SORT _variableNames) +#foreach (_variableName ${_variableNames}) +# message(STATUS "${_variableName}=${${_variableName}}") +#endforeach() +#message(SEND_ERROR "${Boost_LIBRARIES}") +#message(SEND_ERROR "${WALLET_TARGETS} +# ${EXTRA_LIBS_WOWNEROSEED} +# ${EXTRA_LIBS_ANDROID}") + +target_link_libraries( wallet2_api_c + + ${WALLET_TARGETS} + ${EXTRA_LIBS_WOWNEROSEED} + ${EXTRA_LIBS_ANDROID} + ) diff --git a/salvium_libwallet2_api_c/monero_libwallet2_api_c.exp b/salvium_libwallet2_api_c/monero_libwallet2_api_c.exp new file mode 100644 index 0000000..d42f14a --- /dev/null +++ b/salvium_libwallet2_api_c/monero_libwallet2_api_c.exp @@ -0,0 +1,308 @@ +_MONERO_PendingTransaction_status +_MONERO_PendingTransaction_errorString +_MONERO_PendingTransaction_commit +_MONERO_PendingTransaction_commitUR +_MONERO_PendingTransaction_amount +_MONERO_PendingTransaction_dust +_MONERO_PendingTransaction_fee +_MONERO_PendingTransaction_txid +_MONERO_PendingTransaction_txCount +_MONERO_PendingTransaction_subaddrAccount +_MONERO_PendingTransaction_subaddrIndices +_MONERO_PendingTransaction_multisigSignData +_MONERO_PendingTransaction_signMultisigTx +_MONERO_PendingTransaction_signersKeys +_MONERO_PendingTransaction_hex +_MONERO_UnsignedTransaction_status +_MONERO_UnsignedTransaction_errorString +_MONERO_UnsignedTransaction_amount +_MONERO_UnsignedTransaction_fee +_MONERO_UnsignedTransaction_mixin +_MONERO_UnsignedTransaction_confirmationMessage +_MONERO_UnsignedTransaction_paymentId +_MONERO_UnsignedTransaction_recipientAddress +_MONERO_UnsignedTransaction_minMixinCount +_MONERO_UnsignedTransaction_txCount +_MONERO_UnsignedTransaction_sign +_MONERO_UnsignedTransaction_signUR +_MONERO_TransactionInfo_direction +_MONERO_TransactionInfo_isPending +_MONERO_TransactionInfo_isFailed +_MONERO_TransactionInfo_isCoinbase +_MONERO_TransactionInfo_amount +_MONERO_TransactionInfo_fee +_MONERO_TransactionInfo_blockHeight +_MONERO_TransactionInfo_description +_MONERO_TransactionInfo_subaddrIndex +_MONERO_TransactionInfo_subaddrAccount +_MONERO_TransactionInfo_label +_MONERO_TransactionInfo_confirmations +_MONERO_TransactionInfo_unlockTime +_MONERO_TransactionInfo_hash +_MONERO_TransactionInfo_timestamp +_MONERO_TransactionInfo_paymentId +_MONERO_TransactionInfo_transfers_count +_MONERO_TransactionInfo_transfers_amount +_MONERO_TransactionInfo_transfers_address +_MONERO_TransactionHistory_count +_MONERO_TransactionHistory_transaction +_MONERO_TransactionHistory_transactionById +_MONERO_TransactionHistory_refresh +_MONERO_TransactionHistory_setTxNote +_MONERO_AddressBookRow_extra +_MONERO_AddressBookRow_getAddress +_MONERO_AddressBookRow_getDescription +_MONERO_AddressBookRow_getPaymentId +_MONERO_AddressBookRow_getRowId +_MONERO_AddressBook_getAll_size +_MONERO_AddressBook_getAll_byIndex +_MONERO_AddressBook_addRow +_MONERO_AddressBook_deleteRow +_MONERO_AddressBook_setDescription +_MONERO_AddressBook_refresh +_MONERO_AddressBook_errorString +_MONERO_AddressBook_errorCode +_MONERO_AddressBook_lookupPaymentID +_MONERO_CoinsInfo_blockHeight +_MONERO_CoinsInfo_hash +_MONERO_CoinsInfo_internalOutputIndex +_MONERO_CoinsInfo_globalOutputIndex +_MONERO_CoinsInfo_spent +_MONERO_CoinsInfo_frozen +_MONERO_CoinsInfo_spentHeight +_MONERO_CoinsInfo_amount +_MONERO_CoinsInfo_rct +_MONERO_CoinsInfo_keyImageKnown +_MONERO_CoinsInfo_pkIndex +_MONERO_CoinsInfo_subaddrIndex +_MONERO_CoinsInfo_subaddrAccount +_MONERO_CoinsInfo_address +_MONERO_CoinsInfo_addressLabel +_MONERO_CoinsInfo_keyImage +_MONERO_CoinsInfo_unlockTime +_MONERO_CoinsInfo_unlocked +_MONERO_CoinsInfo_pubKey +_MONERO_CoinsInfo_coinbase +_MONERO_CoinsInfo_description +_MONERO_Coins_count +_MONERO_Coins_coin +_MONERO_Coins_getAll_size +_MONERO_Coins_getAll_byIndex +_MONERO_Coins_refresh +_MONERO_Coins_setFrozenByPublicKey +_MONERO_Coins_setFrozen +_MONERO_Coins_thaw +_MONERO_Coins_thawByPublicKey +_MONERO_Coins_isTransferUnlocked +_MONERO_Coins_setDescription +_MONERO_SubaddressRow_extra +_MONERO_SubaddressRow_getAddress +_MONERO_SubaddressRow_getLabel +_MONERO_SubaddressRow_getRowId +_MONERO_Subaddress_getAll_size +_MONERO_Subaddress_getAll_byIndex +_MONERO_Subaddress_addRow +_MONERO_Subaddress_setLabel +_MONERO_Subaddress_refresh +_MONERO_SubaddressAccountRow_extra +_MONERO_SubaddressAccountRow_getAddress +_MONERO_SubaddressAccountRow_getLabel +_MONERO_SubaddressAccountRow_getBalance +_MONERO_SubaddressAccountRow_getUnlockedBalance +_MONERO_SubaddressAccountRow_getRowId +_MONERO_SubaddressAccount_getAll_size +_MONERO_SubaddressAccount_getAll_byIndex +_MONERO_SubaddressAccount_addRow +_MONERO_SubaddressAccount_setLabel +_MONERO_SubaddressAccount_refresh +_MONERO_MultisigState_isMultisig +_MONERO_MultisigState_isReady +_MONERO_MultisigState_threshold +_MONERO_MultisigState_total +_MONERO_DeviceProgress_progress +_MONERO_DeviceProgress_indeterminate +_MONERO_Wallet_seed +_MONERO_Wallet_getSeedLanguage +_MONERO_Wallet_setSeedLanguage +_MONERO_Wallet_status +_MONERO_Wallet_errorString +_MONERO_Wallet_setPassword +_MONERO_Wallet_getPassword +_MONERO_Wallet_setDevicePin +_MONERO_Wallet_setDevicePassphrase +_MONERO_Wallet_address +_MONERO_Wallet_path +_MONERO_Wallet_nettype +_MONERO_Wallet_useForkRules +_MONERO_Wallet_integratedAddress +_MONERO_Wallet_secretViewKey +_MONERO_Wallet_publicViewKey +_MONERO_Wallet_secretSpendKey +_MONERO_Wallet_publicSpendKey +_MONERO_Wallet_publicMultisigSignerKey +_MONERO_Wallet_stop +_MONERO_Wallet_store +_MONERO_Wallet_filename +_MONERO_Wallet_keysFilename +_MONERO_Wallet_init +_MONERO_Wallet_createWatchOnly +_MONERO_Wallet_setRefreshFromBlockHeight +_MONERO_Wallet_getRefreshFromBlockHeight +_MONERO_Wallet_setRecoveringFromSeed +_MONERO_Wallet_setRecoveringFromDevice +_MONERO_Wallet_setSubaddressLookahead +_MONERO_Wallet_connectToDaemon +_MONERO_Wallet_connected +_MONERO_Wallet_setTrustedDaemon +_MONERO_Wallet_trustedDaemon +_MONERO_Wallet_setProxy +_MONERO_Wallet_balance +_MONERO_Wallet_unlockedBalance +_MONERO_Wallet_viewOnlyBalance +_MONERO_Wallet_watchOnly +_MONERO_Wallet_isDeterministic +_MONERO_Wallet_blockChainHeight +_MONERO_Wallet_approximateBlockChainHeight +_MONERO_Wallet_estimateBlockChainHeight +_MONERO_Wallet_daemonBlockChainHeight +_MONERO_Wallet_daemonBlockChainTargetHeight +_MONERO_Wallet_synchronized +_MONERO_Wallet_displayAmount +_MONERO_Wallet_amountFromString +_MONERO_Wallet_amountFromDouble +_MONERO_Wallet_genPaymentId +_MONERO_Wallet_paymentIdValid +_MONERO_Wallet_addressValid +_MONERO_Wallet_keyValid +_MONERO_Wallet_keyValid_error +_MONERO_Wallet_paymentIdFromAddress +_MONERO_Wallet_maximumAllowedAmount +_MONERO_Wallet_init3 +_MONERO_Wallet_getPolyseed +_MONERO_Wallet_createPolyseed +_MONERO_Wallet_startRefresh +_MONERO_Wallet_pauseRefresh +_MONERO_Wallet_refresh +_MONERO_Wallet_refreshAsync +_MONERO_Wallet_rescanBlockchain +_MONERO_Wallet_rescanBlockchainAsync +_MONERO_Wallet_setAutoRefreshInterval +_MONERO_Wallet_autoRefreshInterval +_MONERO_Wallet_addSubaddressAccount +_MONERO_Wallet_numSubaddressAccounts +_MONERO_Wallet_numSubaddresses +_MONERO_Wallet_addSubaddress +_MONERO_Wallet_getSubaddressLabel +_MONERO_Wallet_setSubaddressLabel +_MONERO_Wallet_multisig +_MONERO_Wallet_getMultisigInfo +_MONERO_Wallet_makeMultisig +_MONERO_Wallet_exchangeMultisigKeys +_MONERO_Wallet_exportMultisigImages +_MONERO_Wallet_importMultisigImages +_MONERO_Wallet_hasMultisigPartialKeyImages +_MONERO_Wallet_restoreMultisigTransaction +_MONERO_Wallet_createTransactionMultDest +_MONERO_Wallet_createTransaction +_MONERO_Wallet_loadUnsignedTx +_MONERO_Wallet_loadUnsignedTxUR +_MONERO_Wallet_submitTransaction +_MONERO_Wallet_submitTransactionUR +_MONERO_Wallet_hasUnknownKeyImages +_MONERO_Wallet_exportKeyImages +_MONERO_Wallet_exportKeyImagesUR +_MONERO_Wallet_importKeyImages +_MONERO_Wallet_importKeyImagesUR +_MONERO_Wallet_exportOutputs +_MONERO_Wallet_exportOutputsUR +_MONERO_Wallet_importOutputs +_MONERO_Wallet_importOutputsUR +_MONERO_Wallet_setupBackgroundSync +_MONERO_Wallet_getBackgroundSyncType +_MONERO_Wallet_startBackgroundSync +_MONERO_Wallet_stopBackgroundSync +_MONERO_Wallet_isBackgroundSyncing +_MONERO_Wallet_isBackgroundWallet +_MONERO_Wallet_history +_MONERO_Wallet_addressBook +_MONERO_Wallet_coins +_MONERO_Wallet_subaddress +_MONERO_Wallet_subaddressAccount +_MONERO_Wallet_defaultMixin +_MONERO_Wallet_setDefaultMixin +_MONERO_Wallet_setCacheAttribute +_MONERO_Wallet_getCacheAttribute +_MONERO_Wallet_setUserNote +_MONERO_Wallet_getUserNote +_MONERO_Wallet_getTxKey +_MONERO_Wallet_signMessage +_MONERO_Wallet_verifySignedMessage +_MONERO_Wallet_rescanSpent +_MONERO_Wallet_setOffline +_MONERO_Wallet_isOffline +_MONERO_Wallet_segregatePreForkOutputs +_MONERO_Wallet_segregationHeight +_MONERO_Wallet_keyReuseMitigation2 +_MONERO_Wallet_lockKeysFile +_MONERO_Wallet_unlockKeysFile +_MONERO_Wallet_isKeysFileLocked +_MONERO_Wallet_getDeviceType +_MONERO_Wallet_coldKeyImageSync +_MONERO_Wallet_deviceShowAddress +_MONERO_Wallet_reconnectDevice +_MONERO_Wallet_getBytesReceived +_MONERO_Wallet_getBytesSent +_MONERO_Wallet_getStateIsConnected +_MONERO_Wallet_getSendToDevice +_MONERO_Wallet_getSendToDeviceLength +_MONERO_Wallet_getReceivedFromDevice +_MONERO_Wallet_getReceivedFromDeviceLength +_MONERO_Wallet_getWaitsForDeviceSend +_MONERO_Wallet_getWaitsForDeviceReceive +_MONERO_Wallet_setDeviceReceivedData +_MONERO_Wallet_setDeviceSendData +_MONERO_WalletManager_createWallet +_MONERO_WalletManager_openWallet +_MONERO_WalletManager_recoveryWallet +_MONERO_WalletManager_createWalletFromKeys +_MONERO_WalletManager_createDeterministicWalletFromSpendKey +_MONERO_WalletManager_createWalletFromDevice +_MONERO_WalletManager_createWalletFromPolyseed +_MONERO_WalletManager_closeWallet +_MONERO_WalletManager_walletExists +_MONERO_WalletManager_verifyWalletPassword +_MONERO_WalletManager_queryWalletDevice +_MONERO_WalletManager_findWallets +_MONERO_WalletManager_errorString +_MONERO_WalletManager_setDaemonAddress +_MONERO_WalletManager_blockchainHeight +_MONERO_WalletManager_blockchainTargetHeight +_MONERO_WalletManager_networkDifficulty +_MONERO_WalletManager_miningHashRate +_MONERO_WalletManager_blockTarget +_MONERO_WalletManager_isMining +_MONERO_WalletManager_startMining +_MONERO_WalletManager_stopMining +_MONERO_WalletManager_resolveOpenAlias +_MONERO_WalletManager_setProxy +_MONERO_WalletManagerFactory_getWalletManager +_MONERO_WalletManagerFactory_setLogLevel +_MONERO_WalletManagerFactory_setLogCategories +_MONERO_DEBUG_test0 +_MONERO_DEBUG_test1 +_MONERO_DEBUG_test2 +_MONERO_DEBUG_test3 +_MONERO_DEBUG_test4 +_MONERO_DEBUG_test5 +_MONERO_DEBUG_test5_std +_MONERO_DEBUG_isPointerNull +_MONERO_cw_getWalletListener +_MONERO_cw_WalletListener_resetNeedToRefresh +_MONERO_cw_WalletListener_isNeedToRefresh +_MONERO_cw_WalletListener_isNewTransactionExist +_MONERO_cw_WalletListener_resetIsNewTransactionExist +_MONERO_cw_WalletListener_height +_MONERO_free +_MONERO_checksum_wallet2_api_c_h +_MONERO_checksum_wallet2_api_c_cpp +_MONERO_checksum_wallet2_api_c_exp diff --git a/salvium_libwallet2_api_c/src/main/cpp/helpers.cpp b/salvium_libwallet2_api_c/src/main/cpp/helpers.cpp new file mode 100644 index 0000000..324c12d --- /dev/null +++ b/salvium_libwallet2_api_c/src/main/cpp/helpers.cpp @@ -0,0 +1,265 @@ +#include +#include +#include +#include +#include +#include +#include +#include "helpers.hpp" +#include +#include +#include +#include +#include +#include + +#ifdef __ANDROID__ +#include + +#define LOG_TAG "moneroc" +#define BUFFER_SIZE 1024*32 + +static int stdoutToLogcat(const char *buf, int size) { + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, buf); + return size; +} + +static int stderrToLogcat(const char *buf, int size) { + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, buf); + return size; +} + +void redirectStdoutThread(int pipe_stdout[2]) { + char bufferStdout[BUFFER_SIZE]; + while (true) { + int read_size = read(pipe_stdout[0], bufferStdout, sizeof(bufferStdout) - 1); + if (read_size > 0) { + bufferStdout[read_size] = '\0'; + stdoutToLogcat(bufferStdout, read_size); + } + } +} + +void redirectStderrThread(int pipe_stderr[2]) { + char bufferStderr[BUFFER_SIZE]; + while (true) { + int read_size = read(pipe_stderr[0], bufferStderr, sizeof(bufferStderr) - 1); + if (read_size > 0) { + bufferStderr[read_size] = '\0'; + stderrToLogcat(bufferStderr, read_size); + } + } +} + +void setupAndroidLogging() { + static int pfdStdout[2]; + static int pfdStderr[2]; + + pipe(pfdStdout); + pipe(pfdStderr); + + dup2(pfdStdout[1], STDOUT_FILENO); + dup2(pfdStderr[1], STDERR_FILENO); + + std::thread stdoutThread(redirectStdoutThread, pfdStdout); + std::thread stderrThread(redirectStderrThread, pfdStderr); + + stdoutThread.detach(); + stderrThread.detach(); +} + +#endif // __ANDROID__ + +__attribute__((constructor)) +void library_init() { +#ifdef __ANDROID__ + setupAndroidLogging(); // This will now run automatically when the library is loaded +#endif +} + +const char* vectorToString(const std::vector& vec, const std::string separator) { + // Check if the vector is empty + if (vec.empty()) { + return ""; + } + + // Concatenate all strings in the vector + std::string result; + for (size_t i = 0; i < vec.size() - 1; ++i) { + result += vec[i]; + result += separator; + } + result += vec.back(); // Append the last string without the separator + + std::string str = result; + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; +} + +const char* vectorToString(const std::vector& vec, const std::string separator) { + // Calculate the size needed for the result string + size_t size = 0; + for (size_t i = 0; i < vec.size(); ++i) { + // Calculate the number of digits in each element + size += snprintf(nullptr, 0, "%u", vec[i]); + // Add comma and space for all elements except the last one + if (i < vec.size() - 1) { + size += separator.size(); // comma and space + } + } + + // Allocate memory for the result string + char* result = static_cast(malloc(size + 1)); + if (result == nullptr) { + // Handle memory allocation failure + return nullptr; + } + + // Fill in the result string + char* current = result; + for (size_t i = 0; i < vec.size(); ++i) { + // Convert each element to string and copy to the result string + int written = snprintf(current, size + 1, "%u", vec[i]); + current += written; + // Add comma and space for all elements except the last one + if (i < vec.size() - 1) { + strcpy(current, separator.c_str()); + current += separator.size(); + } + } + + return result; +} + +const char* vectorToString(const std::vector& vec, const std::string separator) { + // Calculate the size needed for the result string + size_t size = 0; + for (size_t i = 0; i < vec.size(); ++i) { + // Calculate the number of digits in each element + size += snprintf(nullptr, 0, "%llu", vec[i]); + // Add comma and space for all elements except the last one + if (i < vec.size() - 1) { + size += separator.size(); // comma and space + } + } + + // Allocate memory for the result string + char* result = static_cast(malloc(size + 1)); + if (result == nullptr) { + // Handle memory allocation failure + return nullptr; + } + + // Fill in the result string + char* current = result; + for (size_t i = 0; i < vec.size(); ++i) { + // Convert each element to string and copy to the result string + int written = snprintf(current, size + 1, "%llu", vec[i]); + current += written; + // Add comma and space for all elements except the last one + if (i < vec.size() - 1) { + strcpy(current, separator.c_str()); + current += separator.size(); + } + } + + return result; +} + +const char* vectorToString(const std::vector>& vec, const std::string separator) { + // Check if the vector is empty + if (vec.empty()) { + return ""; + } + + // Use a stringstream to concatenate sets with commas and individual elements with spaces + std::ostringstream oss; + oss << "{"; + for (auto it = vec.begin(); it != vec.end(); ++it) { + if (it != vec.begin()) { + oss << separator; + } + + oss << "{"; + for (auto setIt = it->begin(); setIt != it->end(); ++setIt) { + if (setIt != it->begin()) { + oss << separator; + } + oss << *setIt; + } + oss << "}"; + } + oss << "}"; + std::string str = oss.str(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; +} + +// Function to convert std::set to a string +const char* vectorToString(const std::set& intSet, const std::string separator) { + // Check if the set is empty + if (intSet.empty()) { + return ""; + } + + // Use a stringstream to concatenate elements with commas + std::ostringstream oss; + auto it = intSet.begin(); + oss << *it; + for (++it; it != intSet.end(); ++it) { + oss << ", " << *it; + } + + std::string str = oss.str(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; +} + +std::set splitString(const std::string& str, const std::string& delim) { + std::set tokens; + if (str.empty()) return tokens; + size_t pos = 0; + std::string token; + std::string content = str; // Copy of str so we can safely erase content + while ((pos = content.find(delim)) != std::string::npos) { + token = content.substr(0, pos); + tokens.insert(token); + content.erase(0, pos + delim.length()); + } + tokens.insert(content); // Inserting the last token + return tokens; +} + +std::vector splitStringVector(const std::string& str, const std::string& delim) { + std::vector tokens; + if (str.empty()) return tokens; + size_t pos = 0; + std::string content = str; // Copy of str so we can safely erase content + while ((pos = content.find(delim)) != std::string::npos) { + tokens.push_back(content.substr(0, pos)); + content.erase(0, pos + delim.length()); + } + tokens.push_back(content); // Inserting the last token + return tokens; +} + +std::vector splitStringUint(const std::string& str, const std::string& delim) { + std::vector tokens; + if (str.empty()) return tokens; + size_t pos = 0; + std::string token; + std::string content = str; // Copy of str so we can safely erase content + while ((pos = content.find(delim)) != std::string::npos) { + token = content.substr(0, pos); + tokens.push_back(std::stoull(token)); // Convert string to uint64_t and push to vector + content.erase(0, pos + delim.length()); + } + tokens.push_back(std::stoull(content)); // Inserting the last token + return tokens; +} \ No newline at end of file diff --git a/salvium_libwallet2_api_c/src/main/cpp/helpers.hpp b/salvium_libwallet2_api_c/src/main/cpp/helpers.hpp new file mode 100644 index 0000000..83cf33b --- /dev/null +++ b/salvium_libwallet2_api_c/src/main/cpp/helpers.hpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include + +// Debug macros +#define DEBUG_START() \ + try { + +#define DEBUG_END() \ + } catch (const std::exception &e) { \ + std::cerr << "Exception caught in function: " << __FUNCTION__ \ + << " at " << __FILE__ << ":" << __LINE__ << std::endl \ + << "Message: " << e.what() << std::endl; \ + std::abort(); \ + } catch (...) { \ + std::cerr << "Unknown exception caught in function: " << __FUNCTION__ \ + << " at " << __FILE__ << ":" << __LINE__ << std::endl; \ + std::abort(); \ + } + + +const char* vectorToString(const std::vector& vec, const std::string separator); +const char* vectorToString(const std::vector& vec, const std::string separator); +const char* vectorToString(const std::vector& vec, const std::string separator); +const char* vectorToString(const std::vector>& vec, const std::string separator); +const char* vectorToString(const std::set& intSet, const std::string separator); +std::set splitString(const std::string& str, const std::string& delim); +std::vector splitStringUint(const std::string& str, const std::string& delim); +std::vector splitStringVector(const std::string& str, const std::string& delim); \ No newline at end of file diff --git a/salvium_libwallet2_api_c/src/main/cpp/monero_checksum.h b/salvium_libwallet2_api_c/src/main/cpp/monero_checksum.h new file mode 100644 index 0000000..4e0fb1c --- /dev/null +++ b/salvium_libwallet2_api_c/src/main/cpp/monero_checksum.h @@ -0,0 +1,6 @@ +#ifndef MONEROC_CHECKSUMS +#define MONEROC_CHECKSUMS +const char * MONERO_wallet2_api_c_h_sha256 = "9e80c4b59a0509aa02fbf01e8df2881b89f82225d1765bfa7856cbdbaf7af116"; +const char * MONERO_wallet2_api_c_cpp_sha256 = "d229507db508e574bd2badf4819a38dbead8c16a84311ad32c22c887a6003439-0232839913b13cf0ab0bb7ad25fff0c05f37d2fe"; +const char * MONERO_wallet2_api_c_exp_sha256 = "d0f95f1f3bc49f1f59fe4eb0b61826128d7d3bb75405d5a01a252d02db03097d"; +#endif diff --git a/salvium_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp b/salvium_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp new file mode 100644 index 0000000..19192cf --- /dev/null +++ b/salvium_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp @@ -0,0 +1,2621 @@ +#include +#include "wallet2_api_c.h" +#include +#include "helpers.hpp" +#include +#include +#include "../../../../monero/src/wallet/api/wallet2_api.h" +#include "monero_checksum.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +// The code in here consists of simple wrappers, that convert +// more advanced c++ types (and function names) into simple C-compatible +// functions, so these implementations can be easly used from all languages +// that do support C interop (such as dart) +// +// +// Here is the most complex definition that we can find in the current codebase, it even includes +// a if statement - which in general I consider an anti-patter in just wrappers +// +// _____________ void* because C++ wallet->createTransaction returns a pointer to Monero::PendingTransaction, which we don't want to have exposed in C land +// / _____________ MONERO prefix just means that this function is using monero codebase, to not cause any symbols collision when using more than one libwallet2_api_c.so in a single program. +// | / _____________ Wallet is one of the classes in Monero namespace in the upstream codebase (see the include line above) +// | | / _____________ aaand it is calling createTransaction function. +// | | | / _________________________________________________________________________________ +// | | | | / \ All of these parameters can be found in the upstream +// | | | | | _____________/ function definition, if something was more complex - +// void* MONERO_Wallet_createTransaction(void* wallet_ptr, const char* dst_addr, const char* payment_id, / like std::set I've used splitString functions and introduced a new +// uint64_t amount, uint32_t mixin_count, / parameter - separator, as it is the simplest way to get vector onto +// int pendingTransactionPriority, / C side from more advanced world. +// uint32_t subaddr_account, / +// const char* preferredInputs, const char* separator) { +// Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); <------------ We are converting the void* into Monero::Wallet* +// Monero::optional optAmount; <------------- optional by default +// if (amount != 0) {------------------\ We set this optional parameter only when it isn't zero +// optAmount = amount; | +// }___________________________________/ +// std::set subaddr_indices = {}; ------------- Default value +// std::set preferred_inputs = splitString(std::string(preferredInputs), std::string(separator)); <------------- We are using helpers.cpp function to split a string into std::set +// return wallet->createTransaction(std::string(dst_addr), std::string(payment_id),-\ const char * is getting casted onto std::string +// optAmount, mixin_count, \_____________/ +// PendingTransaction_Priority_fromInt(pendingTransactionPriority), <------------- special case for this function to get native type instead of int value. +// subaddr_account, subaddr_indices, preferred_inputs); +// } +// +// +// One case which is not covered here is when we have to return a string +// const char* MONERO_PendingTransaction_errorString(void* pendingTx_ptr) { +// Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); +// std::string str = pendingTx->errorString(); <------------- get the actual string from the upstream codebase +// const std::string::size_type size = str.size(); ------------------------------\ +// char *buffer = new char[size + 1]; //we need extra char for NUL | Copy the string onto a new memory so it won't get freed after the function returns +// memcpy(buffer, str.c_str(), size + 1); | NOTE: This requires us to call free() after we are done with the text processing +// return buffer; ______________________________________________________________/ +// } +// +// + +// PendingTransaction + +int MONERO_PendingTransaction_status(void* pendingTx_ptr) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + return pendingTx->status(); + DEBUG_END() +} +const char* MONERO_PendingTransaction_errorString(void* pendingTx_ptr) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + std::string str = pendingTx->errorString(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +bool MONERO_PendingTransaction_commit(void* pendingTx_ptr, const char* filename, bool overwrite) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + return pendingTx->commit(std::string(filename), overwrite); + DEBUG_END() +} +const char* MONERO_PendingTransaction_commitUR(void* pendingTx_ptr, int max_fragment_length) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + std::string str = pendingTx->commitUR(max_fragment_length); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +uint64_t MONERO_PendingTransaction_amount(void* pendingTx_ptr) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + return pendingTx->amount(); + DEBUG_END() +} +uint64_t MONERO_PendingTransaction_dust(void* pendingTx_ptr) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + return pendingTx->dust(); + DEBUG_END() +} +uint64_t MONERO_PendingTransaction_fee(void* pendingTx_ptr) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + return pendingTx->fee(); + DEBUG_END() +} +const char* MONERO_PendingTransaction_txid(void* pendingTx_ptr, const char* separator) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + std::vector txid = pendingTx->txid(); + return vectorToString(txid, std::string(separator)); + DEBUG_END() +} +uint64_t MONERO_PendingTransaction_txCount(void* pendingTx_ptr) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + return pendingTx->txCount(); + DEBUG_END() +} +const char* MONERO_PendingTransaction_subaddrAccount(void* pendingTx_ptr, const char* separator) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + std::vector subaddrAccount = pendingTx->subaddrAccount(); + return vectorToString(subaddrAccount, std::string(separator)); + DEBUG_END() +} +const char* MONERO_PendingTransaction_subaddrIndices(void* pendingTx_ptr, const char* separator) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + std::vector> subaddrIndices = pendingTx->subaddrIndices(); + return vectorToString(subaddrIndices, std::string(separator)); + DEBUG_END() +} +const char* MONERO_PendingTransaction_multisigSignData(void* pendingTx_ptr) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + std::string str = pendingTx->multisigSignData(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +void MONERO_PendingTransaction_signMultisigTx(void* pendingTx_ptr) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + return pendingTx->signMultisigTx(); + DEBUG_END() +} +const char* MONERO_PendingTransaction_signersKeys(void* pendingTx_ptr, const char* separator) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + std::vector txid = pendingTx->signersKeys(); + return vectorToString(txid, std::string(separator)); + DEBUG_END() +} + +const char* MONERO_PendingTransaction_hex(void* pendingTx_ptr, const char* separator) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + std::vector txid = pendingTx->hex(); + return vectorToString(txid, std::string(separator)); + DEBUG_END() +} + +const char* MONERO_PendingTransaction_txKey(void* pendingTx_ptr, const char* separator) { + DEBUG_START() + Monero::PendingTransaction *pendingTx = reinterpret_cast(pendingTx_ptr); + std::vector txid = pendingTx->txKey(); + return vectorToString(txid, std::string(separator)); + DEBUG_END() +} + +// UnsignedTransaction + +int MONERO_UnsignedTransaction_status(void* unsignedTx_ptr) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + return unsignedTx->status(); + DEBUG_END() +} +const char* MONERO_UnsignedTransaction_errorString(void* unsignedTx_ptr) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + std::string str = unsignedTx->errorString(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +const char* MONERO_UnsignedTransaction_amount(void* unsignedTx_ptr, const char* separator) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + return vectorToString(unsignedTx->amount(), std::string(separator)); + DEBUG_END() +} +const char* MONERO_UnsignedTransaction_fee(void* unsignedTx_ptr, const char* separator) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + return vectorToString(unsignedTx->fee(), std::string(separator)); + DEBUG_END() +} +const char* MONERO_UnsignedTransaction_mixin(void* unsignedTx_ptr, const char* separator) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + return vectorToString(unsignedTx->mixin(), std::string(separator)); + DEBUG_END() +} +const char* MONERO_UnsignedTransaction_confirmationMessage(void* unsignedTx_ptr) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + std::string str = unsignedTx->confirmationMessage(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +const char* MONERO_UnsignedTransaction_paymentId(void* unsignedTx_ptr, const char* separator) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + return vectorToString(unsignedTx->paymentId(), std::string(separator)); + DEBUG_END() +} +const char* MONERO_UnsignedTransaction_recipientAddress(void* unsignedTx_ptr, const char* separator) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + return vectorToString(unsignedTx->recipientAddress(), std::string(separator)); + DEBUG_END() +} +uint64_t MONERO_UnsignedTransaction_minMixinCount(void* unsignedTx_ptr) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + return unsignedTx->minMixinCount(); + DEBUG_END() +} +uint64_t MONERO_UnsignedTransaction_txCount(void* unsignedTx_ptr) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + return unsignedTx->txCount(); + DEBUG_END() +} +bool MONERO_UnsignedTransaction_sign(void* unsignedTx_ptr, const char* signedFileName) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + return unsignedTx->sign(std::string(signedFileName)); + DEBUG_END() +} +const char* MONERO_UnsignedTransaction_signUR(void* unsignedTx_ptr, int max_fragment_length) { + DEBUG_START() + Monero::UnsignedTransaction *unsignedTx = reinterpret_cast(unsignedTx_ptr); + std::string str = unsignedTx->signUR(max_fragment_length); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// TransactionInfo +int MONERO_TransactionInfo_direction(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->direction(); + DEBUG_END() +} +bool MONERO_TransactionInfo_isPending(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->isPending(); + DEBUG_END() +} +bool MONERO_TransactionInfo_isFailed(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->isFailed(); + DEBUG_END() +} +bool MONERO_TransactionInfo_isCoinbase(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->isCoinbase(); + DEBUG_END() +} +uint64_t MONERO_TransactionInfo_amount(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->amount(); + DEBUG_END() +} +uint64_t MONERO_TransactionInfo_fee(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->fee(); + DEBUG_END() +} +uint64_t MONERO_TransactionInfo_blockHeight(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->blockHeight(); + DEBUG_END() +} +const char* MONERO_TransactionInfo_description(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + std::string str = txInfo->description(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +const char* MONERO_TransactionInfo_subaddrIndex(void* txInfo_ptr, const char* separator) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + std::set subaddrIndex = txInfo->subaddrIndex(); + return vectorToString(subaddrIndex, std::string(separator)); + DEBUG_END() +} +uint32_t MONERO_TransactionInfo_subaddrAccount(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->subaddrAccount(); + DEBUG_END() +} +const char* MONERO_TransactionInfo_label(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + std::string str = txInfo->label(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +uint64_t MONERO_TransactionInfo_confirmations(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->confirmations(); + DEBUG_END() +} +uint64_t MONERO_TransactionInfo_unlockTime(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->unlockTime(); + DEBUG_END() +} +const char* MONERO_TransactionInfo_hash(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + std::string str = txInfo->hash(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +uint64_t MONERO_TransactionInfo_timestamp(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->timestamp(); + DEBUG_END() +} +const char* MONERO_TransactionInfo_paymentId(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + std::string str = txInfo->paymentId(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +int MONERO_TransactionInfo_transfers_count(void* txInfo_ptr) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->transfers().size(); + DEBUG_END() +} + +uint64_t MONERO_TransactionInfo_transfers_amount(void* txInfo_ptr, int index) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + return txInfo->transfers()[index].amount; + DEBUG_END() +} + +const char* MONERO_TransactionInfo_transfers_address(void* txInfo_ptr, int index) { + DEBUG_START() + Monero::TransactionInfo *txInfo = reinterpret_cast(txInfo_ptr); + std::string str = txInfo->transfers()[index].address; + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + + + + +// TransactionHistory +int MONERO_TransactionHistory_count(void* txHistory_ptr) { + DEBUG_START() + Monero::TransactionHistory *txHistory = reinterpret_cast(txHistory_ptr); + return txHistory->count(); + DEBUG_END() +} +void* MONERO_TransactionHistory_transaction(void* txHistory_ptr, int index) { + DEBUG_START() + Monero::TransactionHistory *txHistory = reinterpret_cast(txHistory_ptr); + return reinterpret_cast(txHistory->transaction(index)); + DEBUG_END() +} +void* MONERO_TransactionHistory_transactionById(void* txHistory_ptr, const char* id) { + DEBUG_START() + Monero::TransactionHistory *txHistory = reinterpret_cast(txHistory_ptr); + return reinterpret_cast(txHistory->transaction(std::string(id))); + DEBUG_END() +} + +void MONERO_TransactionHistory_refresh(void* txHistory_ptr) { + DEBUG_START() + Monero::TransactionHistory *txHistory = reinterpret_cast(txHistory_ptr); + return txHistory->refresh(); + DEBUG_END() +} +void MONERO_TransactionHistory_setTxNote(void* txHistory_ptr, const char* txid, const char* note) { + DEBUG_START() + Monero::TransactionHistory *txHistory = reinterpret_cast(txHistory_ptr); + return txHistory->setTxNote(std::string(txid), std::string(note)); + DEBUG_END() +} + +// AddressBokRow + +// std::string extra; +const char* MONERO_AddressBookRow_extra(void* addressBookRow_ptr) { + DEBUG_START() + Monero::AddressBookRow *addressBookRow = reinterpret_cast(addressBookRow_ptr); + std::string str = addressBookRow->extra; + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::string getAddress() const {return m_address;} +const char* MONERO_AddressBookRow_getAddress(void* addressBookRow_ptr) { + DEBUG_START() + Monero::AddressBookRow *addressBookRow = reinterpret_cast(addressBookRow_ptr); + std::string str = addressBookRow->getAddress(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::string getDescription() const {return m_description;} +const char* MONERO_AddressBookRow_getDescription(void* addressBookRow_ptr) { + DEBUG_START() + Monero::AddressBookRow *addressBookRow = reinterpret_cast(addressBookRow_ptr); + std::string str = addressBookRow->getDescription(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::string getPaymentId() const {return m_paymentId;} +const char* MONERO_AddressBookRow_getPaymentId(void* addressBookRow_ptr) { + DEBUG_START() + Monero::AddressBookRow *addressBookRow = reinterpret_cast(addressBookRow_ptr); + std::string str = addressBookRow->getPaymentId(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::size_t getRowId() const {return m_rowId;} +size_t MONERO_AddressBookRow_getRowId(void* addressBookRow_ptr) { + DEBUG_START() + Monero::AddressBookRow *addressBookRow = reinterpret_cast(addressBookRow_ptr); + return addressBookRow->getRowId(); + DEBUG_END() +} + +// AddressBook +// virtual std::vector getAll() const = 0; +int MONERO_AddressBook_getAll_size(void* addressBook_ptr) { + DEBUG_START() + Monero::AddressBook *addressBook = reinterpret_cast(addressBook_ptr); + return addressBook->getAll().size(); + DEBUG_END() +} +void* MONERO_AddressBook_getAll_byIndex(void* addressBook_ptr, int index) { + DEBUG_START() + Monero::AddressBook *addressBook = reinterpret_cast(addressBook_ptr); + return addressBook->getAll()[index]; + DEBUG_END() +} +// virtual bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) = 0; +bool MONERO_AddressBook_addRow(void* addressBook_ptr, const char* dst_addr , const char* payment_id, const char* description) { + DEBUG_START() + Monero::AddressBook *addressBook = reinterpret_cast(addressBook_ptr); + return addressBook->addRow(std::string(dst_addr), std::string(payment_id), std::string(description)); + DEBUG_END() +} +// virtual bool deleteRow(std::size_t rowId) = 0; +bool MONERO_AddressBook_deleteRow(void* addressBook_ptr, size_t rowId) { + DEBUG_START() + Monero::AddressBook *addressBook = reinterpret_cast(addressBook_ptr); + return addressBook->deleteRow(rowId); + DEBUG_END() +} +// virtual bool setDescription(std::size_t index, const std::string &description) = 0; +bool MONERO_AddressBook_setDescription(void* addressBook_ptr, size_t rowId, const char* description) { + DEBUG_START() + Monero::AddressBook *addressBook = reinterpret_cast(addressBook_ptr); + return addressBook->setDescription(rowId, std::string(description)); + DEBUG_END() +} +// virtual void refresh() = 0; +void MONERO_AddressBook_refresh(void* addressBook_ptr) { + DEBUG_START() + Monero::AddressBook *addressBook = reinterpret_cast(addressBook_ptr); + return addressBook->refresh(); + DEBUG_END() +} +// virtual std::string errorString() const = 0; +const char* MONERO_AddressBook_errorString(void* addressBook_ptr) { + DEBUG_START() + Monero::AddressBook *addressBook = reinterpret_cast(addressBook_ptr); + std::string str = addressBook->errorString(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// virtual int errorCode() const = 0; +int MONERO_AddressBook_errorCode(void* addressBook_ptr) { + DEBUG_START() + Monero::AddressBook *addressBook = reinterpret_cast(addressBook_ptr); + return addressBook->errorCode(); + DEBUG_END() +} +// virtual int lookupPaymentID(const std::string &payment_id) const = 0; +int MONERO_AddressBook_lookupPaymentID(void* addressBook_ptr, const char* payment_id) { + DEBUG_START() + Monero::AddressBook *addressBook = reinterpret_cast(addressBook_ptr); + return addressBook->lookupPaymentID(std::string(payment_id)); + DEBUG_END() +} + +// CoinsInfo +uint64_t MONERO_CoinsInfo_blockHeight(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->blockHeight(); + DEBUG_END() +} +// virtual std::string hash() const = 0; +const char* MONERO_CoinsInfo_hash(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + std::string str = coinsInfo->hash(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// virtual size_t internalOutputIndex() const = 0; +size_t MONERO_CoinsInfo_internalOutputIndex(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->internalOutputIndex(); + DEBUG_END() +} +// virtual uint64_t globalOutputIndex() const = 0; +uint64_t MONERO_CoinsInfo_globalOutputIndex(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->globalOutputIndex(); + DEBUG_END() +} +// virtual bool spent() const = 0; +bool MONERO_CoinsInfo_spent(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->spent(); + DEBUG_END() +} +// virtual bool frozen() const = 0; +bool MONERO_CoinsInfo_frozen(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->frozen(); + DEBUG_END() +} +// virtual uint64_t spentHeight() const = 0; +uint64_t MONERO_CoinsInfo_spentHeight(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->spentHeight(); + DEBUG_END() +} +// virtual uint64_t amount() const = 0; +uint64_t MONERO_CoinsInfo_amount(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->amount(); + DEBUG_END() +} +// virtual bool rct() const = 0; +bool MONERO_CoinsInfo_rct(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->rct(); + DEBUG_END() +} +// virtual bool keyImageKnown() const = 0; +bool MONERO_CoinsInfo_keyImageKnown(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->keyImageKnown(); + DEBUG_END() +} +// virtual size_t pkIndex() const = 0; +size_t MONERO_CoinsInfo_pkIndex(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->pkIndex(); + DEBUG_END() +} +// virtual uint32_t subaddrIndex() const = 0; +uint32_t MONERO_CoinsInfo_subaddrIndex(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->subaddrIndex(); + DEBUG_END() +} +// virtual uint32_t subaddrAccount() const = 0; +uint32_t MONERO_CoinsInfo_subaddrAccount(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->subaddrAccount(); + DEBUG_END() +} +// virtual std::string address() const = 0; +const char* MONERO_CoinsInfo_address(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + std::string str = coinsInfo->address(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// virtual std::string addressLabel() const = 0; +const char* MONERO_CoinsInfo_addressLabel(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + std::string str = coinsInfo->addressLabel(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// virtual std::string keyImage() const = 0; +const char* MONERO_CoinsInfo_keyImage(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + std::string str = coinsInfo->keyImage(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// virtual uint64_t unlockTime() const = 0; +uint64_t MONERO_CoinsInfo_unlockTime(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->unlockTime(); + DEBUG_END() +} +// virtual bool unlocked() const = 0; +bool MONERO_CoinsInfo_unlocked(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->unlocked(); + DEBUG_END() +} +// virtual std::string pubKey() const = 0; +const char* MONERO_CoinsInfo_pubKey(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + std::string str = coinsInfo->pubKey(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// virtual bool coinbase() const = 0; +bool MONERO_CoinsInfo_coinbase(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + return coinsInfo->coinbase(); + DEBUG_END() +} +// virtual std::string description() const = 0; +const char* MONERO_CoinsInfo_description(void* coinsInfo_ptr) { + DEBUG_START() + Monero::CoinsInfo *coinsInfo = reinterpret_cast(coinsInfo_ptr); + std::string str = coinsInfo->description(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + + +// coins + +// virtual ~Coins() = 0; +// virtual int count() const = 0; +int MONERO_Coins_count(void* coins_ptr) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->count(); + DEBUG_END() +} +// virtual CoinsInfo * coin(int index) const = 0; +void* MONERO_Coins_coin(void* coins_ptr, int index) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->coin(index); + DEBUG_END() +} + +int MONERO_Coins_getAll_size(void* coins_ptr) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->getAll().size(); + DEBUG_END() +} +void* MONERO_Coins_getAll_byIndex(void* coins_ptr, int index) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->getAll()[index]; + DEBUG_END() +} + +// virtual std::vector getAll() const = 0; +// virtual void refresh() = 0; +void MONERO_Coins_refresh(void* coins_ptr) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->refresh(); + DEBUG_END() +} +// virtual void setFrozen(std::string public_key) = 0; +void MONERO_Coins_setFrozenByPublicKey(void* coins_ptr, const char* public_key) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->setFrozen(std::string(public_key)); + DEBUG_END() +} +// virtual void setFrozen(int index) = 0; +void MONERO_Coins_setFrozen(void* coins_ptr, int index) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->setFrozen(index); + DEBUG_END() +} +// virtual void thaw(int index) = 0; +void MONERO_Coins_thaw(void* coins_ptr, int index) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->thaw(index); + DEBUG_END() +} +// virtual void thaw(std::string public_key) = 0; +void MONERO_Coins_thawByPublicKey(void* coins_ptr, const char* public_key) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->thaw(std::string(public_key)); + DEBUG_END() +} +// virtual bool isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) = 0; +bool MONERO_Coins_isTransferUnlocked(void* coins_ptr, uint64_t unlockTime, uint64_t blockHeight) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->isTransferUnlocked(unlockTime, blockHeight); + DEBUG_END() +} +// virtual void setDescription(const std::string &public_key, const std::string &description) = 0; +void MONERO_Coins_setDescription(void* coins_ptr, const char* public_key, const char* description) { + DEBUG_START() + Monero::Coins *coins = reinterpret_cast(coins_ptr); + return coins->setDescription(std::string(public_key), std::string(description)); + DEBUG_END() +} + +// SubaddressRow + +// std::string extra; +const char* MONERO_SubaddressRow_extra(void* subaddressRow_ptr) { + DEBUG_START() + Monero::SubaddressRow *subaddressRow = reinterpret_cast(subaddressRow_ptr); + std::string str = subaddressRow->extra; + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::string getAddress() const {return m_address;} +const char* MONERO_SubaddressRow_getAddress(void* subaddressRow_ptr) { + DEBUG_START() + Monero::SubaddressRow *subaddressRow = reinterpret_cast(subaddressRow_ptr); + std::string str = subaddressRow->getAddress(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::string getLabel() const {return m_label;} +const char* MONERO_SubaddressRow_getLabel(void* subaddressRow_ptr) { + DEBUG_START() + Monero::SubaddressRow *subaddressRow = reinterpret_cast(subaddressRow_ptr); + std::string str = subaddressRow->getLabel(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::size_t getRowId() const {return m_rowId;} +size_t MONERO_SubaddressRow_getRowId(void* subaddressRow_ptr) { + DEBUG_START() + Monero::SubaddressRow *subaddressRow = reinterpret_cast(subaddressRow_ptr); + return subaddressRow->getRowId(); + DEBUG_END() +} + +// Subaddress + +int MONERO_Subaddress_getAll_size(void* subaddress_ptr) { + DEBUG_START() + Monero::Subaddress *subaddress = reinterpret_cast(subaddress_ptr); + return subaddress->getAll().size(); + DEBUG_END() +} +void* MONERO_Subaddress_getAll_byIndex(void* subaddress_ptr, int index) { + DEBUG_START() + Monero::Subaddress *subaddress = reinterpret_cast(subaddress_ptr); + return subaddress->getAll()[index]; + DEBUG_END() +} +// virtual void addRow(uint32_t accountIndex, const std::string &label) = 0; +void MONERO_Subaddress_addRow(void* subaddress_ptr, uint32_t accountIndex, const char* label) { + DEBUG_START() + Monero::Subaddress *subaddress = reinterpret_cast(subaddress_ptr); + return subaddress->addRow(accountIndex, std::string(label)); + DEBUG_END() +} +// virtual void setLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label) = 0; +void MONERO_Subaddress_setLabel(void* subaddress_ptr, uint32_t accountIndex, uint32_t addressIndex, const char* label) { + DEBUG_START() + Monero::Subaddress *subaddress = reinterpret_cast(subaddress_ptr); + return subaddress->setLabel(accountIndex, addressIndex, std::string(label)); + DEBUG_END() +} +// virtual void refresh(uint32_t accountIndex) = 0; +void MONERO_Subaddress_refresh(void* subaddress_ptr, uint32_t accountIndex) { + DEBUG_START() + Monero::Subaddress *subaddress = reinterpret_cast(subaddress_ptr); + return subaddress->refresh(accountIndex); + DEBUG_END() +} + +// SubaddressAccountRow + +// std::string extra; +const char* MONERO_SubaddressAccountRow_extra(void* subaddressAccountRow_ptr) { + DEBUG_START() + Monero::SubaddressAccountRow *subaddressAccountRow = reinterpret_cast(subaddressAccountRow_ptr); + std::string str = subaddressAccountRow->extra; + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::string getAddress() const {return m_address;} +const char* MONERO_SubaddressAccountRow_getAddress(void* subaddressAccountRow_ptr) { + DEBUG_START() + Monero::SubaddressAccountRow *subaddressAccountRow = reinterpret_cast(subaddressAccountRow_ptr); + std::string str = subaddressAccountRow->getAddress(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::string getLabel() const {return m_label;} +const char* MONERO_SubaddressAccountRow_getLabel(void* subaddressAccountRow_ptr) { + DEBUG_START() + Monero::SubaddressAccountRow *subaddressAccountRow = reinterpret_cast(subaddressAccountRow_ptr); + std::string str = subaddressAccountRow->getLabel(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::string getBalance() const {return m_balance;} +const char* MONERO_SubaddressAccountRow_getBalance(void* subaddressAccountRow_ptr) { + DEBUG_START() + Monero::SubaddressAccountRow *subaddressAccountRow = reinterpret_cast(subaddressAccountRow_ptr); + std::string str = subaddressAccountRow->getBalance(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::string getUnlockedBalance() const {return m_unlockedBalance;} +const char* MONERO_SubaddressAccountRow_getUnlockedBalance(void* subaddressAccountRow_ptr) { + DEBUG_START() + Monero::SubaddressAccountRow *subaddressAccountRow = reinterpret_cast(subaddressAccountRow_ptr); + std::string str = subaddressAccountRow->getUnlockedBalance(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// std::size_t getRowId() const {return m_rowId;} +size_t MONERO_SubaddressAccountRow_getRowId(void* subaddressAccountRow_ptr) { + DEBUG_START() + Monero::SubaddressAccountRow *subaddressAccountRow = reinterpret_cast(subaddressAccountRow_ptr); + return subaddressAccountRow->getRowId(); + DEBUG_END() +} + +// struct SubaddressAccount +// { +// virtual ~SubaddressAccount() = 0; +// virtual std::vector getAll() const = 0; +int MONERO_SubaddressAccount_getAll_size(void* subaddressAccount_ptr) { + DEBUG_START() + Monero::SubaddressAccount *subaddress = reinterpret_cast(subaddressAccount_ptr); + return subaddress->getAll().size(); + DEBUG_END() +} +void* MONERO_SubaddressAccount_getAll_byIndex(void* subaddressAccount_ptr, int index) { + DEBUG_START() + Monero::SubaddressAccount *subaddress = reinterpret_cast(subaddressAccount_ptr); + return subaddress->getAll()[index]; + DEBUG_END() +} +// virtual void addRow(const std::string &label) = 0; +void MONERO_SubaddressAccount_addRow(void* subaddressAccount_ptr, const char* label) { + DEBUG_START() + Monero::SubaddressAccount *subaddress = reinterpret_cast(subaddressAccount_ptr); + return subaddress->addRow(std::string(label)); + DEBUG_END() +} +// virtual void setLabel(uint32_t accountIndex, const std::string &label) = 0; +void MONERO_SubaddressAccount_setLabel(void* subaddressAccount_ptr, uint32_t accountIndex, const char* label) { + DEBUG_START() + Monero::SubaddressAccount *subaddress = reinterpret_cast(subaddressAccount_ptr); + return subaddress->setLabel(accountIndex, std::string(label)); + DEBUG_END() +} +// virtual void refresh() = 0; +void MONERO_SubaddressAccount_refresh(void* subaddressAccount_ptr) { + DEBUG_START() + Monero::SubaddressAccount *subaddress = reinterpret_cast(subaddressAccount_ptr); + return subaddress->refresh(); + DEBUG_END() +} + +// MultisigState + +// bool isMultisig; +bool MONERO_MultisigState_isMultisig(void* multisigState_ptr) { + DEBUG_START() + Monero::MultisigState *multisigState = reinterpret_cast(multisigState_ptr); + return multisigState->isMultisig; + DEBUG_END() +} +// bool isReady; +bool MONERO_MultisigState_isReady(void* multisigState_ptr) { + DEBUG_START() + Monero::MultisigState *multisigState = reinterpret_cast(multisigState_ptr); + return multisigState->isReady; + DEBUG_END() +} +// uint32_t threshold; +uint32_t MONERO_MultisigState_threshold(void* multisigState_ptr) { + DEBUG_START() + Monero::MultisigState *multisigState = reinterpret_cast(multisigState_ptr); + return multisigState->threshold; + DEBUG_END() +} +// uint32_t total; +uint32_t MONERO_MultisigState_total(void* multisigState_ptr) { + DEBUG_START() + Monero::MultisigState *multisigState = reinterpret_cast(multisigState_ptr); + return multisigState->total; + DEBUG_END() +} + +// DeviceProgress + + +// virtual double progress() const { return m_progress; } +bool MONERO_DeviceProgress_progress(void* deviceProgress_ptr) { + DEBUG_START() + Monero::DeviceProgress *deviceProgress = reinterpret_cast(deviceProgress_ptr); + return deviceProgress->progress(); + DEBUG_END() +} +// virtual bool indeterminate() const { return m_indeterminate; } +bool MONERO_DeviceProgress_indeterminate(void* deviceProgress_ptr) { + DEBUG_START() + Monero::DeviceProgress *deviceProgress = reinterpret_cast(deviceProgress_ptr); + return deviceProgress->indeterminate(); + DEBUG_END() +} + +// Wallet + +const char* MONERO_Wallet_seed(void* wallet_ptr, const char* seed_offset) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->seed(std::string(seed_offset)); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_getSeedLanguage(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->getSeedLanguage(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +void MONERO_Wallet_setSeedLanguage(void* wallet_ptr, const char* arg) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setSeedLanguage(std::string(arg)); + DEBUG_END() +} + +int MONERO_Wallet_status(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->status(); + DEBUG_END() +} + +const char* MONERO_Wallet_errorString(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->errorString(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + + +bool MONERO_Wallet_setPassword(void* wallet_ptr, const char* password) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setPassword(std::string(password)); + DEBUG_END() +} + +const char* MONERO_Wallet_getPassword(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->getPassword(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +bool MONERO_Wallet_setDevicePin(void* wallet_ptr, const char* pin) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setDevicePin(std::string(pin)); + DEBUG_END() +} + +bool MONERO_Wallet_setDevicePassphrase(void* wallet_ptr, const char* passphrase) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setDevicePassphrase(std::string(passphrase)); + DEBUG_END() +} + +const char* MONERO_Wallet_address(void* wallet_ptr, uint64_t accountIndex, uint64_t addressIndex) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->address(accountIndex, addressIndex); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_path(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->path(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +int MONERO_Wallet_nettype(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->nettype(); + DEBUG_END() +} +uint8_t MONERO_Wallet_useForkRules(void* wallet_ptr, uint8_t version, int64_t early_blocks) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->useForkRules(version, early_blocks); + DEBUG_END() +} +const char* MONERO_Wallet_integratedAddress(void* wallet_ptr, const char* payment_id) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->integratedAddress(std::string(payment_id)); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_secretViewKey(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->secretViewKey(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_publicViewKey(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->publicViewKey(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_secretSpendKey(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->secretSpendKey(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_publicSpendKey(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->publicSpendKey(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +const char* MONERO_Wallet_publicMultisigSignerKey(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->publicMultisigSignerKey(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +void MONERO_Wallet_stop(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->stop(); + DEBUG_END() +} + +bool MONERO_Wallet_store(void* wallet_ptr, const char* path) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->store(std::string(path)); + DEBUG_END() +} +const char* MONERO_Wallet_filename(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->filename(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +const char* MONERO_Wallet_keysFilename(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->keysFilename(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +// virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false, const std::string &proxy_address = "") = 0; +bool MONERO_Wallet_init(void* wallet_ptr, const char* daemon_address, uint64_t upper_transaction_size_limit, const char* daemon_username, const char* daemon_password, bool use_ssl, bool lightWallet, const char* proxy_address) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->init(std::string(daemon_address), upper_transaction_size_limit, std::string(daemon_username), std::string(daemon_password), use_ssl, lightWallet, std::string(proxy_address)); + DEBUG_END() +} +bool MONERO_Wallet_createWatchOnly(void* wallet_ptr, const char* path, const char* password, const char* language) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->createWatchOnly(std::string(path), std::string(password), std::string(language)); + DEBUG_END() +} + +void MONERO_Wallet_setRefreshFromBlockHeight(void* wallet_ptr, uint64_t refresh_from_block_height) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setRefreshFromBlockHeight(refresh_from_block_height); + DEBUG_END() +} + +uint64_t MONERO_Wallet_getRefreshFromBlockHeight(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getRefreshFromBlockHeight(); + DEBUG_END() +} + +void MONERO_Wallet_setRecoveringFromSeed(void* wallet_ptr, bool recoveringFromSeed) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setRecoveringFromSeed(recoveringFromSeed); + DEBUG_END() +} +void MONERO_Wallet_setRecoveringFromDevice(void* wallet_ptr, bool recoveringFromDevice) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setRecoveringFromDevice(recoveringFromDevice); + DEBUG_END() +} +void MONERO_Wallet_setSubaddressLookahead(void* wallet_ptr, uint32_t major, uint32_t minor) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setSubaddressLookahead(major, minor); + DEBUG_END() +} + +bool MONERO_Wallet_connectToDaemon(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->connectToDaemon(); + DEBUG_END() +} +int MONERO_Wallet_connected(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->connected(); + DEBUG_END() +} +void MONERO_Wallet_setTrustedDaemon(void* wallet_ptr, bool arg) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setTrustedDaemon(arg); + DEBUG_END() +} +bool MONERO_Wallet_trustedDaemon(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->trustedDaemon(); + DEBUG_END() +} +bool MONERO_Wallet_setProxy(void* wallet_ptr, const char* address) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setProxy(std::string(address)); + DEBUG_END() +} + +uint64_t MONERO_Wallet_balance(void* wallet_ptr, uint32_t accountIndex) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->balance(accountIndex); + DEBUG_END() +} + +uint64_t MONERO_Wallet_unlockedBalance(void* wallet_ptr, uint32_t accountIndex) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->unlockedBalance(accountIndex); + DEBUG_END() +} + +uint64_t MONERO_Wallet_viewOnlyBalance(void* wallet_ptr, uint32_t accountIndex) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->viewOnlyBalance(accountIndex); + DEBUG_END() +} + +// TODO +bool MONERO_Wallet_watchOnly(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->watchOnly(); + DEBUG_END() +} +bool MONERO_Wallet_isDeterministic(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->isDeterministic(); + DEBUG_END() +} +uint64_t MONERO_Wallet_blockChainHeight(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->blockChainHeight(); + DEBUG_END() +} +uint64_t MONERO_Wallet_approximateBlockChainHeight(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->approximateBlockChainHeight(); + DEBUG_END() +} +uint64_t MONERO_Wallet_estimateBlockChainHeight(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->estimateBlockChainHeight(); + DEBUG_END() +} +uint64_t MONERO_Wallet_daemonBlockChainHeight(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->daemonBlockChainHeight(); + DEBUG_END() +} + +uint64_t MONERO_Wallet_daemonBlockChainTargetHeight(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->daemonBlockChainTargetHeight(); + DEBUG_END() +} +bool MONERO_Wallet_synchronized(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->synchronized(); + DEBUG_END() +} + +const char* MONERO_Wallet_displayAmount(uint64_t amount) { + DEBUG_START() + std::string str = Monero::Wallet::displayAmount(amount); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +// static uint64_t amountFromString(const std::string &amount); +uint64_t MONERO_Wallet_amountFromString(const char* amount) { + DEBUG_START() + return Monero::Wallet::amountFromString(amount); + DEBUG_END() +} +// static uint64_t amountFromDouble(double amount); +uint64_t MONERO_Wallet_amountFromDouble(double amount) { + DEBUG_START() + return Monero::Wallet::amountFromDouble(amount); + DEBUG_END() +} +// static std::string genPaymentId(); +const char* MONERO_Wallet_genPaymentId() { + DEBUG_START() + std::string str = Monero::Wallet::genPaymentId(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// static bool paymentIdValid(const std::string &paiment_id); +bool MONERO_Wallet_paymentIdValid(const char* paiment_id) { + DEBUG_START() + return Monero::Wallet::paymentIdValid(std::string(paiment_id)); + DEBUG_END() +} +bool MONERO_Wallet_addressValid(const char* str, int nettype) { + DEBUG_START() + // Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return Monero::Wallet::addressValid(std::string(str), nettype); + DEBUG_END() +} + +bool MONERO_Wallet_keyValid(const char* secret_key_string, const char* address_string, bool isViewKey, int nettype) { + DEBUG_START() + std::string error; + return Monero::Wallet::keyValid(std::string(secret_key_string), std::string(address_string), isViewKey, nettype, error); + DEBUG_END() +} +const char* MONERO_Wallet_keyValid_error(const char* secret_key_string, const char* address_string, bool isViewKey, int nettype) { + DEBUG_START() + std::string str; + Monero::Wallet::keyValid(std::string(secret_key_string), std::string(address_string), isViewKey, nettype, str); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() + +} +const char* MONERO_Wallet_paymentIdFromAddress(const char* strarg, int nettype) { + DEBUG_START() + std::string str = Monero::Wallet::paymentIdFromAddress(std::string(strarg), nettype); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +uint64_t MONERO_Wallet_maximumAllowedAmount() { + DEBUG_START() + return Monero::Wallet::maximumAllowedAmount(); + DEBUG_END() +} + +void MONERO_Wallet_init3(void* wallet_ptr, const char* argv0, const char* default_log_base_name, const char* log_path, bool console) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->init(argv0, default_log_base_name, log_path, console); + DEBUG_END() +} +const char* MONERO_Wallet_getPolyseed(void* wallet_ptr, const char* passphrase) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string seed = ""; + std::string _passphrase = std::string(passphrase); + wallet->getPolyseed(seed, _passphrase); + std::string str = seed; + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// static bool createPolyseed(std::string &seed_words, std::string &err, const std::string &language = "English"); +const char* MONERO_Wallet_createPolyseed(const char* language) { + DEBUG_START() + std::string seed_words = ""; + std::string err; + Monero::Wallet::createPolyseed(seed_words, err, std::string(language)); + std::cout << "MONERO_Wallet_createPolyseed(language: " << language << "):" << std::endl; + std::cout << " err: " << err << std::endl; + std::string str = seed_words; + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +void MONERO_Wallet_startRefresh(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->startRefresh(); + DEBUG_END() +} +void MONERO_Wallet_pauseRefresh(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->pauseRefresh(); + DEBUG_END() +} +bool MONERO_Wallet_refresh(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->refresh(); + DEBUG_END() +} +void MONERO_Wallet_refreshAsync(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->refreshAsync(); + DEBUG_END() +} +bool MONERO_Wallet_rescanBlockchain(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->rescanBlockchain(); + DEBUG_END() +} +void MONERO_Wallet_rescanBlockchainAsync(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->rescanBlockchainAsync(); + DEBUG_END() +} +void MONERO_Wallet_setAutoRefreshInterval(void* wallet_ptr, int millis) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setAutoRefreshInterval(millis); + DEBUG_END() +} +int MONERO_Wallet_autoRefreshInterval(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->autoRefreshInterval(); + DEBUG_END() +} +void MONERO_Wallet_addSubaddressAccount(void* wallet_ptr, const char* label) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->addSubaddressAccount(std::string(label)); + DEBUG_END() +} +size_t MONERO_Wallet_numSubaddressAccounts(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->numSubaddressAccounts(); + DEBUG_END() +} +size_t MONERO_Wallet_numSubaddresses(void* wallet_ptr, uint32_t accountIndex) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->numSubaddresses(accountIndex); + DEBUG_END() +} +void MONERO_Wallet_addSubaddress(void* wallet_ptr, uint32_t accountIndex, const char* label) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->addSubaddress(accountIndex, std::string(label)); + DEBUG_END() +} +const char* MONERO_Wallet_getSubaddressLabel(void* wallet_ptr, uint32_t accountIndex, uint32_t addressIndex) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->getSubaddressLabel(accountIndex, addressIndex); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +void MONERO_Wallet_setSubaddressLabel(void* wallet_ptr, uint32_t accountIndex, uint32_t addressIndex, const char* label) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setSubaddressLabel(accountIndex, addressIndex, std::string(label)); + DEBUG_END() +} + +void* MONERO_Wallet_multisig(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + Monero::MultisigState *mstate_ptr = new Monero::MultisigState(wallet->multisig()); + return reinterpret_cast(mstate_ptr); + DEBUG_END() +} + +const char* MONERO_Wallet_getMultisigInfo(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->getMultisigInfo(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_makeMultisig(void* wallet_ptr, const char* info, const char* info_separator, uint32_t threshold) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->makeMultisig(splitStringVector(std::string(info), std::string(info_separator)), threshold); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_exchangeMultisigKeys(void* wallet_ptr, const char* info, const char* info_separator, bool force_update_use_with_caution) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->exchangeMultisigKeys(splitStringVector(std::string(info), std::string(info_separator)), force_update_use_with_caution); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_exportMultisigImages(void* wallet_ptr, const char* separator) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str; + wallet->exportMultisigImages(str); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +size_t MONERO_Wallet_importMultisigImages(void* wallet_ptr, const char* info, const char* info_separator) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->importMultisigImages(splitStringVector(std::string(info), std::string(info_separator))); + DEBUG_END() +} + +size_t MONERO_Wallet_hasMultisigPartialKeyImages(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->hasMultisigPartialKeyImages(); + DEBUG_END() +} + +void* MONERO_Wallet_restoreMultisigTransaction(void* wallet_ptr, const char* signData) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return reinterpret_cast(wallet->restoreMultisigTransaction(std::string(signData))); + DEBUG_END() +} + + +Monero::PendingTransaction::Priority PendingTransaction_Priority_fromInt(int value) { + switch(value) { + case 0: return Monero::PendingTransaction::Priority::Priority_Default; + case 1: return Monero::PendingTransaction::Priority::Priority_Low; + case 2: return Monero::PendingTransaction::Priority::Priority_Medium; + case 3: return Monero::PendingTransaction::Priority::Priority_High; + default: return Monero::PendingTransaction::Priority::Priority_Default; + } +} + +void* MONERO_Wallet_createTransactionMultDest(void* wallet_ptr, const char* dst_addr_list, const char* dst_addr_list_separator, const char* payment_id, + bool amount_sweep_all, const char* amount_list, const char* amount_list_separator, uint32_t mixin_count, + int pendingTransactionPriority, + uint32_t subaddr_account, + const char* preferredInputs, const char* preferredInputs_separator) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::vector dst_addr = splitStringVector(std::string(dst_addr_list), std::string(dst_addr_list_separator)); + + Monero::optional> optAmount; + if (!amount_sweep_all) { + optAmount = splitStringUint(std::string(amount_list), std::string(amount_list_separator));; + } + std::set subaddr_indices = {}; + std::set preferred_inputs = splitString(std::string(preferredInputs), std::string(preferredInputs_separator)); + + return wallet->createTransactionMultDest( + dst_addr, std::string(payment_id), + optAmount, mixin_count, + PendingTransaction_Priority_fromInt(pendingTransactionPriority), + subaddr_account, + subaddr_indices, + preferred_inputs + ); + DEBUG_END() +} + +void* MONERO_Wallet_createTransaction(void* wallet_ptr, const char* dst_addr, const char* payment_id, + uint64_t amount, uint32_t mixin_count, + int pendingTransactionPriority, + uint32_t subaddr_account, + const char* preferredInputs, const char* separator) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + Monero::optional optAmount; + if (amount != 0) { + optAmount = amount; + } + std::set subaddr_indices = {}; + std::set preferred_inputs = splitString(std::string(preferredInputs), std::string(separator)); + return wallet->createTransaction(std::string(dst_addr), std::string(payment_id), + optAmount, mixin_count, + PendingTransaction_Priority_fromInt(pendingTransactionPriority), + subaddr_account, subaddr_indices, preferred_inputs); + DEBUG_END() +} + +void* MONERO_Wallet_loadUnsignedTx(void* wallet_ptr, const char* fileName) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->loadUnsignedTx(std::string(fileName)); + DEBUG_END() +} + +void* MONERO_Wallet_loadUnsignedTxUR(void* wallet_ptr, const char* input) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->loadUnsignedTxUR(std::string(input)); + DEBUG_END() +} +bool MONERO_Wallet_submitTransaction(void* wallet_ptr, const char* fileName) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->submitTransaction(std::string(fileName)); + DEBUG_END() +} +bool MONERO_Wallet_submitTransactionUR(void* wallet_ptr, const char* input) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->submitTransactionUR(std::string(input)); + DEBUG_END() +} +bool MONERO_Wallet_hasUnknownKeyImages(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->hasUnknownKeyImages(); + DEBUG_END() +} +bool MONERO_Wallet_exportKeyImages(void* wallet_ptr, const char* filename, bool all) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->exportKeyImages(std::string(filename), all); + DEBUG_END() +} + +const char* MONERO_Wallet_exportKeyImagesUR(void* wallet_ptr, size_t max_fragment_length, bool all) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->exportKeyImagesUR(max_fragment_length, all); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +bool MONERO_Wallet_importKeyImages(void* wallet_ptr, const char* filename) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->importKeyImages(std::string(filename)); + DEBUG_END() +} +bool MONERO_Wallet_importKeyImagesUR(void* wallet_ptr, const char* input) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->importKeyImagesUR(std::string(input)); + DEBUG_END() +} +bool MONERO_Wallet_exportOutputs(void* wallet_ptr, const char* filename, bool all) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->exportOutputs(std::string(filename), all); + DEBUG_END() +} +const char* MONERO_Wallet_exportOutputsUR(void* wallet_ptr, size_t max_fragment_length, bool all) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->exportOutputsUR(max_fragment_length, all); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +bool MONERO_Wallet_importOutputs(void* wallet_ptr, const char* filename) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->importOutputs(std::string(filename)); + DEBUG_END() +} +bool MONERO_Wallet_importOutputsUR(void* wallet_ptr, const char* input) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->importOutputsUR(std::string(input)); + DEBUG_END() +} +// virtual bool setupBackgroundSync(const BackgroundSyncType background_sync_type, const std::string &wallet_password, const optional &background_cache_password) = 0; +bool MONERO_Wallet_setupBackgroundSync(void* wallet_ptr, int background_sync_type, const char* wallet_password, const char* background_cache_password) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setupBackgroundSync(Monero::Wallet::BackgroundSyncType::BackgroundSync_CustomPassword, std::string(wallet_password), std::string(background_cache_password)); + DEBUG_END() +} +// virtual BackgroundSyncType getBackgroundSyncType() const = 0; +int MONERO_Wallet_getBackgroundSyncType(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getBackgroundSyncType(); + DEBUG_END() +} +// virtual bool startBackgroundSync() = 0; +bool MONERO_Wallet_startBackgroundSync(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->startBackgroundSync(); + DEBUG_END() +} +// virtual bool stopBackgroundSync(const std::string &wallet_password) = 0; +bool MONERO_Wallet_stopBackgroundSync(void* wallet_ptr, const char* wallet_password) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->stopBackgroundSync(std::string(wallet_password)); + DEBUG_END() +} +// virtual bool isBackgroundSyncing() const = 0; +bool MONERO_Wallet_isBackgroundSyncing(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->hasUnknownKeyImages(); + DEBUG_END() +} +// virtual bool isBackgroundWallet() const = 0; +bool MONERO_Wallet_isBackgroundWallet(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->isBackgroundWallet(); + DEBUG_END() +} +void* MONERO_Wallet_history(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->history(); + DEBUG_END() +} +void* MONERO_Wallet_addressBook(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->addressBook(); + DEBUG_END() +} +// virtual Coins * coins() = 0; +void* MONERO_Wallet_coins(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->coins(); + DEBUG_END() +} +// virtual Subaddress * subaddress() = 0; +void* MONERO_Wallet_subaddress(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->subaddress(); + DEBUG_END() +} +// virtual SubaddressAccount * subaddressAccount() = 0; +void* MONERO_Wallet_subaddressAccount(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->subaddressAccount(); + DEBUG_END() +} +// virtual uint32_t defaultMixin() const = 0; +uint32_t MONERO_Wallet_defaultMixin(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->defaultMixin(); + DEBUG_END() +} +// virtual void setDefaultMixin(uint32_t arg) = 0; +void MONERO_Wallet_setDefaultMixin(void* wallet_ptr, uint32_t arg) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setDefaultMixin(arg); + DEBUG_END() +} +// virtual bool setCacheAttribute(const std::string &key, const std::string &val) = 0; +bool MONERO_Wallet_setCacheAttribute(void* wallet_ptr, const char* key, const char* val) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setCacheAttribute(std::string(key), std::string(val)); + DEBUG_END() +} +// virtual std::string getCacheAttribute(const std::string &key) const = 0; +const char* MONERO_Wallet_getCacheAttribute(void* wallet_ptr, const char* key) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->getCacheAttribute(std::string(key)); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// virtual bool setUserNote(const std::string &txid, const std::string ¬e) = 0; +bool MONERO_Wallet_setUserNote(void* wallet_ptr, const char* txid, const char* note) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setUserNote(std::string(txid), std::string(note)); + DEBUG_END() +} +// virtual std::string getUserNote(const std::string &txid) const = 0; +const char* MONERO_Wallet_getUserNote(void* wallet_ptr, const char* txid) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->getUserNote(std::string(txid)); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_getTxKey(void* wallet_ptr, const char* txid) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->getTxKey(std::string(txid)); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +const char* MONERO_Wallet_signMessage(void* wallet_ptr, const char* message, const char* address) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = wallet->signMessage(std::string(message), std::string(address)); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +bool MONERO_Wallet_verifySignedMessage(void* wallet_ptr, const char* message, const char* address, const char* signature) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + bool v = wallet->verifySignedMessage(std::string(message), std::string(address), std::string(signature)); + return v; + DEBUG_END() +} + +bool MONERO_Wallet_rescanSpent(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->rescanSpent(); + DEBUG_END() +} + +void MONERO_Wallet_setOffline(void* wallet_ptr, bool offline) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setOffline(offline); + DEBUG_END() +} +// virtual bool isOffline() const = 0; +bool MONERO_Wallet_isOffline(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->isOffline(); + DEBUG_END() +} + +void MONERO_Wallet_segregatePreForkOutputs(void* wallet_ptr, bool segregate) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->segregatePreForkOutputs(segregate); + DEBUG_END() +} +// virtual void segregationHeight(uint64_t height) = 0; +void MONERO_Wallet_segregationHeight(void* wallet_ptr, uint64_t height) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->segregationHeight(height); + DEBUG_END() +} +// virtual void keyReuseMitigation2(bool mitigation) = 0; +void MONERO_Wallet_keyReuseMitigation2(void* wallet_ptr, bool mitigation) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->keyReuseMitigation2(mitigation); + DEBUG_END() +} +// virtual bool lightWalletLogin(bool &isNewWallet) const = 0; +// virtual bool lightWalletImportWalletRequest(std::string &payment_id, uint64_t &fee, bool &new_request, bool &request_fulfilled, std::string &payment_address, std::string &status) = 0; +// virtual bool lockKeysFile() = 0; +bool MONERO_Wallet_lockKeysFile(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->lockKeysFile(); + DEBUG_END() +} +// virtual bool unlockKeysFile() = 0; +bool MONERO_Wallet_unlockKeysFile(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->unlockKeysFile(); + DEBUG_END() +} +// virtual bool isKeysFileLocked() = 0; +bool MONERO_Wallet_isKeysFileLocked(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->isKeysFileLocked(); + DEBUG_END() +} +// virtual Device getDeviceType() const = 0; +int MONERO_Wallet_getDeviceType(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getDeviceType(); + DEBUG_END() +} +// virtual uint64_t coldKeyImageSync(uint64_t &spent, uint64_t &unspent) = 0; +uint64_t MONERO_Wallet_coldKeyImageSync(void* wallet_ptr, uint64_t spent, uint64_t unspent) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->coldKeyImageSync(spent, unspent); + DEBUG_END() +} +// virtual void deviceShowAddress(uint32_t accountIndex, uint32_t addressIndex, const std::string &paymentId) = 0; +const char* MONERO_Wallet_deviceShowAddress(void* wallet_ptr, uint32_t accountIndex, uint32_t addressIndex) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + std::string str = ""; + wallet->deviceShowAddress(accountIndex, addressIndex, str); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} +// virtual bool reconnectDevice() = 0; +bool MONERO_Wallet_reconnectDevice(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->reconnectDevice(); + DEBUG_END() +}; + +uint64_t MONERO_Wallet_getBytesReceived(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getBytesReceived(); + DEBUG_END() +} +uint64_t MONERO_Wallet_getBytesSent(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getBytesSent(); + DEBUG_END() +} + +bool MONERO_Wallet_getStateIsConnected(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getStateIsConnected(); + DEBUG_END() +} + +unsigned char* MONERO_Wallet_getSendToDevice(void* wallet_ptr) { + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getSendToDevice(); +} + +size_t MONERO_Wallet_getSendToDeviceLength(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getSendToDeviceLength(); + DEBUG_END() +} + +unsigned char* MONERO_Wallet_getReceivedFromDevice(void* wallet_ptr) { + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getReceivedFromDevice(); +} + +size_t MONERO_Wallet_getReceivedFromDeviceLength(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getReceivedFromDeviceLength(); + DEBUG_END() +} + +bool MONERO_Wallet_getWaitsForDeviceSend(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getWaitsForDeviceSend(); + DEBUG_END() +} + +bool MONERO_Wallet_getWaitsForDeviceReceive(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->getWaitsForDeviceReceive(); + DEBUG_END() +} + +void MONERO_Wallet_setDeviceReceivedData(void* wallet_ptr, unsigned char* data, size_t len) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setDeviceReceivedData(data, len); + DEBUG_END() +} + +void MONERO_Wallet_setDeviceSendData(void* wallet_ptr, unsigned char* data, size_t len) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wallet->setDeviceSendData(data, len); + DEBUG_END() +} + +void* MONERO_WalletManager_createWallet(void* wm_ptr, const char* path, const char* password, const char* language, int networkType) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + Monero::Wallet *wallet = wm->createWallet( + std::string(path), + std::string(password), + std::string(language), + static_cast(networkType)); + return reinterpret_cast(wallet); + DEBUG_END() +} + +void* MONERO_WalletManager_openWallet(void* wm_ptr, const char* path, const char* password, int networkType) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + Monero::Wallet *wallet = wm->openWallet( + std::string(path), + std::string(password), + static_cast(networkType)); + return reinterpret_cast(wallet); + DEBUG_END() +} +void* MONERO_WalletManager_recoveryWallet(void* wm_ptr, const char* path, const char* password, const char* mnemonic, int networkType, uint64_t restoreHeight, uint64_t kdfRounds, const char* seedOffset) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + // (const std::string &path, const std::string &password, const std::string &mnemonic, + // NetworkType nettype = MAINNET, uint64_t restoreHeight = 0, uint64_t kdf_rounds = 1, + // const std::string &seed_offset = {}) + Monero::Wallet *wallet = wm->recoveryWallet( + std::string(path), + std::string(password), + std::string(mnemonic), + static_cast(networkType), + restoreHeight, + kdfRounds, + std::string(seedOffset)); + return reinterpret_cast(wallet); + DEBUG_END() +} +// virtual Wallet * createWalletFromKeys(const std::string &path, +// const std::string &password, +// const std::string &language, +// NetworkType nettype, +// uint64_t restoreHeight, +// const std::string &addressString, +// const std::string &viewKeyString, +// const std::string &spendKeyString = "", +// uint64_t kdf_rounds = 1) = 0; +void* MONERO_WalletManager_createWalletFromKeys(void* wm_ptr, const char* path, const char* password, const char* language, int nettype, uint64_t restoreHeight, const char* addressString, const char* viewKeyString, const char* spendKeyString, uint64_t kdf_rounds) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + Monero::Wallet *wallet = wm->createWalletFromKeys( + std::string(path), + std::string(password), + std::string(language), + static_cast(nettype), + restoreHeight, + std::string(addressString), + std::string(viewKeyString), + std::string(spendKeyString)); + return reinterpret_cast(wallet); + DEBUG_END() +} + +void* MONERO_WalletManager_createWalletFromDevice(void* wm_ptr, const char* path, const char* password, int nettype, const char* deviceName, uint64_t restoreHeight, const char* subaddressLookahead, const char* viewKeyString, const char* spendKeyString, uint64_t kdf_rounds) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + Monero::Wallet *wallet = wm->createWalletFromDevice(std::string(path), + std::string(password), + static_cast(nettype), + std::string(deviceName), + restoreHeight, + std::string(subaddressLookahead), + kdf_rounds); + return reinterpret_cast(wallet); + DEBUG_END() +} + +void* MONERO_WalletManager_createDeterministicWalletFromSpendKey(void* wm_ptr, const char* path, const char* password, + const char* language, int nettype, uint64_t restoreHeight, + const char* spendKeyString, uint64_t kdf_rounds) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + Monero::Wallet *wallet = wm->createDeterministicWalletFromSpendKey( + std::string(path), + std::string(password), + std::string(language), + static_cast(nettype), + restoreHeight, + std::string(spendKeyString), + kdf_rounds + ); + return reinterpret_cast(wallet); + DEBUG_END() +} + +void* MONERO_WalletManager_createWalletFromPolyseed(void* wm_ptr, const char* path, const char* password, + int nettype, const char* mnemonic, const char* passphrase, + bool newWallet, uint64_t restore_height, uint64_t kdf_rounds) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->createWalletFromPolyseed(std::string(path), + std::string(password), + static_cast(nettype), + std::string(mnemonic), + std::string(passphrase), + newWallet, + restore_height, + kdf_rounds); + DEBUG_END() +} + + +bool MONERO_WalletManager_closeWallet(void* wm_ptr, void* wallet_ptr, bool store) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return wm->closeWallet(wallet, store); + DEBUG_END() +} + +bool MONERO_WalletManager_walletExists(void* wm_ptr, const char* path) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->walletExists(std::string(path)); + DEBUG_END() +} + +// virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const = 0; +bool MONERO_WalletManager_verifyWalletPassword(void* wm_ptr, const char* keys_file_name, const char* password, bool no_spend_key, uint64_t kdf_rounds) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->verifyWalletPassword(std::string(keys_file_name), std::string(password), no_spend_key, kdf_rounds); + DEBUG_END() +} + +// virtual bool queryWalletDevice(Wallet::Device& device_type, const std::string &keys_file_name, const std::string &password, uint64_t kdf_rounds = 1) const = 0; +int MONERO_WalletManager_queryWalletDevice(void* wm_ptr, const char* keys_file_name, const char* password, uint64_t kdf_rounds) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + Monero::Wallet::Device device_type; + wm->queryWalletDevice(device_type, std::string(keys_file_name), std::string(password), kdf_rounds); + return device_type; + DEBUG_END() +} + +// virtual std::vector findWallets(const std::string &path) = 0; +const char* MONERO_WalletManager_findWallets(void* wm_ptr, const char* path, const char* separator) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return vectorToString(wm->findWallets(std::string(path)), std::string(separator)); + DEBUG_END() +} + + +const char* MONERO_WalletManager_errorString(void* wm_ptr) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + std::string str = wm->errorString(); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +void MONERO_WalletManager_setDaemonAddress(void* wm_ptr, const char* address) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->setDaemonAddress(std::string(address)); + DEBUG_END() +} + +bool MONERO_WalletManager_setProxy(void* wm_ptr, const char* address) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->setProxy(std::string(address)); + DEBUG_END() +} + + +// virtual bool connected(uint32_t *version = NULL) = 0; +// virtual uint64_t blockchainHeight() = 0; +uint64_t MONERO_WalletManager_blockchainHeight(void* wm_ptr) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->blockchainHeight(); + DEBUG_END() +} +// virtual uint64_t blockchainTargetHeight() = 0; +uint64_t MONERO_WalletManager_blockchainTargetHeight(void* wm_ptr) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->blockchainTargetHeight(); + DEBUG_END() +} +// virtual uint64_t networkDifficulty() = 0; +uint64_t MONERO_WalletManager_networkDifficulty(void* wm_ptr) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->networkDifficulty(); + DEBUG_END() +} +// virtual double miningHashRate() = 0; +double MONERO_WalletManager_miningHashRate(void* wm_ptr) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->miningHashRate(); + DEBUG_END() +} +// virtual uint64_t blockTarget() = 0; +uint64_t MONERO_WalletManager_blockTarget(void* wm_ptr) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->blockTarget(); + DEBUG_END() +} +// virtual bool isMining() = 0; +bool MONERO_WalletManager_isMining(void* wm_ptr) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->isMining(); + DEBUG_END() +} +// virtual bool startMining(const std::string &address, uint32_t threads = 1, bool background_mining = false, bool ignore_battery = true) = 0; +bool MONERO_WalletManager_startMining(void* wm_ptr, const char* address, uint32_t threads, bool backgroundMining, bool ignoreBattery) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->startMining(std::string(address), threads, backgroundMining, ignoreBattery); + DEBUG_END() +} +// virtual bool stopMining() = 0; +bool MONERO_WalletManager_stopMining(void* wm_ptr, const char* address) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + return wm->stopMining(); + DEBUG_END() +} +// virtual std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const = 0; +const char* MONERO_WalletManager_resolveOpenAlias(void* wm_ptr, const char* address, bool dnssec_valid) { + DEBUG_START() + Monero::WalletManager *wm = reinterpret_cast(wm_ptr); + std::string str = wm->resolveOpenAlias(std::string(address), dnssec_valid); + const std::string::size_type size = str.size(); + char *buffer = new char[size + 1]; //we need extra char for NUL + memcpy(buffer, str.c_str(), size + 1); + return buffer; + DEBUG_END() +} + +// WalletManagerFactory + +void* MONERO_WalletManagerFactory_getWalletManager() { + DEBUG_START() + Monero::WalletManager *wm = Monero::WalletManagerFactory::getWalletManager(); + return reinterpret_cast(wm); + DEBUG_END() +} + +void MONERO_WalletManagerFactory_setLogLevel(int level) { + DEBUG_START() + return Monero::WalletManagerFactory::setLogLevel(level); + DEBUG_END() +} + +void MONERO_WalletManagerFactory_setLogCategories(const char* categories) { + DEBUG_START() + return Monero::WalletManagerFactory::setLogCategories(std::string(categories)); + DEBUG_END() +} + +// DEBUG functions + +// As it turns out we need a bit more functions to make sure that the library is working. +// 0) void +// 1) bool +// 2) int +// 3) uint64_t +// 4) void* +// 5) const char* + +void MONERO_DEBUG_test0() { + return; +} + +bool MONERO_DEBUG_test1(bool x) { + return x; +} + +int MONERO_DEBUG_test2(int x) { + return x; +} + +uint64_t MONERO_DEBUG_test3(uint64_t x) { + return x; +} + +void* MONERO_DEBUG_test4(uint64_t x) { + int *y = new int(x); + return reinterpret_cast(y); +} + +const char* MONERO_DEBUG_test5() { + const char *text = "This is a const char* text"; + return text; +} + +const char* MONERO_DEBUG_test5_std() { + std::string text("This is a std::string text"); + const char *text2 = "This is a text"; + return text2; +} + +bool MONERO_DEBUG_isPointerNull(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + return (wallet != NULL); + DEBUG_END() +} + +// cake wallet world +// TODO(mrcyjanek): https://api.dart.dev/stable/3.3.3/dart-ffi/Pointer/fromFunction.html +// callback to dart should be possible..? I mean why not? But I need to +// wait for other implementation (Go preferably) to see if this approach +// will work as expected. +struct MONERO_cw_WalletListener; +struct MONERO_cw_WalletListener : Monero::WalletListener +{ + uint64_t m_height; + bool m_need_to_refresh; + bool m_new_transaction; + + MONERO_cw_WalletListener() + { + m_height = 0; + m_need_to_refresh = false; + m_new_transaction = false; + } + + void moneySpent(const std::string &txId, uint64_t amount) + { + m_new_transaction = true; + } + + void moneyReceived(const std::string &txId, uint64_t amount) + { + m_new_transaction = true; + } + + void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) + { + m_new_transaction = true; + } + + void newBlock(uint64_t height) + { + m_height = height; + } + + void updated() + { + m_new_transaction = true; + } + + void refreshed() + { + m_need_to_refresh = true; + } + + + void cw_resetNeedToRefresh() + { + m_need_to_refresh = false; + } + + bool cw_isNeedToRefresh() + { + return m_need_to_refresh; + } + + bool cw_isNewTransactionExist() + { + return m_new_transaction; + } + + void cw_resetIsNewTransactionExist() + { + m_new_transaction = false; + } + + uint64_t cw_height() + { + return m_height; + } +}; + +void* MONERO_cw_getWalletListener(void* wallet_ptr) { + DEBUG_START() + Monero::Wallet *wallet = reinterpret_cast(wallet_ptr); + MONERO_cw_WalletListener *listener = new MONERO_cw_WalletListener(); + wallet->setListener(listener); + return reinterpret_cast(listener); + DEBUG_END() +} + +void MONERO_cw_WalletListener_resetNeedToRefresh(void* cw_walletListener_ptr) { + DEBUG_START() + MONERO_cw_WalletListener *listener = reinterpret_cast(cw_walletListener_ptr); + listener->cw_resetNeedToRefresh(); + DEBUG_END() +} + +bool MONERO_cw_WalletListener_isNeedToRefresh(void* cw_walletListener_ptr) { + DEBUG_START() + MONERO_cw_WalletListener *listener = reinterpret_cast(cw_walletListener_ptr); + return listener->cw_isNeedToRefresh(); + DEBUG_END() +}; + +bool MONERO_cw_WalletListener_isNewTransactionExist(void* cw_walletListener_ptr) { + DEBUG_START() + MONERO_cw_WalletListener *listener = reinterpret_cast(cw_walletListener_ptr); + return listener->cw_isNeedToRefresh(); + DEBUG_END() +}; + +void MONERO_cw_WalletListener_resetIsNewTransactionExist(void* cw_walletListener_ptr) { + DEBUG_START() + MONERO_cw_WalletListener *listener = reinterpret_cast(cw_walletListener_ptr); + listener->cw_isNeedToRefresh(); + DEBUG_END() +}; + +uint64_t MONERO_cw_WalletListener_height(void* cw_walletListener_ptr) { + DEBUG_START() + MONERO_cw_WalletListener *listener = reinterpret_cast(cw_walletListener_ptr); + return listener->cw_isNeedToRefresh(); + DEBUG_END() +}; + +const char* MONERO_checksum_wallet2_api_c_h() { + return MONERO_wallet2_api_c_h_sha256; +} +const char* MONERO_checksum_wallet2_api_c_cpp() { + return MONERO_wallet2_api_c_cpp_sha256; +} +const char* MONERO_checksum_wallet2_api_c_exp() { + return MONERO_wallet2_api_c_exp_sha256; +} +// i hate windows + +void MONERO_free(void* ptr) { + free(ptr); +} + +#ifdef __cplusplus +} +#endif diff --git a/salvium_libwallet2_api_c/src/main/cpp/wallet2_api_c.h b/salvium_libwallet2_api_c/src/main/cpp/wallet2_api_c.h new file mode 100644 index 0000000..17c647c --- /dev/null +++ b/salvium_libwallet2_api_c/src/main/cpp/wallet2_api_c.h @@ -0,0 +1,1040 @@ +/* +#include + +#define LOG_TAG "[NDK]" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) +*/ +#include +#include +#include +#include +#include "monero_checksum.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef __MINGW32__ + #define ADDAPI __declspec(dllexport) +#else + #define ADDAPI __attribute__((__visibility__("default"))) +#endif + +// namespace Monero { +// enum NetworkType : uint8_t { +// MAINNET = 0, +const int NetworkType_MAINNET = 0; +// TESTNET, +const int NetworkType_TESTNET = 1; +// STAGENET +const int NetworkType_STAGENET = 2; +// }; +// namespace Utils { +// bool isAddressLocal(const std::string &hostaddr); +// void onStartup(); +// } +// template +// class optional { +// public: +// optional(): set(false) {} +// optional(const T &t): t(t), set(true) {} +// const T &operator*() const { return t; } +// T &operator*() { return t; } +// operator bool() const { return set; } +// private: +// T t; +// bool set; +// }; + +// struct PendingTransaction +// { +// enum Status { +// Status_Ok, +const int PendingTransactionStatus_Ok = 0; +// Status_Error, +const int PendingTransactionStatus_Error = 1; +// Status_Critical +const int PendingTransactionStatus_Critical = 2; +// }; +// enum Priority { +// Priority_Default = 0, +const int Priority_Default = 0; +// Priority_Low = 1, +const int Priority_Low = 1; +// Priority_Medium = 2, +const int Priority_Medium = 2; +// Priority_High = 3, +const int Priority_High = 3; +// Priority_Last +const int Priority_Last = 4; +// }; +// virtual ~PendingTransaction() = 0; +// virtual int status() const = 0; +extern ADDAPI int MONERO_PendingTransaction_status(void* pendingTx_ptr); +// virtual std::string errorString() const = 0; +extern ADDAPI const char* MONERO_PendingTransaction_errorString(void* pendingTx_ptr); +// virtual bool commit(const std::string &filename = "", bool overwrite = false) = 0; +extern ADDAPI bool MONERO_PendingTransaction_commit(void* pendingTx_ptr, const char* filename, bool overwrite); +extern ADDAPI const char* MONERO_PendingTransaction_commitUR(void* pendingTx_ptr, int max_fragment_length); +// virtual uint64_t amount() const = 0; +extern ADDAPI uint64_t MONERO_PendingTransaction_amount(void* pendingTx_ptr); +// virtual uint64_t dust() const = 0; +extern ADDAPI uint64_t MONERO_PendingTransaction_dust(void* pendingTx_ptr); +// virtual uint64_t fee() const = 0; +extern ADDAPI uint64_t MONERO_PendingTransaction_fee(void* pendingTx_ptr); +// virtual std::vector txid() const = 0; +extern ADDAPI const char* MONERO_PendingTransaction_txid(void* pendingTx_ptr, const char* separator); +// virtual uint64_t txCount() const = 0; +extern ADDAPI uint64_t MONERO_PendingTransaction_txCount(void* pendingTx_ptr); +// virtual std::vector subaddrAccount() const = 0; +extern ADDAPI const char* MONERO_PendingTransaction_subaddrAccount(void* pendingTx_ptr, const char* separator); +// virtual std::vector> subaddrIndices() const = 0; +extern ADDAPI const char* MONERO_PendingTransaction_subaddrIndices(void* pendingTx_ptr, const char* separator); +// virtual std::string multisigSignData() = 0; +extern ADDAPI const char* MONERO_PendingTransaction_multisigSignData(void* pendingTx_ptr); +// virtual void signMultisigTx() = 0; +extern ADDAPI void MONERO_PendingTransaction_signMultisigTx(void* pendingTx_ptr); +// virtual std::vector signersKeys() const = 0; +extern ADDAPI const char* MONERO_PendingTransaction_signersKeys(void* pendingTx_ptr, const char* separator); +// virtual std::vector hex() const = 0; +extern ADDAPI const char* MONERO_PendingTransaction_hex(void* pendingTx_ptr, const char* separator); +// virtual std::vector txKey() const = 0; +// extern ADDAPI const char* MONERO_PendingTransaction_txHex(void* pendingTx_ptr, const char* separator); +// }; + +// struct UnsignedTransaction +// { +// enum Status { +// Status_Ok, +const int UnsignedTransactionStatus_Ok = 0; +// Status_Error, +const int UnsignedTransactionStatus_Error = 1; +// Status_Critical +const int UnsignedTransactionStatus_Critical = 2; +// }; +// virtual ~UnsignedTransaction() = 0; +// virtual int status() const = 0; +extern ADDAPI int MONERO_UnsignedTransaction_status(void* unsignedTx_ptr); +// virtual std::string errorString() const = 0; +extern ADDAPI const char* MONERO_UnsignedTransaction_errorString(void* unsignedTx_ptr); +// virtual std::vector amount() const = 0; +extern ADDAPI const char* MONERO_UnsignedTransaction_amount(void* unsignedTx_ptr, const char* separator); +// virtual std::vector fee() const = 0; +extern ADDAPI const char* MONERO_UnsignedTransaction_fee(void* unsignedTx_ptr, const char* separator); +// virtual std::vector mixin() const = 0; +extern ADDAPI const char* MONERO_UnsignedTransaction_mixin(void* unsignedTx_ptr, const char* separator); +// virtual std::string confirmationMessage() const = 0; +extern ADDAPI const char* MONERO_UnsignedTransaction_confirmationMessage(void* unsignedTx_ptr); +// virtual std::vector paymentId() const = 0; +extern ADDAPI const char* MONERO_UnsignedTransaction_paymentId(void* unsignedTx_ptr, const char* separator); +// virtual std::vector recipientAddress() const = 0; +extern ADDAPI const char* MONERO_UnsignedTransaction_recipientAddress(void* unsignedTx_ptr, const char* separator); +// virtual uint64_t minMixinCount() const = 0; +extern ADDAPI uint64_t MONERO_UnsignedTransaction_minMixinCount(void* unsignedTx_ptr); +// virtual uint64_t txCount() const = 0; +extern ADDAPI uint64_t MONERO_UnsignedTransaction_txCount(void* unsignedTx_ptr); +// virtual bool sign(const std::string &signedFileName) = 0; +extern ADDAPI bool MONERO_UnsignedTransaction_sign(void* unsignedTx_ptr, const char* signedFileName); +extern ADDAPI const char* MONERO_UnsignedTransaction_signUR(void* unsignedTx_ptr, int max_fragment_length); +// }; +// struct TransactionInfo +// { +// enum Direction { +// Direction_In, +const int TransactionInfoDirection_In = 0; +// Direction_Out +const int TransactionInfoDirection_Out = 1; +// }; +// struct Transfer { +// Transfer(uint64_t _amount, const std::string &address); +// const uint64_t amount; +// const std::string address; +// }; +// virtual ~TransactionInfo() = 0; +// virtual int direction() const = 0; +extern ADDAPI int MONERO_TransactionInfo_direction(void* txInfo_ptr); +// virtual bool isPending() const = 0; +extern ADDAPI bool MONERO_TransactionInfo_isPending(void* txInfo_ptr); +// virtual bool isFailed() const = 0; +extern ADDAPI bool MONERO_TransactionInfo_isFailed(void* txInfo_ptr); +// virtual bool isCoinbase() const = 0; +extern ADDAPI bool MONERO_TransactionInfo_isCoinbase(void* txInfo_ptr); +// virtual uint64_t amount() const = 0; +extern ADDAPI uint64_t MONERO_TransactionInfo_amount(void* txInfo_ptr); +// virtual uint64_t fee() const = 0; +extern ADDAPI uint64_t MONERO_TransactionInfo_fee(void* txInfo_ptr); +// virtual uint64_t blockHeight() const = 0; +extern ADDAPI uint64_t MONERO_TransactionInfo_blockHeight(void* txInfo_ptr); +// virtual std::string description() const = 0; +extern ADDAPI const char* MONERO_TransactionInfo_description(void* txInfo_ptr); +// virtual std::set subaddrIndex() const = 0; +extern ADDAPI const char* MONERO_TransactionInfo_subaddrIndex(void* txInfo_ptr, const char* separator); +// virtual uint32_t subaddrAccount() const = 0; +extern ADDAPI uint32_t MONERO_TransactionInfo_subaddrAccount(void* txInfo_ptr); +// virtual std::string label() const = 0; +extern ADDAPI const char* MONERO_TransactionInfo_label(void* txInfo_ptr); +// virtual uint64_t confirmations() const = 0; +extern ADDAPI uint64_t MONERO_TransactionInfo_confirmations(void* txInfo_ptr); +// virtual uint64_t unlockTime() const = 0; +extern ADDAPI uint64_t MONERO_TransactionInfo_unlockTime(void* txInfo_ptr); +// virtual std::string hash() const = 0; +extern ADDAPI const char* MONERO_TransactionInfo_hash(void* txInfo_ptr); +// virtual std::time_t timestamp() const = 0; +extern ADDAPI uint64_t MONERO_TransactionInfo_timestamp(void* txInfo_ptr); +// virtual std::string paymentId() const = 0; +extern ADDAPI const char* MONERO_TransactionInfo_paymentId(void* txInfo_ptr); +// virtual const std::vector & transfers() const = 0; +extern ADDAPI int MONERO_TransactionInfo_transfers_count(void* txInfo_ptr); +extern ADDAPI uint64_t MONERO_TransactionInfo_transfers_amount(void* txInfo_ptr, int index); +extern ADDAPI const char* MONERO_TransactionInfo_transfers_address(void* txInfo_ptr, int address); +// }; +// struct TransactionHistory +// { +// virtual ~TransactionHistory() = 0; +// virtual int count() const = 0; +extern ADDAPI int MONERO_TransactionHistory_count(void* txHistory_ptr); +// virtual TransactionInfo * transaction(int index) const = 0; +extern ADDAPI void* MONERO_TransactionHistory_transaction(void* txHistory_ptr, int index); +// virtual TransactionInfo * transaction(const std::string &id) const = 0; +extern ADDAPI void* MONERO_TransactionHistory_transactionById(void* txHistory_ptr, const char* id); +// virtual std::vector getAll() const = 0; +// virtual void refresh() = 0; +extern ADDAPI void MONERO_TransactionHistory_refresh(void* txHistory_ptr); +// virtual void setTxNote(const std::string &txid, const std::string ¬e) = 0; +extern ADDAPI void MONERO_TransactionHistory_setTxNote(void* txHistory_ptr, const char* txid, const char* note); +// }; +// struct AddressBookRow { +// public: +// AddressBookRow(std::size_t _rowId, const std::string &_address, const std::string &_paymentId, const std::string &_description): +// m_rowId(_rowId), +// m_address(_address), +// m_paymentId(_paymentId), +// m_description(_description) {} + +// private: +// std::size_t m_rowId; +// std::string m_address; +// std::string m_paymentId; +// std::string m_description; +// public: +// std::string extra; +extern ADDAPI const char* MONERO_AddressBookRow_extra(void* addressBookRow_ptr); +// std::string getAddress() const {return m_address;} +extern ADDAPI const char* MONERO_AddressBookRow_getAddress(void* addressBookRow_ptr); +// std::string getDescription() const {return m_description;} +extern ADDAPI const char* MONERO_AddressBookRow_getDescription(void* addressBookRow_ptr); +// std::string getPaymentId() const {return m_paymentId;} +extern ADDAPI const char* MONERO_AddressBookRow_getPaymentId(void* addressBookRow_ptr); +// std::size_t getRowId() const {return m_rowId;} +extern ADDAPI size_t MONERO_AddressBookRow_getRowId(void* addressBookRow_ptr); +// }; +// struct AddressBook +// { +// enum ErrorCode { +// Status_Ok, +const int AddressBookErrorCodeStatus_Ok = 0; +// General_Error, +const int AddressBookErrorCodeGeneral_Error = 1; +// Invalid_Address, +const int AddressBookErrorCodeInvalid_Address = 2; +// Invalid_Payment_Id +const int AddressBookErrorCodeInvalidPaymentId = 3; +// }; +// virtual ~AddressBook() = 0; +// virtual std::vector getAll() const = 0; +extern ADDAPI int MONERO_AddressBook_getAll_size(void* addressBook_ptr); +extern ADDAPI void* MONERO_AddressBook_getAll_byIndex(void* addressBook_ptr, int index); +// virtual bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) = 0; +extern ADDAPI bool MONERO_AddressBook_addRow(void* addressBook_ptr, const char* dst_addr , const char* payment_id, const char* description); +// virtual bool deleteRow(std::size_t rowId) = 0; +extern ADDAPI bool MONERO_AddressBook_deleteRow(void* addressBook_ptr, size_t rowId); +// virtual bool setDescription(std::size_t index, const std::string &description) = 0; +extern ADDAPI bool MONERO_AddressBook_setDescription(void* addressBook_ptr, size_t rowId, const char* description); +// virtual void refresh() = 0; +extern ADDAPI void MONERO_AddressBook_refresh(void* addressBook_ptr); +// virtual std::string errorString() const = 0; +extern ADDAPI const char* MONERO_AddressBook_errorString(void* addressBook_ptr); +// virtual int errorCode() const = 0; +extern ADDAPI int MONERO_AddressBook_errorCode(void* addressBook_ptr); +// virtual int lookupPaymentID(const std::string &payment_id) const = 0; +extern ADDAPI int MONERO_AddressBook_lookupPaymentID(void* addressBook_ptr, const char* payment_id); +// }; +// struct CoinsInfo +// { +// virtual ~CoinsInfo() = 0; +// virtual uint64_t blockHeight() const = 0; +extern ADDAPI uint64_t MONERO_CoinsInfo_blockHeight(void* coinsInfo_ptr); +// virtual std::string hash() const = 0; +extern ADDAPI const char* MONERO_CoinsInfo_hash(void* coinsInfo_ptr); +// virtual size_t internalOutputIndex() const = 0; +extern ADDAPI size_t MONERO_CoinsInfo_internalOutputIndex(void* coinsInfo_ptr); +// virtual uint64_t globalOutputIndex() const = 0; +extern ADDAPI uint64_t MONERO_CoinsInfo_globalOutputIndex(void* coinsInfo_ptr); +// virtual bool spent() const = 0; +extern ADDAPI bool MONERO_CoinsInfo_spent(void* coinsInfo_ptr); +// virtual bool frozen() const = 0; +extern ADDAPI bool MONERO_CoinsInfo_frozen(void* coinsInfo_ptr); +// virtual uint64_t spentHeight() const = 0; +extern ADDAPI uint64_t MONERO_CoinsInfo_spentHeight(void* coinsInfo_ptr); +// virtual uint64_t amount() const = 0; +extern ADDAPI uint64_t MONERO_CoinsInfo_amount(void* coinsInfo_ptr); +// virtual bool rct() const = 0; +extern ADDAPI bool MONERO_CoinsInfo_rct(void* coinsInfo_ptr); +// virtual bool keyImageKnown() const = 0; +extern ADDAPI bool MONERO_CoinsInfo_keyImageKnown(void* coinsInfo_ptr); +// virtual size_t pkIndex() const = 0; +extern ADDAPI size_t MONERO_CoinsInfo_pkIndex(void* coinsInfo_ptr); +// virtual uint32_t subaddrIndex() const = 0; +extern ADDAPI uint32_t MONERO_CoinsInfo_subaddrIndex(void* coinsInfo_ptr); +// virtual uint32_t subaddrAccount() const = 0; +extern ADDAPI uint32_t MONERO_CoinsInfo_subaddrAccount(void* coinsInfo_ptr); +// virtual std::string address() const = 0; +extern ADDAPI const char* MONERO_CoinsInfo_address(void* coinsInfo_ptr); +// virtual std::string addressLabel() const = 0; +extern ADDAPI const char* MONERO_CoinsInfo_addressLabel(void* coinsInfo_ptr); +// virtual std::string keyImage() const = 0; +extern ADDAPI const char* MONERO_CoinsInfo_keyImage(void* coinsInfo_ptr); +// virtual uint64_t unlockTime() const = 0; +extern ADDAPI uint64_t MONERO_CoinsInfo_unlockTime(void* coinsInfo_ptr); +// virtual bool unlocked() const = 0; +extern ADDAPI bool MONERO_CoinsInfo_unlocked(void* coinsInfo_ptr); +// virtual std::string pubKey() const = 0; +extern ADDAPI const char* MONERO_CoinsInfo_pubKey(void* coinsInfo_ptr); +// virtual bool coinbase() const = 0; +extern ADDAPI bool MONERO_CoinsInfo_coinbase(void* coinsInfo_ptr); +// virtual std::string description() const = 0; +extern ADDAPI const char* MONERO_CoinsInfo_description(void* coinsInfo_ptr); +// }; +// struct Coins +// { +// virtual ~Coins() = 0; +// virtual int count() const = 0; +extern ADDAPI int MONERO_Coins_count(void* coins_ptr); +// virtual CoinsInfo * coin(int index) const = 0; +extern ADDAPI void* MONERO_Coins_coin(void* coins_ptr, int index); +// virtual std::vector getAll() const = 0; +extern ADDAPI int MONERO_Coins_getAll_size(void* coins_ptr); +extern ADDAPI void* MONERO_Coins_getAll_byIndex(void* coins_ptr, int index); +// virtual void refresh() = 0; +extern ADDAPI void MONERO_Coins_refresh(void* coins_ptr); +// virtual void setFrozen(std::string public_key) = 0; +extern ADDAPI void MONERO_Coins_setFrozenByPublicKey(void* coins_ptr, const char* public_key); +// virtual void setFrozen(int index) = 0; +extern ADDAPI void MONERO_Coins_setFrozen(void* coins_ptr, int index); +// virtual void thaw(int index) = 0; +extern ADDAPI void MONERO_Coins_thaw(void* coins_ptr, int index); +// virtual void thaw(std::string public_key) = 0; +extern ADDAPI void MONERO_Coins_thawByPublicKey(void* coins_ptr, const char* public_key); +// virtual bool isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) = 0; +extern ADDAPI bool MONERO_Coins_isTransferUnlocked(void* coins_ptr, uint64_t unlockTime, uint64_t blockHeight); +// virtual void setDescription(const std::string &public_key, const std::string &description) = 0; +extern ADDAPI void MONERO_Coins_setDescription(void* coins_ptr, const char* public_key, const char* description); +// }; +// struct SubaddressRow { +// public: +// SubaddressRow(std::size_t _rowId, const std::string &_address, const std::string &_label): +// m_rowId(_rowId), +// m_address(_address), +// m_label(_label) {} + +// private: +// std::size_t m_rowId; +// std::string m_address; +// std::string m_label; +// public: +// std::string extra; +extern ADDAPI const char* MONERO_SubaddressRow_extra(void* subaddressRow_ptr); +// std::string getAddress() const {return m_address;} +extern ADDAPI const char* MONERO_SubaddressRow_getAddress(void* subaddressRow_ptr); +// std::string getLabel() const {return m_label;} +extern ADDAPI const char* MONERO_SubaddressRow_getLabel(void* subaddressRow_ptr); +// std::size_t getRowId() const {return m_rowId;} +extern ADDAPI size_t MONERO_SubaddressRow_getRowId(void* subaddressRow_ptr); +// }; + +// struct Subaddress +// { +// virtual ~Subaddress() = 0; +// virtual std::vector getAll() const = 0; +extern ADDAPI int MONERO_Subaddress_getAll_size(void* subaddress_ptr); +extern ADDAPI void* MONERO_Subaddress_getAll_byIndex(void* subaddress_ptr, int index); +// virtual void addRow(uint32_t accountIndex, const std::string &label) = 0; +extern ADDAPI void MONERO_Subaddress_addRow(void* subaddress_ptr, uint32_t accountIndex, const char* label); +// virtual void setLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label) = 0; +extern ADDAPI void MONERO_Subaddress_setLabel(void* subaddress_ptr, uint32_t accountIndex, uint32_t addressIndex, const char* label); +// virtual void refresh(uint32_t accountIndex) = 0; +extern ADDAPI void MONERO_Subaddress_refresh(void* subaddress_ptr, uint32_t accountIndex); +// }; + +// struct SubaddressAccountRow { +// public: +// SubaddressAccountRow(std::size_t _rowId, const std::string &_address, const std::string &_label, const std::string &_balance, const std::string &_unlockedBalance): +// m_rowId(_rowId), +// m_address(_address), +// m_label(_label), +// m_balance(_balance), +// m_unlockedBalance(_unlockedBalance) {} + +// private: +// std::size_t m_rowId; +// std::string m_address; +// std::string m_label; +// std::string m_balance; +// std::string m_unlockedBalance; +// public: +// std::string extra; +extern ADDAPI const char* MONERO_SubaddressAccountRow_extra(void* subaddressAccountRow_ptr); +// std::string getAddress() const {return m_address;} +extern ADDAPI const char* MONERO_SubaddressAccountRow_getAddress(void* subaddressAccountRow_ptr); +// std::string getLabel() const {return m_label;} +extern ADDAPI const char* MONERO_SubaddressAccountRow_getLabel(void* subaddressAccountRow_ptr); +// std::string getBalance() const {return m_balance;} +extern ADDAPI const char* MONERO_SubaddressAccountRow_getBalance(void* subaddressAccountRow_ptr); +// std::string getUnlockedBalance() const {return m_unlockedBalance;} +extern ADDAPI const char* MONERO_SubaddressAccountRow_getUnlockedBalance(void* subaddressAccountRow_ptr); +// std::size_t getRowId() const {return m_rowId;} +extern ADDAPI size_t MONERO_SubaddressAccountRow_getRowId(void* subaddressAccountRow_ptr); +// }; + +// struct SubaddressAccount +// { +// virtual ~SubaddressAccount() = 0; +// virtual std::vector getAll() const = 0; +extern ADDAPI int MONERO_SubaddressAccount_getAll_size(void* subaddressAccount_ptr); +extern ADDAPI void* MONERO_SubaddressAccount_getAll_byIndex(void* subaddressAccount_ptr, int index); +// virtual void addRow(const std::string &label) = 0; +extern ADDAPI void MONERO_SubaddressAccount_addRow(void* subaddressAccount_ptr, const char* label); +// virtual void setLabel(uint32_t accountIndex, const std::string &label) = 0; +extern ADDAPI void MONERO_SubaddressAccount_setLabel(void* subaddressAccount_ptr, uint32_t accountIndex, const char* label); +// virtual void refresh() = 0; +extern ADDAPI void MONERO_SubaddressAccount_refresh(void* subaddressAccount_ptr); +// }; + +// struct MultisigState { +// MultisigState() : isMultisig(false), isReady(false), threshold(0), total(0) {} + +// bool isMultisig; +extern ADDAPI bool MONERO_MultisigState_isMultisig(void* multisigState_ptr); +// bool isReady; +extern ADDAPI bool MONERO_MultisigState_isReady(void* multisigState_ptr); +// uint32_t threshold; +extern ADDAPI uint32_t MONERO_MultisigState_threshold(void* multisigState_ptr); +// uint32_t total; +extern ADDAPI uint32_t MONERO_MultisigState_total(void* multisigState_ptr); +// }; + + +// struct DeviceProgress { +// DeviceProgress(): m_progress(0), m_indeterminate(false) {} +// DeviceProgress(double progress, bool indeterminate=false): m_progress(progress), m_indeterminate(indeterminate) {} + +// virtual double progress() const { return m_progress; } +extern ADDAPI bool MONERO_DeviceProgress_progress(void* deviceProgress_ptr); +// virtual bool indeterminate() const { return m_indeterminate; } +extern ADDAPI bool MONERO_DeviceProgress_indeterminate(void* deviceProgress_ptr); + +// protected: +// double m_progress; +// bool m_indeterminate; +// }; + +// struct Wallet; +// struct WalletListener +// { +// virtual ~WalletListener() = 0; +// virtual void moneySpent(const std::string &txId, uint64_t amount) = 0; +// virtual void moneyReceived(const std::string &txId, uint64_t amount) = 0; +// virtual void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) = 0; +// virtual void newBlock(uint64_t height) = 0; +// virtual void updated() = 0; +// virtual void refreshed() = 0; +// virtual void onDeviceButtonRequest(uint64_t code) { (void)code; } +// virtual void onDeviceButtonPressed() { } +// virtual optional onDevicePinRequest() { +// throw std::runtime_error("Not supported"); +// } +// virtual optional onDevicePassphraseRequest(bool & on_device) { +// on_device = true; +// return optional(); +// } +// virtual void onDeviceProgress(const DeviceProgress & event) { (void)event; }; +// virtual void onSetWallet(Wallet * wallet) { (void)wallet; }; +// }; +// struct Wallet +// { +// enum Device { +// Device_Software = 0, +const int WalletDevice_Software = 0; +// Device_Ledger = 1, +const int WalletDevice_Ledger = 1; +// Device_Trezor = 2 +const int WalletDevice_Trezor = 2; +// }; +// enum Status { +// Status_Ok, +const int WalletStatus_Ok = 0; +// Status_Error, +const int WalletStatus_Error = 1; +// Status_Critical +const int WalletStatus_Critical = 2; +// }; +// enum ConnectionStatus { +// ConnectionStatus_Disconnected, +const int WalletConnectionStatus_Disconnected = 0; +// ConnectionStatus_Connected, +const int WalletConnectionStatus_Connected = 1; +// ConnectionStatus_WrongVersion +const int WalletConnectionStatus_WrongVersion = 2; +// }; +// enum BackgroundSyncType { +// BackgroundSync_Off = 0, +const int WalletBackgroundSync_Off = 0; +// BackgroundSync_ReusePassword = 1, +const int WalletBackgroundSync_ReusePassword = 1; +// BackgroundSync_CustomPassword = 2 +const int BackgroundSync_CustomPassword = 2; +// }; +// virtual ~Wallet() = 0; +// virtual std::string seed(const std::string& seed_offset = "") const = 0; +extern ADDAPI const char* MONERO_Wallet_seed(void* wallet_ptr, const char* seed_offset); +// virtual std::string getSeedLanguage() const = 0; +extern ADDAPI const char* MONERO_Wallet_getSeedLanguage(void* wallet_ptr); +// virtual void setSeedLanguage(const std::string &arg) = 0; +extern ADDAPI void MONERO_Wallet_setSeedLanguage(void* wallet_ptr, const char* arg); +// virtual int status() const = 0; +extern ADDAPI int MONERO_Wallet_status(void* wallet_ptr); +// virtual std::string errorString() const = 0; +extern ADDAPI const char* MONERO_Wallet_errorString(void* wallet_ptr); +// virtual void statusWithErrorString(int& status, std::string& errorString) const = 0; +// virtual bool setPassword(const std::string &password) = 0; +extern ADDAPI bool MONERO_Wallet_setPassword(void* wallet_ptr, const char* password); +// virtual const std::string& getPassword() const = 0; +extern ADDAPI const char* MONERO_Wallet_getPassword(void* wallet_ptr); +// virtual bool setDevicePin(const std::string &pin) { (void)pin; return false; }; +extern ADDAPI bool MONERO_Wallet_setDevicePin(void* wallet_ptr, const char* pin); +// virtual bool setDevicePassphrase(const std::string &passphrase) { (void)passphrase; return false; }; +extern ADDAPI bool MONERO_Wallet_setDevicePassphrase(void* wallet_ptr, const char* passphrase); +// virtual std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const = 0; +extern ADDAPI const char* MONERO_Wallet_address(void* wallet_ptr, uint64_t accountIndex, uint64_t addressIndex); +// std::string mainAddress() const { return address(0, 0); } +// virtual std::string path() const = 0; +extern ADDAPI const char* MONERO_Wallet_path(void* wallet_ptr); +// virtual NetworkType nettype() const = 0; +extern ADDAPI int MONERO_Wallet_nettype(void* wallet_ptr); +// bool mainnet() const { return nettype() == MAINNET; } +// bool testnet() const { return nettype() == TESTNET; } +// bool stagenet() const { return nettype() == STAGENET; } +// virtual void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const = 0; +// virtual bool useForkRules(uint8_t version, int64_t early_blocks) const = 0; +extern ADDAPI uint8_t MONERO_Wallet_useForkRules(void* wallet_ptr, uint8_t version, int64_t early_blocks); +// virtual std::string integratedAddress(const std::string &payment_id) const = 0; +extern ADDAPI const char* MONERO_Wallet_integratedAddress(void* wallet_ptr, const char* payment_id); +// virtual std::string secretViewKey() const = 0; +extern ADDAPI const char* MONERO_Wallet_secretViewKey(void* wallet_ptr); +// virtual std::string publicViewKey() const = 0; +extern ADDAPI const char* MONERO_Wallet_publicViewKey(void* wallet_ptr); +// virtual std::string secretSpendKey() const = 0; +extern ADDAPI const char* MONERO_Wallet_secretSpendKey(void* wallet_ptr); +// virtual std::string publicSpendKey() const = 0; +extern ADDAPI const char* MONERO_Wallet_publicSpendKey(void* wallet_ptr); +// virtual std::string publicMultisigSignerKey() const = 0; +extern ADDAPI const char* MONERO_Wallet_publicMultisigSignerKey(void* wallet_ptr); +// virtual void stop() = 0; +extern ADDAPI void MONERO_Wallet_stop(void* wallet_ptr); +// virtual bool store(const std::string &path) = 0; +extern ADDAPI bool MONERO_Wallet_store(void* wallet_ptr, const char* path); +// virtual std::string filename() const = 0; +extern ADDAPI const char* MONERO_Wallet_filename(void* wallet_ptr); +// virtual std::string keysFilename() const = 0; +extern ADDAPI const char* MONERO_Wallet_keysFilename(void* wallet_ptr); +// virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false, const std::string &proxy_address = "") = 0; +extern ADDAPI bool MONERO_Wallet_init(void* wallet_ptr, const char* daemon_address, uint64_t upper_transaction_size_limit, const char* daemon_username, const char* daemon_password, bool use_ssl, bool lightWallet, const char* proxy_address); +// virtual bool createWatchOnly(const std::string &path, const std::string &password, const std::string &language) const = 0; +extern ADDAPI bool MONERO_Wallet_createWatchOnly(void* wallet_ptr, const char* path, const char* password, const char* language); +// virtual void setRefreshFromBlockHeight(uint64_t refresh_from_block_height) = 0; +extern ADDAPI void MONERO_Wallet_setRefreshFromBlockHeight(void* wallet_ptr, uint64_t refresh_from_block_height); +// virtual uint64_t getRefreshFromBlockHeight() const = 0; +extern ADDAPI uint64_t MONERO_Wallet_getRefreshFromBlockHeight(void* wallet_ptr); +// virtual void setRecoveringFromSeed(bool recoveringFromSeed) = 0; +extern ADDAPI void MONERO_Wallet_setRecoveringFromSeed(void* wallet_ptr, bool recoveringFromSeed); +// virtual void setRecoveringFromDevice(bool recoveringFromDevice) = 0; +extern ADDAPI void MONERO_Wallet_setRecoveringFromDevice(void* wallet_ptr, bool recoveringFromDevice); +// virtual void setSubaddressLookahead(uint32_t major, uint32_t minor) = 0; +extern ADDAPI void MONERO_Wallet_setSubaddressLookahead(void* wallet_ptr, uint32_t major, uint32_t minor); +// virtual bool connectToDaemon() = 0; +extern ADDAPI bool MONERO_Wallet_connectToDaemon(void* wallet_ptr); +// virtual ConnectionStatus connected() const = 0; +extern ADDAPI int MONERO_Wallet_connected(void* wallet_ptr); +// virtual void setTrustedDaemon(bool arg) = 0; +extern ADDAPI void MONERO_Wallet_setTrustedDaemon(void* wallet_ptr, bool arg); +// virtual bool trustedDaemon() const = 0; +extern ADDAPI bool MONERO_Wallet_trustedDaemon(void* wallet_ptr); +// virtual bool setProxy(const std::string &address) = 0; +extern ADDAPI bool MONERO_Wallet_setProxy(void* wallet_ptr, const char* address); +// virtual uint64_t balance(uint32_t accountIndex = 0) const = 0; +extern ADDAPI uint64_t MONERO_Wallet_balance(void* wallet_ptr, uint32_t accountIndex); +// uint64_t balanceAll() const { +// uint64_t result = 0; +// for (uint32_t i = 0; i < numSubaddressAccounts(); ++i) +// result += balance(i); +// return result; +// } +// virtual uint64_t unlockedBalance(uint32_t accountIndex = 0) const = 0; +extern ADDAPI uint64_t MONERO_Wallet_unlockedBalance(void* wallet_ptr, uint32_t accountIndex); +// uint64_t unlockedBalanceAll() const { +// uint64_t result = 0; +// for (uint32_t i = 0; i < numSubaddressAccounts(); ++i) +// result += unlockedBalance(i); +// return result; +// } +// virtual bool watchOnly() const = 0; +// virtual uint64_t viewOnlyBalance(uint32_t accountIndex, const std::vector &key_images = {}) const = 0; +extern ADDAPI uint64_t MONERO_Wallet_viewOnlyBalance(void* wallet_ptr, uint32_t accountIndex); +extern ADDAPI bool MONERO_Wallet_watchOnly(void* wallet_ptr); +// virtual bool isDeterministic() const = 0; +extern ADDAPI bool MONERO_Wallet_isDeterministic(void* wallet_ptr); +// virtual uint64_t blockChainHeight() const = 0; +extern ADDAPI uint64_t MONERO_Wallet_blockChainHeight(void* wallet_ptr); +// virtual uint64_t approximateBlockChainHeight() const = 0; +extern ADDAPI uint64_t MONERO_Wallet_approximateBlockChainHeight(void* wallet_ptr); +// virtual uint64_t estimateBlockChainHeight() const = 0; +extern ADDAPI uint64_t MONERO_Wallet_estimateBlockChainHeight(void* wallet_ptr); +// virtual uint64_t daemonBlockChainHeight() const = 0; +extern ADDAPI uint64_t MONERO_Wallet_daemonBlockChainHeight(void* wallet_ptr); +// virtual uint64_t daemonBlockChainTargetHeight() const = 0; +extern ADDAPI uint64_t MONERO_Wallet_daemonBlockChainTargetHeight(void* wallet_ptr); +// virtual bool synchronized() const = 0; +extern ADDAPI bool MONERO_Wallet_synchronized(void* wallet_ptr); +// static std::string displayAmount(uint64_t amount); +extern ADDAPI const char* MONERO_Wallet_displayAmount(uint64_t amount); +// static uint64_t amountFromString(const std::string &amount); +extern ADDAPI uint64_t MONERO_Wallet_amountFromString(const char* amount); +// static uint64_t amountFromDouble(double amount); +extern ADDAPI uint64_t MONERO_Wallet_amountFromDouble(double amount); +// static std::string genPaymentId(); +extern ADDAPI const char* MONERO_Wallet_genPaymentId(); +// static bool paymentIdValid(const std::string &paiment_id); +extern ADDAPI bool MONERO_Wallet_paymentIdValid(const char* paiment_id); +// static bool addressValid(const std::string &str, NetworkType nettype); +extern ADDAPI bool MONERO_Wallet_addressValid(const char* str, int nettype); +// static bool addressValid(const std::string &str, bool testnet) // deprecated +// { +// return addressValid(str, testnet ? TESTNET : MAINNET); +// } +extern ADDAPI bool MONERO_Wallet_keyValid(const char* secret_key_string, const char* address_string, bool isViewKey, int nettype); +extern ADDAPI const char* MONERO_Wallet_keyValid_error(const char* secret_key_string, const char* address_string, bool isViewKey, int nettype); +// static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, NetworkType nettype, std::string &error); +// static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error) // deprecated +// { +// return keyValid(secret_key_string, address_string, isViewKey, testnet ? TESTNET : MAINNET, error); +// } +// static std::string paymentIdFromAddress(const std::string &str, NetworkType nettype); +extern ADDAPI const char* MONERO_Wallet_paymentIdFromAddress(const char* strarg, int nettype); +// static std::string paymentIdFromAddress(const std::string &str, bool testnet) // deprecated +// { +// return paymentIdFromAddress(str, testnet ? TESTNET : MAINNET); +// } +// static uint64_t maximumAllowedAmount(); +extern ADDAPI uint64_t MONERO_Wallet_maximumAllowedAmount(); +// static void init(const char *argv0, const char *default_log_base_name) { init(argv0, default_log_base_name, "", true); } +// static void init(const char *argv0, const char *default_log_base_name, const std::string &log_path, bool console); +extern ADDAPI void MONERO_Wallet_init3(void* wallet_ptr, const char* argv0, const char* default_log_base_name, const char* log_path, bool console); +// static void debug(const std::string &category, const std::string &str); +// static void info(const std::string &category, const std::string &str); +// static void warning(const std::string &category, const std::string &str); +// static void error(const std::string &category, const std::string &str); +// virtual void startRefresh() = 0; +// virtual bool getPolyseed(std::string &seed, std::string &passphrase) const = 0; +extern ADDAPI const char* MONERO_Wallet_getPolyseed(void* wallet_ptr, const char* passphrase); +// static bool createPolyseed(std::string &seed_words, std::string &err, const std::string &language = "English"); +extern ADDAPI const char* MONERO_Wallet_createPolyseed(const char* language); +extern ADDAPI void MONERO_Wallet_startRefresh(void* wallet_ptr); +// virtual void pauseRefresh() = 0; +extern ADDAPI void MONERO_Wallet_pauseRefresh(void* wallet_ptr); +// virtual bool refresh() = 0; +extern ADDAPI bool MONERO_Wallet_refresh(void* wallet_ptr); +// virtual void refreshAsync() = 0; +extern ADDAPI void MONERO_Wallet_refreshAsync(void* wallet_ptr); +// virtual bool rescanBlockchain() = 0; +extern ADDAPI bool MONERO_Wallet_rescanBlockchain(void* wallet_ptr); +// virtual void rescanBlockchainAsync() = 0; +extern ADDAPI void MONERO_Wallet_rescanBlockchainAsync(void* wallet_ptr); +// virtual void setAutoRefreshInterval(int millis) = 0; +extern ADDAPI void MONERO_Wallet_setAutoRefreshInterval(void* wallet_ptr, int millis); +// virtual int autoRefreshInterval() const = 0; +extern ADDAPI int MONERO_Wallet_autoRefreshInterval(void* wallet_ptr); +// virtual void addSubaddressAccount(const std::string& label) = 0; +extern ADDAPI void MONERO_Wallet_addSubaddressAccount(void* wallet_ptr, const char* label); +// virtual size_t numSubaddressAccounts() const = 0; +extern ADDAPI size_t MONERO_Wallet_numSubaddressAccounts(void* wallet_ptr); +// virtual size_t numSubaddresses(uint32_t accountIndex) const = 0; +extern ADDAPI size_t MONERO_Wallet_numSubaddresses(void* wallet_ptr, uint32_t accountIndex); +// virtual void addSubaddress(uint32_t accountIndex, const std::string& label) = 0; +extern ADDAPI void MONERO_Wallet_addSubaddress(void* wallet_ptr, uint32_t accountIndex, const char* label); +// virtual std::string getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const = 0; +extern ADDAPI const char* MONERO_Wallet_getSubaddressLabel(void* wallet_ptr, uint32_t accountIndex, uint32_t addressIndex); +// virtual void setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label) = 0; +extern ADDAPI void MONERO_Wallet_setSubaddressLabel(void* wallet_ptr, uint32_t accountIndex, uint32_t addressIndex, const char* label); +// virtual MultisigState multisig() const = 0; +extern ADDAPI void* MONERO_Wallet_multisig(void* wallet_ptr); +// virtual std::string getMultisigInfo() const = 0; +extern ADDAPI const char* MONERO_Wallet_getMultisigInfo(void* wallet_ptr); +// virtual std::string makeMultisig(const std::vector& info, uint32_t threshold) = 0; +extern ADDAPI const char* MONERO_Wallet_makeMultisig(void* wallet_ptr, const char* info, const char* info_separator, uint32_t threshold); +// virtual std::string exchangeMultisigKeys(const std::vector &info, const bool force_update_use_with_caution) = 0; +extern ADDAPI const char* MONERO_Wallet_exchangeMultisigKeys(void* wallet_ptr, const char* info, const char* info_separator, bool force_update_use_with_caution); +// virtual bool exportMultisigImages(std::string& images) = 0; +extern ADDAPI const char* MONERO_Wallet_exportMultisigImages(void* wallet_ptr, const char* separator); +// virtual size_t importMultisigImages(const std::vector& images) = 0; +extern ADDAPI size_t MONERO_Wallet_importMultisigImages(void* wallet_ptr, const char* info, const char* info_separator); +// virtual bool hasMultisigPartialKeyImages() const = 0; +extern ADDAPI size_t MONERO_Wallet_hasMultisigPartialKeyImages(void* wallet_ptr); +// virtual PendingTransaction* restoreMultisigTransaction(const std::string& signData) = 0; +extern ADDAPI void* MONERO_Wallet_restoreMultisigTransaction(void* wallet_ptr, const char* signData); +// virtual PendingTransaction * createTransactionMultDest(const std::vector &dst_addr, const std::string &payment_id, +// optional> amount, uint32_t mixin_count, +// PendingTransaction::Priority = PendingTransaction::Priority_Low, +// uint32_t subaddr_account = 0, +// std::set subaddr_indices = {}) = 0; +extern ADDAPI void* MONERO_Wallet_createTransactionMultDest(void* wallet_ptr, const char* dst_addr_list, const char* dst_addr_list_separator, const char* payment_id, + bool amount_sweep_all, const char* amount_list, const char* amount_list_separator, uint32_t mixin_count, + int pendingTransactionPriority, + uint32_t subaddr_account, + const char* preferredInputs, const char* preferredInputs_separator); +// virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, +// optional amount, uint32_t mixin_count, +// PendingTransaction::Priority = PendingTransaction::Priority_Low, +// uint32_t subaddr_account = 0, +// std::set subaddr_indices = {}, +// const std::set &preferred_inputs = {) = 0; +extern ADDAPI void* MONERO_Wallet_createTransaction(void* wallet_ptr, const char* dst_addr, const char* payment_id, + uint64_t amount, uint32_t mixin_count, + int pendingTransactionPriority, + uint32_t subaddr_account, + const char* preferredInputs, const char* separator); +// virtual PendingTransaction * createSweepUnmixableTransaction() = 0; +// virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) = 0; +extern ADDAPI void* MONERO_Wallet_loadUnsignedTx(void* wallet_ptr, const char* unsigned_filename); +extern ADDAPI void* MONERO_Wallet_loadUnsignedTxUR(void* wallet_ptr, const char* input); +// virtual bool submitTransaction(const std::string &fileName) = 0; +extern ADDAPI bool MONERO_Wallet_submitTransaction(void* wallet_ptr, const char* fileName); +extern ADDAPI bool MONERO_Wallet_submitTransactionUR(void* wallet_ptr, const char* input); +// virtual void disposeTransaction(PendingTransaction * t) = 0; +// virtual uint64_t estimateTransactionFee(const std::vector> &destinations, +// PendingTransaction::Priority priority) const = 0; +// virtual bool hasUnknownKeyImages() const = 0; +extern ADDAPI bool MONERO_Wallet_hasUnknownKeyImages(void* wallet_ptr); +// virtual bool exportKeyImages(const std::string &filename, bool all = false) = 0; +extern ADDAPI bool MONERO_Wallet_exportKeyImages(void* wallet_ptr, const char* filename, bool all); +extern ADDAPI const char* MONERO_Wallet_exportKeyImagesUR(void* wallet_ptr, size_t max_fragment_length, bool all) ; +// virtual bool importKeyImages(const std::string &filename) = 0; +extern ADDAPI bool MONERO_Wallet_importKeyImages(void* wallet_ptr, const char* filename); +extern ADDAPI bool MONERO_Wallet_importKeyImagesUR(void* wallet_ptr, const char* input); +// virtual bool exportOutputs(const std::string &filename, bool all = false) = 0; +extern ADDAPI bool MONERO_Wallet_exportOutputs(void* wallet_ptr, const char* filename, bool all); +extern ADDAPI const char* MONERO_Wallet_exportOutputsUR(void* wallet_ptr, size_t max_fragment_length, bool all); +// virtual bool importOutputs(const std::string &filename) = 0; +extern ADDAPI bool MONERO_Wallet_importOutputs(void* wallet_ptr, const char* filename); +extern ADDAPI bool MONERO_Wallet_importOutputsUR(void* wallet_ptr, const char* input); +// virtual bool scanTransactions(const std::vector &txids) = 0; +// virtual bool setupBackgroundSync(const BackgroundSyncType background_sync_type, const std::string &wallet_password, const optional &background_cache_password) = 0; +extern ADDAPI bool MONERO_Wallet_setupBackgroundSync(void* wallet_ptr, int background_sync_type, const char* wallet_password, const char* background_cache_password); +// virtual BackgroundSyncType getBackgroundSyncType() const = 0; +extern ADDAPI int MONERO_Wallet_getBackgroundSyncType(void* wallet_ptr); +// virtual bool startBackgroundSync() = 0; +extern ADDAPI bool MONERO_Wallet_startBackgroundSync(void* wallet_ptr); +// virtual bool stopBackgroundSync(const std::string &wallet_password) = 0; +extern ADDAPI bool MONERO_Wallet_stopBackgroundSync(void* wallet_ptr, const char* wallet_password); +// virtual bool isBackgroundSyncing() const = 0; +extern ADDAPI bool MONERO_Wallet_isBackgroundSyncing(void* wallet_ptr); +// virtual bool isBackgroundWallet() const = 0; +extern ADDAPI bool MONERO_Wallet_isBackgroundWallet(void* wallet_ptr); +// virtual TransactionHistory * history() = 0; +extern ADDAPI void* MONERO_Wallet_history(void* wallet_ptr); +// virtual AddressBook * addressBook() = 0; +extern ADDAPI void* MONERO_Wallet_addressBook(void* wallet_ptr); +// virtual Coins * coins() = 0; +extern ADDAPI void* MONERO_Wallet_coins(void* wallet_ptr); +// virtual Subaddress * subaddress() = 0; +extern ADDAPI void* MONERO_Wallet_subaddress(void* wallet_ptr); +// virtual SubaddressAccount * subaddressAccount() = 0; +extern ADDAPI void* MONERO_Wallet_subaddressAccount(void* wallet_ptr); +// virtual void setListener(WalletListener *) = 0; +// virtual uint32_t defaultMixin() const = 0; +extern ADDAPI uint32_t MONERO_Wallet_defaultMixin(void* wallet_ptr); +// virtual void setDefaultMixin(uint32_t arg) = 0; +extern ADDAPI void MONERO_Wallet_setDefaultMixin(void* wallet_ptr, uint32_t arg); +// virtual bool setCacheAttribute(const std::string &key, const std::string &val) = 0; +extern ADDAPI bool MONERO_Wallet_setCacheAttribute(void* wallet_ptr, const char* key, const char* val); +// virtual std::string getCacheAttribute(const std::string &key) const = 0; +extern ADDAPI const char* MONERO_Wallet_getCacheAttribute(void* wallet_ptr, const char* key); +// virtual bool setUserNote(const std::string &txid, const std::string ¬e) = 0; +extern ADDAPI bool MONERO_Wallet_setUserNote(void* wallet_ptr, const char* txid, const char* note); +// virtual std::string getUserNote(const std::string &txid) const = 0; +extern ADDAPI const char* MONERO_Wallet_getUserNote(void* wallet_ptr, const char* txid); +// virtual std::string getTxKey(const std::string &txid) const = 0; +extern ADDAPI const char* MONERO_Wallet_getTxKey(void* wallet_ptr, const char* txid); +// virtual bool checkTxKey(const std::string &txid, std::string tx_key, const std::string &address, uint64_t &received, bool &in_pool, uint64_t &confirmations) = 0; +// virtual std::string getTxProof(const std::string &txid, const std::string &address, const std::string &message) const = 0; +// virtual bool checkTxProof(const std::string &txid, const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &received, bool &in_pool, uint64_t &confirmations) = 0; +// virtual std::string getSpendProof(const std::string &txid, const std::string &message) const = 0; +// virtual bool checkSpendProof(const std::string &txid, const std::string &message, const std::string &signature, bool &good) const = 0; +// virtual std::string getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const = 0; +// virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const = 0; +// virtual std::string signMessage(const std::string &message, const std::string &address = "") = 0; +extern ADDAPI const char* MONERO_Wallet_signMessage(void* wallet_ptr, const char* message, const char* address); +// virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0; +extern ADDAPI bool MONERO_Wallet_verifySignedMessage(void* wallet_ptr, const char* message, const char* address, const char* signature); +// virtual std::string signMultisigParticipant(const std::string &message) const = 0; +// virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const = 0; +// virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) = 0; +// virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const = 0; +// virtual std::string getDefaultDataDir() const = 0; +// virtual bool rescanSpent() = 0; +extern ADDAPI bool MONERO_Wallet_rescanSpent(void* wallet_ptr); +// virtual void setOffline(bool offline) = 0; +extern ADDAPI void MONERO_Wallet_setOffline(void* wallet_ptr, bool offline); +// virtual bool isOffline() const = 0; +extern ADDAPI bool MONERO_Wallet_isOffline(void* wallet_ptr); +// virtual bool blackballOutputs(const std::vector &outputs, bool add) = 0; +// virtual bool blackballOutput(const std::string &amount, const std::string &offset) = 0; +// virtual bool unblackballOutput(const std::string &amount, const std::string &offset) = 0; +// virtual bool getRing(const std::string &key_image, std::vector &ring) const = 0; +// virtual bool getRings(const std::string &txid, std::vector>> &rings) const = 0; +// virtual bool setRing(const std::string &key_image, const std::vector &ring, bool relative) = 0; +// virtual void segregatePreForkOutputs(bool segregate) = 0; +extern ADDAPI void MONERO_Wallet_segregatePreForkOutputs(void* wallet_ptr, bool segregate); +// virtual void segregationHeight(uint64_t height) = 0; +extern ADDAPI void MONERO_Wallet_segregationHeight(void* wallet_ptr, uint64_t height); +// virtual void keyReuseMitigation2(bool mitigation) = 0; +extern ADDAPI void MONERO_Wallet_keyReuseMitigation2(void* wallet_ptr, bool mitigation); +// virtual bool lightWalletLogin(bool &isNewWallet) const = 0; +// virtual bool lightWalletImportWalletRequest(std::string &payment_id, uint64_t &fee, bool &new_request, bool &request_fulfilled, std::string &payment_address, std::string &status) = 0; +// virtual bool lockKeysFile() = 0; +extern ADDAPI bool MONERO_Wallet_lockKeysFile(void* wallet_ptr); +// virtual bool unlockKeysFile() = 0; +extern ADDAPI bool MONERO_Wallet_unlockKeysFile(void* wallet_ptr); +// virtual bool isKeysFileLocked() = 0; +extern ADDAPI bool MONERO_Wallet_isKeysFileLocked(void* wallet_ptr); +// virtual Device getDeviceType() const = 0; +extern ADDAPI int MONERO_Wallet_getDeviceType(void* wallet_ptr); +// virtual uint64_t coldKeyImageSync(uint64_t &spent, uint64_t &unspent) = 0; +extern ADDAPI uint64_t MONERO_Wallet_coldKeyImageSync(void* wallet_ptr, uint64_t spent, uint64_t unspent); +// virtual void deviceShowAddress(uint32_t accountIndex, uint32_t addressIndex, const std::string &paymentId) = 0; +extern ADDAPI const char* MONERO_Wallet_deviceShowAddress(void* wallet_ptr, uint32_t accountIndex, uint32_t addressIndex); +// virtual bool reconnectDevice() = 0; +extern ADDAPI bool MONERO_Wallet_reconnectDevice(void* wallet_ptr); +// virtual uint64_t getBytesReceived() = 0; +extern ADDAPI uint64_t MONERO_Wallet_getBytesReceived(void* wallet_ptr); +// virtual uint64_t getBytesSent() = 0; +extern ADDAPI uint64_t MONERO_Wallet_getBytesSent(void* wallet_ptr); + // HIDAPI_DUMMY +extern ADDAPI bool MONERO_Wallet_getStateIsConnected(void* wallet_ptr); +extern ADDAPI unsigned char* MONERO_Wallet_getSendToDevice(void* wallet_ptr); +extern ADDAPI size_t MONERO_Wallet_getSendToDeviceLength(void* wallet_ptr); +extern ADDAPI unsigned char* MONERO_Wallet_getReceivedFromDevice(void* wallet_ptr); +extern ADDAPI size_t MONERO_Wallet_getReceivedFromDeviceLength(void* wallet_ptr); +extern ADDAPI bool MONERO_Wallet_getWaitsForDeviceSend(void* wallet_ptr); +extern ADDAPI bool MONERO_Wallet_getWaitsForDeviceReceive(void* wallet_ptr); +extern ADDAPI void MONERO_Wallet_setDeviceReceivedData(void* wallet_ptr, unsigned char* data, size_t len); +extern ADDAPI void MONERO_Wallet_setDeviceSendData(void* wallet_ptr, unsigned char* data, size_t len); +// }; + +// struct WalletManager +// { +// virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, NetworkType nettype, uint64_t kdf_rounds = 1) = 0; +extern ADDAPI void* MONERO_WalletManager_createWallet(void* wm_ptr, const char* path, const char* password, const char* language, int networkType); +// Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet = false) // deprecated +// { +// return createWallet(path, password, language, testnet ? TESTNET : MAINNET); +// } +// virtual Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1, WalletListener * listener = nullptr) = 0; +extern ADDAPI void* MONERO_WalletManager_openWallet(void* wm_ptr, const char* path, const char* password, int networkType); +// Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) // deprecated +// { +// return openWallet(path, password, testnet ? TESTNET : MAINNET); +// } +// virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, +// NetworkType nettype = MAINNET, uint64_t restoreHeight = 0, uint64_t kdf_rounds = 1, +// const std::string &seed_offset = {}) = 0; +extern ADDAPI void* MONERO_WalletManager_recoveryWallet(void* wm_ptr, const char* path, const char* password, const char* mnemonic, int networkType, uint64_t restoreHeight, uint64_t kdfRounds, const char* seedOffset); +// Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, +// bool testnet = false, uint64_t restoreHeight = 0) // deprecated +// { +// return recoveryWallet(path, password, mnemonic, testnet ? TESTNET : MAINNET, restoreHeight); +// } +// virtual Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, NetworkType nettype, uint64_t restoreHeight = 0) = 0; +// Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, bool testnet = false, uint64_t restoreHeight = 0) // deprecated +// { +// return recoveryWallet(path, mnemonic, testnet ? TESTNET : MAINNET, restoreHeight); +// } +// virtual Wallet * createWalletFromKeys(const std::string &path, +// const std::string &password, +// const std::string &language, +// NetworkType nettype, +// uint64_t restoreHeight, +// const std::string &addressString, +// const std::string &viewKeyString, +// const std::string &spendKeyString = "", +// uint64_t kdf_rounds = 1) = 0; +extern ADDAPI void* MONERO_WalletManager_createWalletFromKeys(void* wm_ptr, const char* path, const char* password, const char* language, int nettype, uint64_t restoreHeight, const char* addressString, const char* viewKeyString, const char* spendKeyString, uint64_t kdf_rounds); +// Wallet * createWalletFromKeys(const std::string &path, +// const std::string &password, +// const std::string &language, +// bool testnet, +// uint64_t restoreHeight, +// const std::string &addressString, +// const std::string &viewKeyString, +// const std::string &spendKeyString = "") // deprecated +// { +// return createWalletFromKeys(path, password, language, testnet ? TESTNET : MAINNET, restoreHeight, addressString, viewKeyString, spendKeyString); +// } +// virtual Wallet * createWalletFromKeys(const std::string &path, +// const std::string &language, +// NetworkType nettype, +// uint64_t restoreHeight, +// const std::string &addressString, +// const std::string &viewKeyString, +// const std::string &spendKeyString = "") = 0; +// Wallet * createWalletFromKeys(const std::string &path, +// const std::string &language, +// bool testnet, +// uint64_t restoreHeight, +// const std::string &addressString, +// const std::string &viewKeyString, +// const std::string &spendKeyString = "") // deprecated +// { +// return createWalletFromKeys(path, language, testnet ? TESTNET : MAINNET, restoreHeight, addressString, viewKeyString, spendKeyString); +// } +// virtual Wallet * createDeterministicWalletFromSpendKey(const std::string &path, +// const std::string &password, +// const std::string &language, +// NetworkType nettype, +// uint64_t restoreHeight, +// const std::string &spendKeyString, +// uint64_t kdf_rounds = 1) = 0; +extern ADDAPI void* MONERO_WalletManager_createDeterministicWalletFromSpendKey(void* wm_ptr, const char* path, const char* password, + const char* language, int nettype, uint64_t restoreHeight, + const char* spendKeyString, uint64_t kdf_rounds); +// virtual Wallet * createWalletFromDevice(const std::string &path, +// const std::string &password, +// NetworkType nettype, +// const std::string &deviceName, +// uint64_t restoreHeight = 0, +// const std::string &subaddressLookahead = "", +// uint64_t kdf_rounds = 1, +// WalletListener * listener = nullptr) = 0; +extern ADDAPI void* MONERO_WalletManager_createWalletFromDevice(void* wm_ptr, const char* path, const char* password, int nettype, const char* deviceName, uint64_t restoreHeight, const char* subaddressLookahead, const char* viewKeyString, const char* spendKeyString, uint64_t kdf_rounds); +// virtual Wallet * createWalletFromPolyseed(const std::string &path, +// const std::string &password, +// NetworkType nettype, +// const std::string &mnemonic, +// const std::string &passphrase = "", +// bool newWallet = true, +// uint64_t restore_height = 0, +// uint64_t kdf_rounds = 1) = 0; +extern ADDAPI void* MONERO_WalletManager_createWalletFromPolyseed(void* wm_ptr, const char* path, const char* password, + int nettype, const char* mnemonic, const char* passphrase, + bool newWallet, uint64_t restore_height, uint64_t kdf_rounds); +// virtual bool closeWallet(Wallet *wallet, bool store = true) = 0; +extern ADDAPI bool MONERO_WalletManager_closeWallet(void* wm_ptr, void* wallet_ptr, bool store); +// virtual bool walletExists(const std::string &path) = 0; +extern ADDAPI bool MONERO_WalletManager_walletExists(void* wm_ptr, const char* path); +// virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const = 0; +extern ADDAPI bool MONERO_WalletManager_verifyWalletPassword(void* wm_ptr, const char* keys_file_name, const char* password, bool no_spend_key, uint64_t kdf_rounds); +// virtual bool queryWalletDevice(Wallet::Device& device_type, const std::string &keys_file_name, const std::string &password, uint64_t kdf_rounds = 1) const = 0; +extern ADDAPI int MONERO_WalletManager_queryWalletDevice(void* wm_ptr, const char* keys_file_name, const char* password, uint64_t kdf_rounds); +// virtual std::vector findWallets(const std::string &path) = 0; +extern ADDAPI const char* MONERO_WalletManager_findWallets(void* wm_ptr, const char* path, const char* separator); +// virtual std::string errorString() const = 0; +extern ADDAPI const char* MONERO_WalletManager_errorString(void* wm_ptr); +// virtual void setDaemonAddress(const std::string &address) = 0; +extern ADDAPI void MONERO_WalletManager_setDaemonAddress(void* wm_ptr, const char* address); +// virtual bool connected(uint32_t *version = NULL) = 0; +// virtual uint64_t blockchainHeight() = 0; +extern ADDAPI uint64_t MONERO_WalletManager_blockchainHeight(void* wm_ptr); +// virtual uint64_t blockchainTargetHeight() = 0; +extern ADDAPI uint64_t MONERO_WalletManager_blockchainTargetHeight(void* wm_ptr); +// virtual uint64_t networkDifficulty() = 0; +extern ADDAPI uint64_t MONERO_WalletManager_networkDifficulty(void* wm_ptr); +// virtual double miningHashRate() = 0; +extern ADDAPI double MONERO_WalletManager_miningHashRate(void* wm_ptr); +// virtual uint64_t blockTarget() = 0; +extern ADDAPI uint64_t MONERO_WalletManager_blockTarget(void* wm_ptr); +// virtual bool isMining() = 0; +extern ADDAPI bool MONERO_WalletManager_isMining(void* wm_ptr); +// virtual bool startMining(const std::string &address, uint32_t threads = 1, bool background_mining = false, bool ignore_battery = true) = 0; +extern ADDAPI bool MONERO_WalletManager_startMining(void* wm_ptr, const char* address, uint32_t threads, bool backgroundMining, bool ignoreBattery); +// virtual bool stopMining() = 0; +extern ADDAPI bool MONERO_WalletManager_stopMining(void* wm_ptr, const char* address); +// virtual std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const = 0; +extern ADDAPI const char* MONERO_WalletManager_resolveOpenAlias(void* wm_ptr, const char* address, bool dnssec_valid); +// static std::tuple checkUpdates( +// const std::string &software, +// std::string subdir, +// const char *buildtag = nullptr, +// const char *current_version = nullptr); +// virtual bool setProxy(const std::string &address) = 0; +extern ADDAPI bool MONERO_WalletManager_setProxy(void* wm_ptr, const char* address); +// }; + +int LogLevel_Silent = -1; +int LogLevel_0 = 0; +int LogLevel_1 = 1; +int LogLevel_2 = 2; +int LogLevel_3 = 3; +int LogLevel_4 = 4; +int LogLevel_Min = -1; +int LogLevel_Max = 4; + +// struct WalletManagerFactory +// { +// enum LogLevel { +// LogLevel_Silent = -1, +// LogLevel_0 = 0, +// LogLevel_1 = 1, +// LogLevel_2 = 2, +// LogLevel_3 = 3, +// LogLevel_4 = 4, +// LogLevel_Min = LogLevel_Silent, +// LogLevel_Max = LogLevel_4 +// }; +// static WalletManager * getWalletManager(); +extern ADDAPI void* MONERO_WalletManagerFactory_getWalletManager(); +// static void setLogLevel(int level); +extern ADDAPI void MONERO_WalletManagerFactory_setLogLevel(int level); +// static void setLogCategories(const std::string &categories); +extern ADDAPI void MONERO_WalletManagerFactory_setLogCategories(const char* categories); +// }; +// } + +extern ADDAPI void MONERO_DEBUG_test0(); +extern ADDAPI bool MONERO_DEBUG_test1(bool x); +extern ADDAPI int MONERO_DEBUG_test2(int x); +extern ADDAPI uint64_t MONERO_DEBUG_test3(uint64_t x); +extern ADDAPI void* MONERO_DEBUG_test4(uint64_t x); +extern ADDAPI const char* MONERO_DEBUG_test5(); +extern ADDAPI const char* MONERO_DEBUG_test5_std(); +extern ADDAPI bool MONERO_DEBUG_isPointerNull(void* wallet_ptr); + +// cake world + +extern ADDAPI void* MONERO_cw_getWalletListener(void* wallet_ptr); +extern ADDAPI void MONERO_cw_WalletListener_resetNeedToRefresh(void* cw_walletListener_ptr); +extern ADDAPI bool MONERO_cw_WalletListener_isNeedToRefresh(void* cw_walletListener_ptr); +extern ADDAPI bool MONERO_cw_WalletListener_isNewTransactionExist(void* cw_walletListener_ptr); +extern ADDAPI void MONERO_cw_WalletListener_resetIsNewTransactionExist(void* cw_walletListener_ptr); +extern ADDAPI uint64_t MONERO_cw_WalletListener_height(void* cw_walletListener_ptr); + +extern ADDAPI void MONERO_free(void* ptr); + +extern ADDAPI const char* MONERO_checksum_wallet2_api_c_h(); +extern ADDAPI const char* MONERO_checksum_wallet2_api_c_cpp(); +extern ADDAPI const char* MONERO_checksum_wallet2_api_c_exp(); + +#ifdef __cplusplus +} +#endif