update to monero-project v0.18.0.0

This commit is contained in:
woodser
2022-08-06 10:25:16 -04:00
parent 583a21288b
commit ff965cbfae
8 changed files with 153 additions and 133 deletions
+27 -24
View File
@@ -11,8 +11,8 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11 -F/Library/Frameworks -
project(MoneroCppLibrary)
set(BUILD_LIBRARY ON)
option(BUILD_SAMPLE "Build sample" ON)
option(BUILD_SCRATCHPAD "Build scratchpad" ON)
set(BUILD_SAMPLE ON)
set(BUILD_SCRATCHPAD ON)
###################
# monero-project
@@ -137,7 +137,6 @@ if (APPLE AND NOT IOS)
endif()
find_package(HIDAPI REQUIRED)
message(STATUS "Using HIDAPI include dir at ${HIDAPI_INCLUDE_DIR}")
add_definitions(-DHAVE_HIDAPI)
include_directories(${HIDAPI_INCLUDE_DIR})
@@ -151,10 +150,6 @@ message(STATUS "Using monero-project build" : ${MONERO_PROJECT_BUILD})
list(APPEND CMAKE_MODULE_PATH "${MONERO_PROJECT}/cmake")
add_library(wallet_merged STATIC IMPORTED)
set_target_properties(wallet_merged PROPERTIES IMPORTED_LOCATION
${MONERO_PROJECT_BUILD}/lib/libwallet_merged.a)
add_library(wallet STATIC IMPORTED)
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
${MONERO_PROJECT_BUILD}/lib/libwallet.a)
@@ -172,16 +167,24 @@ set_target_properties(epee PROPERTIES IMPORTED_LOCATION
${MONERO_PROJECT_BUILD}/contrib/epee/src/libepee.a)
find_package(Unbound)
if ("${UNBOUND_LIBRARIES}" MATCHES "libunbound.so")
if ("${UNBOUND_LIBRARIES}" MATCHES "libunbound")
message(STATUS "Using libunbound: ${UNBOUND_LIBRARIES}")
add_library(unbound SHARED IMPORTED)
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
${UNBOUND_LIBRARIES})
else()
add_library(unbound STATIC IMPORTED)
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
${MONERO_PROJECT_BUILD}/external/unbound/libunbound.a)
endif()
add_library(rpc_base STATIC IMPORTED)
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
${MONERO_PROJECT_BUILD}/src/rpc/librpc_base.a)
add_library(net STATIC IMPORTED)
set_target_properties(net PROPERTIES IMPORTED_LOCATION
${MONERO_PROJECT_BUILD}/src/net/libnet.a)
add_library(hardforks STATIC IMPORTED)
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
${MONERO_PROJECT_BUILD}/src/hardforks/libhardforks.a)
add_library(easylogging STATIC IMPORTED)
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
@@ -270,11 +273,11 @@ if (BUILD_LIBRARY)
add_library(monero-cpp SHARED ${LIBRARY_SRC_FILES})
target_link_libraries(monero-cpp
wallet_merged
wallet_crypto
#wallet_api
wallet
wallet_crypto
rpc_base
net
hardforks
lmdb
epee
unbound
@@ -333,11 +336,11 @@ if (BUILD_SAMPLE)
add_executable(sample_code ${LIBRARY_SRC_FILES} ${SAMPLE_CODE_SRC_FILES})
target_link_libraries(sample_code
wallet_merged
wallet_crypto
#wallet_api
wallet
wallet_crypto
rpc_base
net
hardforks
lmdb
epee
unbound
@@ -381,11 +384,11 @@ if (BUILD_SCRATCHPAD)
add_executable(scratchpad ${LIBRARY_SRC_FILES} ${SCRATCHPAD_SRC_FILES})
target_link_libraries(scratchpad
wallet_merged
wallet_crypto
#wallet_api
wallet
wallet_crypto
rpc_base
net
hardforks
lmdb
epee
unbound
+1 -1
View File
@@ -1,6 +1,6 @@
# Monero C++ Library
A C++ library for creating Monero applications using native bindings to [monero v0.17.3.2 'Oxygen Orion'](https://github.com/monero-project/monero/tree/v0.17.3.2).
A C++ library for creating Monero applications using native bindings to [monero v0.18.0.0 'Flourine Fermie'](https://github.com/monero-project/monero/tree/v0.18.0.0).
* Supports fully client-side wallets by wrapping [wallet2.h](https://github.com/monero-project/monero/blob/master/src/wallet/wallet2.h).
* Supports multisig, view-only, and offline wallets.
+5 -2
View File
@@ -57,6 +57,7 @@
#include "mnemonics/electrum-words.h"
#include "mnemonics/english.h"
#include "string_tools.h"
#include "byte_stream.h"
using namespace cryptonote;
using namespace monero_utils;
@@ -141,7 +142,9 @@ void monero_utils::validate_private_spend_key(const std::string& private_spend_k
void monero_utils::json_to_binary(const std::string &json, std::string &bin) {
epee::serialization::portable_storage ps;
ps.load_from_json(json);
ps.store_to_binary(bin);
epee::byte_stream bs;
ps.store_to_binary(bs);
bin = std::string((char*) bs.data(), bs.size());
}
void monero_utils::binary_to_json(const std::string &bin, std::string &json) {
@@ -347,7 +350,7 @@ std::shared_ptr<monero_tx> monero_utils::cn_tx_to_tx(const cryptonote::transacti
output->m_tx = tx;
tx->m_outputs.push_back(output);
output->m_amount = cnVout.amount;
const crypto::public_key& cnStealthPublicKey = boost::get<txout_to_key>(cnVout.target).key;
const crypto::public_key& cnStealthPublicKey = boost::get<txout_to_tagged_key>(cnVout.target).key;
output->m_stealth_public_key = epee::string_tools::pod_to_hex(cnStealthPublicKey);
}
+5 -5
View File
@@ -1160,8 +1160,8 @@ namespace monero {
* @param config specifies configuration for a potential tx
* @return is the payment uri
*/
virtual std::string create_payment_uri(const monero_tx_config& config) const {
throw std::runtime_error("create_payment_uri() not supported");
virtual std::string get_payment_uri(const monero_tx_config& config) const {
throw std::runtime_error("get_payment_uri() not supported");
}
/**
@@ -1265,9 +1265,9 @@ namespace monero {
* @param multisig_hexes are multisig hex from each participant
* @param threshold is the number of signatures needed to sign transfers
* @password is the wallet password
* @return the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not N/N
* @return this wallet's multisig hex to share with participants
*/
virtual monero_multisig_init_result make_multisig(const std::vector<std::string>& multisig_hexes, int threshold, const std::string& password) {
virtual std::string make_multisig(const std::vector<std::string>& multisig_hexes, int threshold, const std::string& password) {
throw std::runtime_error("make_multisig() not supported");
}
@@ -1280,7 +1280,7 @@ namespace monero {
* @param password is the wallet's password // TODO monero-project: redundant? wallet is created with password
* @return the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done
*/
virtual monero_multisig_init_result exchange_multisig_keys(const std::vector<std::string>& mutisig_hexes, const std::string& password) {
virtual monero_multisig_init_result exchange_multisig_keys(const std::vector<std::string>& mutisig_hexes, const std::string& password) {
throw std::runtime_error("exchange_multisig_keys() not supported");
}
+110 -96
View File
@@ -381,7 +381,7 @@ namespace monero {
output->m_subaddress_index = td.m_subaddr_index.minor;
output->m_is_spent = td.m_spent;
output->m_is_frozen = td.m_frozen;
//output->m_stealth_public_key = epee::string_tools::pod_to_hex(td.get_public_key()); // TODO (monero-wallet-rpc): provide this field
output->m_stealth_public_key = epee::string_tools::pod_to_hex(td.get_public_key());
if (td.m_key_image_known) {
output->m_key_image = std::make_shared<monero_key_image>();
output->m_key_image.get()->m_hex = epee::string_tools::pod_to_hex(td.m_key_image);
@@ -720,6 +720,7 @@ namespace monero {
}
void update_listening() {
boost::lock_guard<boost::mutex> guarg(m_listener_mutex);
// if starting to listen, cache locked txs for later comparison
if (!m_wallet.get_listeners().empty() && m_w2.callback() == nullptr) check_for_changed_unlocked_txs();
@@ -785,72 +786,80 @@ namespace monero {
// queue notification processing off main thread
tools::threadpool::waiter waiter(*m_notification_pool);
m_notification_pool->submit(&waiter, [this, height, txid, cn_tx, amount, subaddr_index]() {
try {
// create library tx
std::shared_ptr<monero_tx_wallet> tx = std::static_pointer_cast<monero_tx_wallet>(monero_utils::cn_tx_to_tx(cn_tx, true));
tx->m_hash = epee::string_tools::pod_to_hex(txid);
tx->m_is_confirmed = false;
tx->m_is_locked = true;
std::shared_ptr<monero_output_wallet> output = std::make_shared<monero_output_wallet>();
tx->m_outputs.push_back(output);
output->m_tx = tx;
output->m_amount = amount;
output->m_account_index = subaddr_index.major;
output->m_subaddress_index = subaddr_index.minor;
// create library tx
std::shared_ptr<monero_tx_wallet> tx = std::static_pointer_cast<monero_tx_wallet>(monero_utils::cn_tx_to_tx(cn_tx, true));
tx->m_hash = epee::string_tools::pod_to_hex(txid);
tx->m_is_confirmed = false;
tx->m_is_locked = true;
std::shared_ptr<monero_output_wallet> output = std::make_shared<monero_output_wallet>();
tx->m_outputs.push_back(output);
output->m_tx = tx;
output->m_amount = amount;
output->m_account_index = subaddr_index.major;
output->m_subaddress_index = subaddr_index.minor;
// notify listeners of output
for (monero_wallet_listener* listener : m_wallet.get_listeners()) {
listener->on_output_received(*output);
// notify listeners of output
for (monero_wallet_listener* listener : m_wallet.get_listeners()) {
listener->on_output_received(*output);
}
// notify if balances changed
check_for_changed_balances();
// watch for unlock
m_prev_locked_tx_hashes.insert(tx->m_hash.get());
// free memory
output.reset();
tx.reset();
} catch (std::exception& e) {
std::cout << "Error processing unconfirmed output received: " << std::string(e.what()) << std::endl;
}
// notify if balances changed
check_for_changed_balances();
// watch for unlock
m_prev_locked_tx_hashes.insert(tx->m_hash.get());
// free memory
output.reset();
tx.reset();
});
}
void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& cn_tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_height) override {
void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& cn_tx, uint64_t amount, uint64_t burnt, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_height) override {
if (m_wallet.get_listeners().empty()) return;
// queue notification processing off main thread
tools::threadpool::waiter waiter(*m_notification_pool);
m_notification_pool->submit(&waiter, [this, height, txid, cn_tx, amount, subaddr_index, is_change, unlock_height]() {
m_notification_pool->submit(&waiter, [this, height, txid, cn_tx, amount, burnt, subaddr_index, is_change, unlock_height]() {
try {
// create native library tx
std::shared_ptr<monero_block> block = std::make_shared<monero_block>();
block->m_height = height;
std::shared_ptr<monero_tx_wallet> tx = std::static_pointer_cast<monero_tx_wallet>(monero_utils::cn_tx_to_tx(cn_tx, true));
block->m_txs.push_back(tx);
tx->m_block = block;
tx->m_hash = epee::string_tools::pod_to_hex(txid);
tx->m_is_confirmed = true;
tx->m_is_locked = true;
tx->m_unlock_height = unlock_height;
std::shared_ptr<monero_output_wallet> output = std::make_shared<monero_output_wallet>();
tx->m_outputs.push_back(output);
output->m_tx = tx;
output->m_amount = amount;
output->m_account_index = subaddr_index.major;
output->m_subaddress_index = subaddr_index.minor;
// create native library tx
std::shared_ptr<monero_block> block = std::make_shared<monero_block>();
block->m_height = height;
std::shared_ptr<monero_tx_wallet> tx = std::static_pointer_cast<monero_tx_wallet>(monero_utils::cn_tx_to_tx(cn_tx, true));
block->m_txs.push_back(tx);
tx->m_block = block;
tx->m_hash = epee::string_tools::pod_to_hex(txid);
tx->m_is_confirmed = true;
tx->m_is_locked = true;
tx->m_unlock_height = unlock_height;
std::shared_ptr<monero_output_wallet> output = std::make_shared<monero_output_wallet>();
tx->m_outputs.push_back(output);
output->m_tx = tx;
output->m_amount = amount - burnt;
output->m_account_index = subaddr_index.major;
output->m_subaddress_index = subaddr_index.minor;
// notify listeners of output
for (monero_wallet_listener* listener : m_wallet.get_listeners()) {
listener->on_output_received(*output);
// notify listeners of output
for (monero_wallet_listener* listener : m_wallet.get_listeners()) {
listener->on_output_received(*output);
}
// watch for unlock
m_prev_locked_tx_hashes.insert(tx->m_hash.get());
// free memory
monero_utils::free(block);
output.reset();
tx.reset();
} catch (std::exception& e) {
std::cout << "Error processing confirmed output received: " << std::string(e.what()) << std::endl;
}
// watch for unlock
m_prev_locked_tx_hashes.insert(tx->m_hash.get());
// free memory
monero_utils::free(block);
output.reset();
tx.reset();
});
}
@@ -861,35 +870,39 @@ namespace monero {
// queue notification processing off main thread
tools::threadpool::waiter waiter(*m_notification_pool);
m_notification_pool->submit(&waiter, [this, height, txid, cn_tx_in, amount, cn_tx_out, subaddr_index]() {
try {
// create native library tx
std::shared_ptr<monero_block> block = std::make_shared<monero_block>();
block->m_height = height;
std::shared_ptr<monero_tx_wallet> tx = std::static_pointer_cast<monero_tx_wallet>(monero_utils::cn_tx_to_tx(cn_tx_in, true));
block->m_txs.push_back(tx);
tx->m_block = block;
tx->m_hash = epee::string_tools::pod_to_hex(txid);
tx->m_is_confirmed = true;
tx->m_is_locked = true;
std::shared_ptr<monero_output_wallet> output = std::make_shared<monero_output_wallet>();
tx->m_inputs.push_back(output);
output->m_tx = tx;
output->m_amount = amount;
output->m_account_index = subaddr_index.major;
output->m_subaddress_index = subaddr_index.minor;
// create native library tx
std::shared_ptr<monero_block> block = std::make_shared<monero_block>();
block->m_height = height;
std::shared_ptr<monero_tx_wallet> tx = std::static_pointer_cast<monero_tx_wallet>(monero_utils::cn_tx_to_tx(cn_tx_in, true));
block->m_txs.push_back(tx);
tx->m_block = block;
tx->m_hash = epee::string_tools::pod_to_hex(txid);
tx->m_is_confirmed = true;
tx->m_is_locked = true;
std::shared_ptr<monero_output_wallet> output = std::make_shared<monero_output_wallet>();
tx->m_inputs.push_back(output);
output->m_tx = tx;
output->m_amount = amount;
output->m_account_index = subaddr_index.major;
output->m_subaddress_index = subaddr_index.minor;
// notify listeners of output
for (monero_wallet_listener* listener : m_wallet.get_listeners()) {
listener->on_output_spent(*output);
// notify listeners of output
for (monero_wallet_listener* listener : m_wallet.get_listeners()) {
listener->on_output_spent(*output);
}
// watch for unlock
m_prev_locked_tx_hashes.insert(tx->m_hash.get());
// free memory
monero_utils::free(block);
output.reset();
tx.reset();
} catch (std::exception& e) {
std::cout << "Error processing confirmed output spent: " << std::string(e.what()) << std::endl;
}
// watch for unlock
m_prev_locked_tx_hashes.insert(tx->m_hash.get());
// free memory
monero_utils::free(block);
output.reset();
tx.reset();
});
}
@@ -917,6 +930,7 @@ namespace monero {
tools::wallet2& m_w2; // internal wallet implementation to listen to
boost::optional<uint64_t> m_sync_start_height;
boost::optional<uint64_t> m_sync_end_height;
boost::mutex m_listener_mutex;
uint64_t m_prev_balance;
uint64_t m_prev_unlocked_balance;
std::set<std::string> m_prev_locked_tx_hashes;
@@ -1326,7 +1340,7 @@ namespace monero {
// validate standard address
cryptonote::address_parse_info info;
if (!cryptonote::get_account_address_from_str(info, m_w2->nettype(), standard_address)) throw std::runtime_error("Invalid address: " + standard_address);
if (!cryptonote::get_account_address_from_str(info, m_w2->nettype(), standard_address)) throw std::runtime_error("Invalid address");
if (info.is_subaddress) throw std::runtime_error("Subaddress shouldn't be used");
if (info.has_payment_id) throw std::runtime_error("Already integrated address");
if (payment_id.empty()) throw std::runtime_error("Payment ID shouldn't be left unspecified");
@@ -1341,7 +1355,7 @@ namespace monero {
// validate integrated address
cryptonote::address_parse_info info;
if (!cryptonote::get_account_address_from_str(info, m_w2->nettype(), integrated_address)) throw std::runtime_error("Invalid integrated address: " + integrated_address);
if (!cryptonote::get_account_address_from_str(info, m_w2->nettype(), integrated_address)) throw std::runtime_error("Invalid address");
if (!info.has_payment_id) throw std::runtime_error("Address is not an integrated address");
// initialize and return result
@@ -1942,7 +1956,6 @@ namespace monero {
if (tx->m_is_relayed.get()) tx->m_last_relayed_timestamp = static_cast<uint64_t>(time(NULL)); // set last relayed timestamp to current time iff relayed // TODO monero-project: this should be encapsulated in wallet2
out_transfer->m_account_index = config.m_account_index;
if (config.m_subaddress_indices.size() == 1) out_transfer->m_subaddress_indices.push_back(config.m_subaddress_indices[0]); // subaddress index is known iff 1 requested // TODO: get all known subaddress indices here
out_transfer->m_destinations = config.get_normalized_destinations();
// iterate to next element
tx_keys_iter++;
@@ -1954,6 +1967,9 @@ namespace monero {
input_key_images_list_iter++;
}
// copy destinations if single tx
if (txs.size() == 1) txs[0]->m_outgoing_transfer.get()->m_destinations = config.get_normalized_destinations();
// build tx set
std::shared_ptr<monero_tx_set> tx_set = std::make_shared<monero_tx_set>();
tx_set->m_txs = txs;
@@ -2424,8 +2440,7 @@ namespace monero {
bool loaded = false;
tools::wallet2::pending_tx ptx;
try {
std::istringstream iss(blob);
binary_archive<false> ar(iss);
binary_archive<false> ar{epee::strspan<std::uint8_t>(blob)};
if (::serialization::serialize(ar, ptx)) loaded = true;
} catch (...) {}
if (!loaded) {
@@ -3014,8 +3029,8 @@ namespace monero {
if (!m_w2->delete_address_book_row(index)) throw std::runtime_error("Failed to delete address book entry");
}
std::string monero_wallet_full::create_payment_uri(const monero_tx_config& config) const {
MTRACE("create_payment_uri()");
std::string monero_wallet_full::get_payment_uri(const monero_tx_config& config) const {
MTRACE("get_payment_uri()");
// validate config
std::vector<std::shared_ptr<monero_destination>> destinations = config.get_normalized_destinations();
@@ -3158,17 +3173,15 @@ namespace monero {
std::string monero_wallet_full::prepare_multisig() {
if (m_w2->multisig()) throw std::runtime_error("This wallet is already multisig");
if (m_w2->watch_only()) throw std::runtime_error("This wallet is view-only and cannot be made multisig");
m_w2->enable_multisig(true);
return m_w2->get_multisig_first_kex_msg();
}
monero_multisig_init_result monero_wallet_full::make_multisig(const std::vector<std::string>& multisig_hexes, int threshold, const std::string& password) {
std::string monero_wallet_full::make_multisig(const std::vector<std::string>& multisig_hexes, int threshold, const std::string& password) {
if (m_w2->multisig()) throw std::runtime_error("This wallet is already multisig");
if (m_w2->watch_only()) throw std::runtime_error("This wallet is view-only and cannot be made multisig");
boost::lock_guard<boost::mutex> guarg(m_sync_mutex); // do not refresh while making multisig
monero_multisig_init_result result;
result.m_multisig_hex = m_w2->make_multisig(epee::wipeable_string(password), multisig_hexes, threshold);
result.m_address = m_w2->get_account().get_public_address_str(m_w2->nettype());
return result;
return m_w2->make_multisig(epee::wipeable_string(password), multisig_hexes, threshold);
}
monero_multisig_init_result monero_wallet_full::exchange_multisig_keys(const std::vector<std::string>& multisig_hexes, const std::string& password) {
@@ -3178,7 +3191,7 @@ namespace monero {
uint32_t threshold, total;
if (!m_w2->multisig(&ready, &threshold, &total)) throw std::runtime_error("This wallet is not multisig");
if (ready) throw std::runtime_error("This wallet is multisig, and already finalized");
if (multisig_hexes.size() < 1 || multisig_hexes.size() > total) throw std::runtime_error("Needs multisig info from more participants");
if (multisig_hexes.size() + 1 < total) throw std::runtime_error("Needs multisig info from more participants");
// do not refresh while exchanging multisig keys
boost::lock_guard<boost::mutex> guarg(m_sync_mutex);
@@ -3186,10 +3199,11 @@ namespace monero {
// import peer multisig keys and get multisig hex to be shared next round
std::string multisig_hex = m_w2->exchange_multisig_keys(epee::wipeable_string(password), multisig_hexes);
// build and return the exchange result
// build and return exchange result
monero_multisig_init_result result;
if (!multisig_hex.empty()) result.m_multisig_hex = multisig_hex;
else result.m_address = m_w2->get_account().get_public_address_str(m_w2->nettype()); // only return address on completion
m_w2->multisig(&ready);
result.m_multisig_hex = multisig_hex;
if (ready) result.m_address = m_w2->get_account().get_public_address_str(m_w2->nettype());
return result;
}
+2 -2
View File
@@ -258,7 +258,7 @@ namespace monero {
uint64_t add_address_book_entry(const std::string& address, const std::string& description) override;
void edit_address_book_entry(uint64_t index, bool set_address, const std::string& address, bool set_description, const std::string& description) override;
void delete_address_book_entry(uint64_t index) override;
std::string create_payment_uri(const monero_tx_config& config) const override;
std::string get_payment_uri(const monero_tx_config& config) const override;
std::shared_ptr<monero_tx_config> parse_payment_uri(const std::string& uri) const override;
bool get_attribute(const std::string& key, std::string& value) const override;
void set_attribute(const std::string& key, const std::string& val) override;
@@ -268,7 +268,7 @@ namespace monero {
bool is_multisig_import_needed() const override;
monero_multisig_info get_multisig_info() const override;
std::string prepare_multisig() override;
monero_multisig_init_result make_multisig(const std::vector<std::string>& multisig_hexes, int threshold, const std::string& password) override;
std::string make_multisig(const std::vector<std::string>& multisig_hexes, int threshold, const std::string& password) override;
monero_multisig_init_result exchange_multisig_keys(const std::vector<std::string>& mutisig_hexes, const std::string& password) override;
std::string export_multisig_hex() override;
int import_multisig_hex(const std::vector<std::string>& multisig_hexes) override;
+2 -2
View File
@@ -688,8 +688,8 @@ namespace monero {
// TODO monero-project: failed tx in pool (after testUpdateLockedDifferentAccounts()) causes non-originating saved wallets to return duplicate incoming transfers but one has amount of 0
if (m_amount != boost::none && other->m_amount != boost::none && *m_amount != *other->m_amount && (*m_amount == 0 || *other->m_amount == 0)) {
std::cout << "WARNING: failed tx in pool causes non-originating wallets to return duplicate incoming transfers but with one amount/m_num_suggested_confirmations of 0, using non-zero amount" << std::endl;
if (*m_amount == 0) m_amount = other->m_amount;
std::cout << "WARNING: monero-project returning transfers with 0 amount/numSuggestedConfirmations" << std::endl;
//if (*m_amount == 0) m_amount = *other->m_amount;
} else {
m_amount = gen_utils::reconcile(m_amount, other->m_amount, "transfer amount");
}