aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt29
-rw-r--r--LICENSE31
-rw-r--r--Makefile8
-rw-r--r--README.md16
-rw-r--r--cmake/MergeStaticLibs.cmake129
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.h2
-rw-r--r--src/common/stack_trace.cpp2
-rw-r--r--src/simplewallet/simplewallet.cpp2
-rw-r--r--src/wallet/CMakeLists.txt34
-rw-r--r--src/wallet/api/common_defines.h7
-rw-r--r--src/wallet/api/pending_transaction.cpp138
-rw-r--r--src/wallet/api/pending_transaction.h64
-rw-r--r--src/wallet/api/transaction_history.cpp194
-rw-r--r--src/wallet/api/transaction_history.h57
-rw-r--r--src/wallet/api/transaction_info.cpp112
-rw-r--r--src/wallet/api/transaction_info.h75
-rw-r--r--src/wallet/api/utils.cpp79
-rw-r--r--src/wallet/api/wallet.cpp588
-rw-r--r--src/wallet/api/wallet.h103
-rw-r--r--src/wallet/api/wallet_manager.cpp142
-rw-r--r--src/wallet/api/wallet_manager.h56
-rw-r--r--src/wallet/wallet2.cpp128
-rw-r--r--src/wallet/wallet2.h2
-rw-r--r--src/wallet/wallet2_api.cpp346
-rw-r--r--src/wallet/wallet2_api.h176
-rw-r--r--tests/libwallet_api_tests/main.cpp513
-rwxr-xr-xtests/libwallet_api_tests/scripts/create_wallets.sh20
-rwxr-xr-xtests/libwallet_api_tests/scripts/mining_start.sh4
-rwxr-xr-xtests/libwallet_api_tests/scripts/mining_stop.sh4
-rwxr-xr-xtests/libwallet_api_tests/scripts/open_wallet_1.sh5
-rwxr-xr-xtests/libwallet_api_tests/scripts/open_wallet_2.sh5
-rwxr-xr-xtests/libwallet_api_tests/scripts/open_wallet_3.sh4
-rwxr-xr-xtests/libwallet_api_tests/scripts/open_wallet_4.sh4
-rwxr-xr-xtests/libwallet_api_tests/scripts/open_wallet_5.sh4
-rwxr-xr-xtests/libwallet_api_tests/scripts/open_wallet_miner.sh4
-rwxr-xr-xtests/libwallet_api_tests/scripts/send_funds.sh22
36 files changed, 2624 insertions, 485 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9e99e5a51..6b9c81895 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,7 +45,12 @@ function (die msg)
message(FATAL_ERROR "${BoldRed}${msg}${ColourReset}")
endfunction ()
-if (NOT ${ARCH} STREQUAL "")
+if ("${ARCH}" STREQUAL "" OR "${ARCH}" STREQUAL "native")
+ set(ARCH ${CMAKE_SYSTEM_PROCESSOR})
+ message(STATUS "Building natively on ${ARCH}")
+endif()
+
+if (NOT "${ARCH}" STREQUAL "")
string(SUBSTRING ${ARCH} 0 3 IS_ARM)
string(TOLOWER ${IS_ARM} IS_ARM)
@@ -323,7 +328,7 @@ else()
endif()
if(MINGW)
set(WARNINGS "${WARNINGS} -Wno-error=unused-value -Wno-error=unused-but-set-variable")
- set(MINGW_FLAG "${MINGW_FLAG} -DWIN32_LEAN_AND_MEAN -D_POSIX_C_SOURCE")
+ set(MINGW_FLAG "${MINGW_FLAG} -DWIN32_LEAN_AND_MEAN")
set(Boost_THREADAPI win32)
include_directories(SYSTEM src/platform/mingw)
# mingw doesn't support LTO (multiple definition errors at link time)
@@ -342,16 +347,19 @@ else()
set(STATIC_ASSERT_FLAG "-Dstatic_assert=_Static_assert")
endif()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}")
+
option(NO_AES "Explicitly disable AES support" ${NO_AES})
- if (NO_AES)
- message(STATUS "Disabling AES support")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}")
+ if(NOT NO_AES AND NOT (ARM6 OR ARM7))
+ message(STATUS "AES support enabled")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
+ elseif(ARM7 OR ARM6)
+ message(STATUS "AES support disabled (not available on ARM)")
else()
- message(STATUS "Enabling AES support")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} -maes")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} -maes")
+ message(STATUS "AES support disabled")
endif()
if(ARM6)
@@ -455,6 +463,9 @@ include(version.cmake)
add_subdirectory(contrib)
add_subdirectory(src)
+
+option(BUILD_TESTS "Build tests." OFF)
+
if(BUILD_TESTS)
add_subdirectory(tests)
endif()
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..3bc2ed2cf
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,31 @@
+Copyright (c) 2014-2016, 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.
+
+Parts of the project are originally copyright (c) 2012-2013 The Cryptonote
+developers
diff --git a/Makefile b/Makefile
index b02f92ad5..69d1127de 100644
--- a/Makefile
+++ b/Makefile
@@ -58,14 +58,6 @@ release-all:
mkdir -p build/release
cd build/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
-release-arm6:
- mkdir -p build/release
- cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv6zk" -D BUILD_64=OFF -D NO_AES=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
-
-release-arm7:
- mkdir -p build/release
- cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D BUILD_64=OFF -D NO_AES=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
-
release-static: release-static-64
release-static-64:
diff --git a/README.md b/README.md
index 81d5d75da..d78d08e1d 100644
--- a/README.md
+++ b/README.md
@@ -47,21 +47,7 @@ There are also several mining pools that kindly donate a portion of their fees,
## License
-Copyright (c) 2014-2016, 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.
-
-Parts of the project are originally copyright (c) 2012-2013 The Cryptonote developers
+See [LICENSE](LICENSE).
## Compiling Monero
diff --git a/cmake/MergeStaticLibs.cmake b/cmake/MergeStaticLibs.cmake
new file mode 100644
index 000000000..858a026a3
--- /dev/null
+++ b/cmake/MergeStaticLibs.cmake
@@ -0,0 +1,129 @@
+# Copyright (C) 2012 Modelon AB
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the BSD style license.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# FMILIB_License.txt file for more details.
+
+# You should have received a copy of the FMILIB_License.txt file
+# along with this program. If not, contact Modelon AB <http://www.modelon.com>.
+
+# Merge_static_libs(outlib lib1 lib2 ... libn) merges a number of static
+# libs into a single static library
+function(merge_static_libs outlib )
+ set(libs ${ARGV})
+ list(REMOVE_AT libs 0)
+# Create a dummy file that the target will depend on
+ set(dummyfile ${CMAKE_CURRENT_BINARY_DIR}/${outlib}_dummy.c)
+ file(WRITE ${dummyfile} "const char * dummy = \"${dummyfile}\";")
+
+ add_library(${outlib} STATIC ${dummyfile})
+
+ if("${CMAKE_CFG_INTDIR}" STREQUAL ".")
+ set(multiconfig FALSE)
+ else()
+ set(multiconfig TRUE)
+ endif()
+
+# First get the file names of the libraries to be merged
+ foreach(lib ${libs})
+ get_target_property(libtype ${lib} TYPE)
+ if(NOT libtype STREQUAL "STATIC_LIBRARY")
+ message(FATAL_ERROR "Merge_static_libs can only process static libraries")
+ endif()
+ if(multiconfig)
+ foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES})
+ get_target_property("libfile_${CONFIG_TYPE}" ${lib} "LOCATION_${CONFIG_TYPE}")
+ list(APPEND libfiles_${CONFIG_TYPE} ${libfile_${CONFIG_TYPE}})
+ endforeach()
+ else()
+ get_target_property(libfile ${lib} LOCATION)
+ list(APPEND libfiles "${libfile}")
+ endif(multiconfig)
+ endforeach()
+ message(STATUS "will be merging ${libfiles}")
+# Just to be sure: cleanup from duplicates
+ if(multiconfig)
+ foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES})
+ list(REMOVE_DUPLICATES libfiles_${CONFIG_TYPE})
+ set(libfiles ${libfiles} ${libfiles_${CONFIG_TYPE}})
+ endforeach()
+ endif()
+ list(REMOVE_DUPLICATES libfiles)
+
+# Now the easy part for MSVC and for MAC
+ if(MSVC)
+ # lib.exe does the merging of libraries just need to conver the list into string
+ foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES})
+ set(flags "")
+ foreach(lib ${libfiles_${CONFIG_TYPE}})
+ set(flags "${flags} ${lib}")
+ endforeach()
+ string(TOUPPER "STATIC_LIBRARY_FLAGS_${CONFIG_TYPE}" PROPNAME)
+ set_target_properties(${outlib} PROPERTIES ${PROPNAME} "${flags}")
+ endforeach()
+
+ elseif(APPLE)
+ # Use OSX's libtool to merge archives
+ if(multiconfig)
+ message(FATAL_ERROR "Multiple configurations are not supported")
+ endif()
+ get_target_property(outfile ${outlib} LOCATION)
+ add_custom_command(TARGET ${outlib} POST_BUILD
+ COMMAND rm ${outfile}
+ COMMAND /usr/bin/libtool -static -o ${outfile}
+ ${libfiles}
+ )
+ else()
+ # general UNIX - need to "ar -x" and then "ar -ru"
+ if(multiconfig)
+ message(FATAL_ERROR "Multiple configurations are not supported")
+ endif()
+ get_target_property(outfile ${outlib} LOCATION)
+ message(STATUS "outfile location is ${outfile}")
+ foreach(lib ${libfiles})
+# objlistfile will contain the list of object files for the library
+ set(objlistfile ${lib}.objlist)
+ set(objdir ${lib}.objdir)
+ set(objlistcmake ${objlistfile}.cmake)
+# we only need to extract files once
+ if(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/cmake.check_cache IS_NEWER_THAN ${objlistcmake})
+#---------------------------------
+ FILE(WRITE ${objlistcmake}
+"# Extract object files from the library
+message(STATUS \"Extracting object files from ${lib}\")
+EXECUTE_PROCESS(COMMAND ${CMAKE_AR} -x ${lib}
+ WORKING_DIRECTORY ${objdir})
+# save the list of object files
+EXECUTE_PROCESS(COMMAND ls .
+ OUTPUT_FILE ${objlistfile}
+ WORKING_DIRECTORY ${objdir})")
+#---------------------------------
+ file(MAKE_DIRECTORY ${objdir})
+ add_custom_command(
+ OUTPUT ${objlistfile}
+ COMMAND ${CMAKE_COMMAND} -P ${objlistcmake}
+ DEPENDS ${lib})
+ endif()
+ list(APPEND extrafiles "${objlistfile}")
+ # relative path is needed by ar under MSYS
+ file(RELATIVE_PATH objlistfilerpath ${objdir} ${objlistfile})
+ add_custom_command(TARGET ${outlib} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "Running: ${CMAKE_AR} ru ${outfile} @${objlistfilerpath}"
+ COMMAND ${CMAKE_AR} ru "${outfile}" @"${objlistfilerpath}"
+ WORKING_DIRECTORY ${objdir})
+ endforeach()
+ add_custom_command(TARGET ${outlib} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "Running: ${CMAKE_RANLIB} ${outfile}"
+ COMMAND ${CMAKE_RANLIB} ${outfile})
+ endif()
+ file(WRITE ${dummyfile}.base "const char* ${outlib}_sublibs=\"${libs}\";")
+ add_custom_command(
+ OUTPUT ${dummyfile}
+ COMMAND ${CMAKE_COMMAND} -E copy ${dummyfile}.base ${dummyfile}
+ DEPENDS ${libs} ${extrafiles})
+
+ endfunction() \ No newline at end of file
diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h
index 80f3f6db0..cb387d39f 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.h
+++ b/contrib/epee/include/net/abstract_tcp_server2.h
@@ -95,7 +95,7 @@ namespace net_utils
i_connection_filter * &pfilter
,t_connection_type connection_type);
- virtual ~connection();
+ virtual ~connection() noexcept(false);
/// Get the socket associated with the connection.
boost::asio::ip::tcp::socket& socket();
diff --git a/src/common/stack_trace.cpp b/src/common/stack_trace.cpp
index 2805e7604..0d2ccb39d 100644
--- a/src/common/stack_trace.cpp
+++ b/src/common/stack_trace.cpp
@@ -33,7 +33,9 @@
#include <libunwind.h>
#endif
#include <cxxabi.h>
+#ifndef STATICLIB
#include <dlfcn.h>
+#endif
// from http://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c
#ifdef STATICLIB
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 2ae42324c..4144c0b71 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -3077,7 +3077,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
}
LOCK_REFRESH_THREAD_SCOPE();
-
+
// optional in/out selector
if (local_args.size() > 0) {
if (local_args[0] == "in" || local_args[0] == "incoming") {
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index a6fc37dec..0b8fe4cb1 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -26,15 +26,24 @@
# 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 (${PROJECT_SOURCE_DIR}/cmake/libutils.cmake)
+include (${PROJECT_SOURCE_DIR}/cmake/MergeStaticLibs.cmake)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(wallet_sources
wallet2.cpp
wallet_rpc_server.cpp
- wallet2_api.cpp)
+ api/wallet.cpp
+ api/wallet_manager.cpp
+ api/transaction_info.cpp
+ api/transaction_history.cpp
+ api/pending_transaction.cpp
+ api/utils.cpp)
-set(wallet_headers)
+set(wallet_api_headers
+ wallet2_api.h)
+
set(wallet_private_headers
wallet2.h
@@ -42,13 +51,18 @@ set(wallet_private_headers
wallet_rpc_server.h
wallet_rpc_server_commands_defs.h
wallet_rpc_server_error_codes.h
- wallet2_api.h)
+ api/wallet.h
+ api/wallet_manager.h
+ api/transaction_info.h
+ api/transaction_history.h
+ api/pending_transaction.h
+ api/common_defines.h)
bitmonero_private_headers(wallet
${wallet_private_headers})
bitmonero_add_library(wallet
${wallet_sources}
- ${wallet_headers}
+ ${wallet_api_headers}
${wallet_private_headers})
target_link_libraries(wallet
LINK_PUBLIC
@@ -61,3 +75,15 @@ target_link_libraries(wallet
${Boost_REGEX_LIBRARY}
${EXTRA_LIBRARIES})
+
+set(libs_to_merge wallet cryptonote_core mnemonics common crypto)
+#MERGE_STATIC_LIBS(wallet_merged wallet_merged "${libs_to_merge}")
+merge_static_libs(wallet_merged "${libs_to_merge}")
+
+install(TARGETS wallet_merged
+ ARCHIVE DESTINATION lib)
+
+install(FILES ${wallet_api_headers}
+ DESTINATION include/wallet)
+
+
diff --git a/src/wallet/api/common_defines.h b/src/wallet/api/common_defines.h
new file mode 100644
index 000000000..60a40a45a
--- /dev/null
+++ b/src/wallet/api/common_defines.h
@@ -0,0 +1,7 @@
+#ifndef WALLET_API_COMMON_DEFINES_H__
+#define WALLET_API_COMMON_DEFINES_H__
+
+#define tr(x) (x)
+
+#endif
+
diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp
new file mode 100644
index 000000000..c4a770f87
--- /dev/null
+++ b/src/wallet/api/pending_transaction.cpp
@@ -0,0 +1,138 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include "pending_transaction.h"
+#include "wallet.h"
+#include "common_defines.h"
+
+#include "cryptonote_core/cryptonote_format_utils.h"
+#include "cryptonote_core/cryptonote_basic_impl.h"
+#include "cryptonote_core/cryptonote_format_utils.h"
+
+#include <memory>
+#include <vector>
+#include <sstream>
+#include <boost/format.hpp>
+
+using namespace std;
+
+namespace Bitmonero {
+
+PendingTransaction::~PendingTransaction() {}
+
+
+PendingTransactionImpl::PendingTransactionImpl(WalletImpl &wallet)
+ : m_wallet(wallet)
+{
+
+}
+
+PendingTransactionImpl::~PendingTransactionImpl()
+{
+
+}
+
+int PendingTransactionImpl::status() const
+{
+ return m_status;
+}
+
+string PendingTransactionImpl::errorString() const
+{
+ return m_errorString;
+}
+
+bool PendingTransactionImpl::commit()
+{
+
+ LOG_PRINT_L0("m_pending_tx size: " << m_pending_tx.size());
+ assert(m_pending_tx.size() == 1);
+ try {
+ while (!m_pending_tx.empty()) {
+ auto & ptx = m_pending_tx.back();
+ m_wallet.m_wallet->commit_tx(ptx);
+ // success_msg_writer(true) << tr("Money successfully sent, transaction ") << get_transaction_hash(ptx.tx);
+ // if no exception, remove element from vector
+ m_pending_tx.pop_back();
+ } // TODO: extract method;
+ } catch (const tools::error::daemon_busy&) {
+ // TODO: make it translatable with "tr"?
+ m_errorString = tr("daemon is busy. Please try again later.");
+ m_status = Status_Error;
+ } catch (const tools::error::no_connection_to_daemon&) {
+ m_errorString = tr("no connection to daemon. Please make sure daemon is running.");
+ m_status = Status_Error;
+ } catch (const tools::error::tx_rejected& e) {
+ std::ostringstream writer(m_errorString);
+ writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
+ m_status = Status_Error;
+ } catch (std::exception &e) {
+ m_errorString = string(tr("Unknown exception: ")) + e.what();
+ m_status = Status_Error;
+ } catch (...) {
+ m_errorString = tr("Unhandled exception");
+ LOG_ERROR(m_errorString);
+ m_status = Status_Error;
+ }
+
+ return m_status == Status_Ok;
+}
+
+uint64_t PendingTransactionImpl::amount() const
+{
+ uint64_t result = 0;
+ for (const auto &ptx : m_pending_tx) {
+ for (const auto &dest : ptx.dests) {
+ result += dest.amount;
+ }
+ }
+ return result;
+}
+
+uint64_t PendingTransactionImpl::dust() const
+{
+ uint32_t result = 0;
+ for (const auto & ptx : m_pending_tx) {
+ result += ptx.dust;
+ }
+ return result;
+}
+
+uint64_t PendingTransactionImpl::fee() const
+{
+ uint32_t result = 0;
+ for (const auto ptx : m_pending_tx) {
+ result += ptx.fee;
+ }
+ return result;
+}
+
+}
+
diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h
new file mode 100644
index 000000000..8e09bec91
--- /dev/null
+++ b/src/wallet/api/pending_transaction.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include "wallet/wallet2_api.h"
+#include "wallet/wallet2.h"
+
+#include <string>
+#include <vector>
+
+
+namespace Bitmonero {
+
+class WalletImpl;
+class PendingTransactionImpl : public PendingTransaction
+{
+public:
+ PendingTransactionImpl(WalletImpl &wallet);
+ ~PendingTransactionImpl();
+ int status() const;
+ std::string errorString() const;
+ bool commit();
+ uint64_t amount() const;
+ uint64_t dust() const;
+ uint64_t fee() const;
+ // TODO: continue with interface;
+
+private:
+ friend class WalletImpl;
+ WalletImpl &m_wallet;
+
+ int m_status;
+ std::string m_errorString;
+ std::vector<tools::wallet2::pending_tx> m_pending_tx;
+};
+
+
+}
diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp
new file mode 100644
index 000000000..db42e2141
--- /dev/null
+++ b/src/wallet/api/transaction_history.cpp
@@ -0,0 +1,194 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+
+#include "transaction_history.h"
+#include "transaction_info.h"
+#include "wallet.h"
+
+#include "crypto/hash.h"
+#include "wallet/wallet2.h"
+
+
+#include <string>
+#include <list>
+
+using namespace epee;
+
+namespace Bitmonero {
+
+TransactionHistory::~TransactionHistory() {}
+
+
+TransactionHistoryImpl::TransactionHistoryImpl(WalletImpl *wallet)
+ : m_wallet(wallet)
+{
+
+}
+
+TransactionHistoryImpl::~TransactionHistoryImpl()
+{
+
+}
+
+int TransactionHistoryImpl::count() const
+{
+ return m_history.size();
+}
+
+TransactionInfo *TransactionHistoryImpl::transaction(const std::string &id) const
+{
+ return nullptr;
+}
+
+std::vector<TransactionInfo *> TransactionHistoryImpl::getAll() const
+{
+ return m_history;
+}
+
+void TransactionHistoryImpl::refresh()
+{
+ // TODO: configurable values;
+ uint64_t min_height = 0;
+ uint64_t max_height = (uint64_t)-1;
+
+ // delete old transactions;
+ for (auto t : m_history)
+ delete t;
+ m_history.clear();
+
+
+
+ // transactions are stored in wallet2:
+ // - confirmed_transfer_details - out transfers
+ // - unconfirmed_transfer_details - pending out transfers
+ // - payment_details - input transfers
+
+ // payments are "input transactions";
+ // one input transaction contains only one transfer. e.g. <transaction_id> - <100XMR>
+
+ std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> in_payments;
+ m_wallet->m_wallet->get_payments(in_payments, min_height, max_height);
+ for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = in_payments.begin(); i != in_payments.end(); ++i) {
+ const tools::wallet2::payment_details &pd = i->second;
+ std::string payment_id = string_tools::pod_to_hex(i->first);
+ if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
+ payment_id = payment_id.substr(0,16);
+ // TODO
+ TransactionInfoImpl * ti = new TransactionInfoImpl();
+ ti->m_paymentid = payment_id;
+ ti->m_amount = pd.m_amount;
+ ti->m_direction = TransactionInfo::Direction_In;
+ ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash);
+ ti->m_blockheight = pd.m_block_height;
+ // TODO:
+ // ti->m_timestamp = pd.m_timestamp;
+ m_history.push_back(ti);
+
+ /* output.insert(std::make_pair(pd.m_block_height, std::make_pair(true, (boost::format("%20.20s %s %s %s")
+ % print_money(pd.m_amount)
+ % string_tools::pod_to_hex(pd.m_tx_hash)
+ % payment_id % "-").str()))); */
+ }
+
+ // confirmed output transactions
+ // one output transaction may contain more than one money transfer, e.g.
+ // <transaction_id>:
+ // transfer1: 100XMR to <address_1>
+ // transfer2: 50XMR to <address_2>
+ // fee: fee charged per transaction
+ //
+
+ std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> out_payments;
+ m_wallet->m_wallet->get_payments_out(out_payments, min_height, max_height);
+
+ for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = out_payments.begin();
+ i != out_payments.end(); ++i) {
+
+ const crypto::hash &hash = i->first;
+ const tools::wallet2::confirmed_transfer_details &pd = i->second;
+
+ uint64_t fee = pd.m_amount_in - pd.m_amount_out;
+ uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known
+
+
+ std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id);
+ if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
+ payment_id = payment_id.substr(0,16);
+
+
+ TransactionInfoImpl * ti = new TransactionInfoImpl();
+ ti->m_paymentid = payment_id;
+ ti->m_amount = pd.m_amount_in - change - fee;
+ ti->m_fee = fee;
+ ti->m_direction = TransactionInfo::Direction_Out;
+ ti->m_hash = string_tools::pod_to_hex(hash);
+ ti->m_blockheight = pd.m_block_height;
+
+ // single output transaction might contain multiple transfers
+ for (const auto &d: pd.m_dests) {
+ ti->m_transfers.push_back({d.amount, get_account_address_as_str(m_wallet->m_wallet->testnet(), d.addr)});
+ }
+ m_history.push_back(ti);
+ }
+
+ // unconfirmed output transactions
+ std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>> upayments;
+ m_wallet->m_wallet->get_unconfirmed_payments_out(upayments);
+ for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
+ const tools::wallet2::unconfirmed_transfer_details &pd = i->second;
+ const crypto::hash &hash = i->first;
+ uint64_t amount = 0;
+ cryptonote::get_inputs_money_amount(pd.m_tx, amount);
+ uint64_t fee = amount - get_outs_money_amount(pd.m_tx);
+ std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id);
+ if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
+ payment_id = payment_id.substr(0,16);
+ bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed;
+
+ TransactionInfoImpl * ti = new TransactionInfoImpl();
+ ti->m_paymentid = payment_id;
+ ti->m_amount = amount - pd.m_change;
+ ti->m_fee = fee;
+ ti->m_direction = TransactionInfo::Direction_Out;
+ ti->m_failed = is_failed;
+ ti->m_pending = true;
+ ti->m_hash = string_tools::pod_to_hex(hash);
+ m_history.push_back(ti);
+ }
+
+}
+
+TransactionInfo *TransactionHistoryImpl::transaction(int index) const
+{
+ return nullptr;
+}
+
+}
diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h
new file mode 100644
index 000000000..171fd2210
--- /dev/null
+++ b/src/wallet/api/transaction_history.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include "wallet/wallet2_api.h"
+
+namespace Bitmonero {
+
+class TransactionInfo;
+class WalletImpl;
+
+class TransactionHistoryImpl : public TransactionHistory
+{
+public:
+ TransactionHistoryImpl(WalletImpl * wallet);
+ ~TransactionHistoryImpl();
+ virtual int count() const;
+ virtual TransactionInfo * transaction(int index) const;
+ virtual TransactionInfo * transaction(const std::string &id) const;
+ virtual std::vector<TransactionInfo*> getAll() const;
+ virtual void refresh();
+
+private:
+
+ // TransactionHistory is responsible of memory management
+ std::vector<TransactionInfo*> m_history;
+ WalletImpl *m_wallet;
+};
+
+}
+
diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp
new file mode 100644
index 000000000..f25c53a90
--- /dev/null
+++ b/src/wallet/api/transaction_info.cpp
@@ -0,0 +1,112 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include "transaction_info.h"
+
+
+using namespace std;
+
+namespace Bitmonero {
+
+TransactionInfo::~TransactionInfo() {}
+
+TransactionInfo::Transfer::Transfer(uint64_t _amount, const string &_address)
+ : amount(_amount), address(_address) {}
+
+
+TransactionInfoImpl::TransactionInfoImpl()
+ : m_direction(Direction_Out)
+ , m_pending(false)
+ , m_failed(false)
+ , m_amount(0)
+ , m_fee(0)
+ , m_blockheight(0)
+ , m_timestamp(0)
+{
+
+}
+
+TransactionInfoImpl::~TransactionInfoImpl()
+{
+
+}
+
+int TransactionInfoImpl::direction() const
+{
+ return m_direction;
+}
+
+
+bool TransactionInfoImpl::isPending() const
+{
+ return m_pending;
+}
+
+bool TransactionInfoImpl::isFailed() const
+{
+ return m_failed;
+}
+
+uint64_t TransactionInfoImpl::amount() const
+{
+ return m_amount;
+}
+
+uint64_t TransactionInfoImpl::fee() const
+{
+ return m_fee;
+}
+
+uint64_t TransactionInfoImpl::blockHeight() const
+{
+ return m_blockheight;
+}
+
+string TransactionInfoImpl::hash() const
+{
+ return m_hash;
+}
+
+std::time_t TransactionInfoImpl::timestamp() const
+{
+ return m_timestamp;
+}
+
+string TransactionInfoImpl::paymentId() const
+{
+ return m_paymentid;
+}
+
+const std::vector<TransactionInfo::Transfer> &TransactionInfoImpl::transfers() const
+{
+ return m_transfers;
+}
+
+} // namespace
diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h
new file mode 100644
index 000000000..82ab2cc6b
--- /dev/null
+++ b/src/wallet/api/transaction_info.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include "wallet/wallet2_api.h"
+#include <string>
+#include <ctime>
+
+namespace Bitmonero {
+
+class TransactionHistoryImpl;
+
+class TransactionInfoImpl : public TransactionInfo
+{
+public:
+ TransactionInfoImpl();
+ ~TransactionInfoImpl();
+ //! in/out
+ virtual int direction() const;
+ //! true if hold
+ virtual bool isPending() const;
+ virtual bool isFailed() const;
+ virtual uint64_t amount() const;
+ //! always 0 for incoming txes
+ virtual uint64_t fee() const;
+ virtual uint64_t blockHeight() const;
+
+ virtual std::string hash() const;
+ virtual std::time_t timestamp() const;
+ virtual std::string paymentId() const;
+ virtual const std::vector<Transfer> &transfers() const;
+
+private:
+ int m_direction;
+ bool m_pending;
+ bool m_failed;
+ uint64_t m_amount;
+ uint64_t m_fee;
+ uint64_t m_blockheight;
+ std::string m_hash;
+ std::time_t m_timestamp;
+ std::string m_paymentid;
+ std::vector<Transfer> m_transfers;
+
+ friend class TransactionHistoryImpl;
+
+};
+
+} // namespace
diff --git a/src/wallet/api/utils.cpp b/src/wallet/api/utils.cpp
new file mode 100644
index 000000000..aa85323f0
--- /dev/null
+++ b/src/wallet/api/utils.cpp
@@ -0,0 +1,79 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+
+
+#include "include_base_utils.h" // LOG_PRINT_x
+#include "net/http_client.h" // epee::net_utils::...
+#include <boost/asio.hpp>
+
+using namespace std;
+
+namespace Bitmonero {
+namespace Utils {
+
+
+// copy-pasted from simplewallet.
+
+bool isAddressLocal(const std::string &address)
+{
+ // extract host
+ epee::net_utils::http::url_content u_c;
+ if (!epee::net_utils::parse_url(address, u_c))
+ {
+ LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not");
+ return false;
+ }
+ if (u_c.host.empty())
+ {
+ LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not");
+ return false;
+ }
+
+ // resolve to IP
+ boost::asio::io_service io_service;
+ boost::asio::ip::tcp::resolver resolver(io_service);
+ boost::asio::ip::tcp::resolver::query query(u_c.host, "");
+ boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query);
+ while (i != boost::asio::ip::tcp::resolver::iterator())
+ {
+ const boost::asio::ip::tcp::endpoint &ep = *i;
+ if (ep.address().is_loopback())
+ return true;
+ ++i;
+ }
+
+ return false;
+}
+
+}
+
+
+} // namespace
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
new file mode 100644
index 000000000..be379cb99
--- /dev/null
+++ b/src/wallet/api/wallet.cpp
@@ -0,0 +1,588 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+
+#include "wallet.h"
+#include "pending_transaction.h"
+#include "transaction_history.h"
+#include "common_defines.h"
+
+#include "mnemonics/electrum-words.h"
+#include <boost/format.hpp>
+#include <sstream>
+
+using namespace std;
+using namespace cryptonote;
+
+namespace Bitmonero {
+
+namespace {
+ // copy-pasted from simplewallet
+ static const size_t DEFAULT_MIXIN = 4;
+}
+
+struct Wallet2CallbackImpl : public tools::i_wallet2_callback
+{
+
+ Wallet2CallbackImpl()
+ : m_listener(nullptr)
+ {
+
+ }
+
+ ~Wallet2CallbackImpl()
+ {
+
+ }
+
+ void setListener(WalletListener * listener)
+ {
+ m_listener = listener;
+ }
+
+ WalletListener * getListener() const
+ {
+ return m_listener;
+ }
+
+ virtual void on_new_block(uint64_t height, const cryptonote::block& block)
+ {
+ // TODO;
+ LOG_PRINT_L3(__FUNCTION__ << ": new block. height: " << height);
+ }
+
+ virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index)
+ {
+
+ std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(tx));
+ uint64_t amount = tx.vout[out_index].amount;
+
+ LOG_PRINT_L3(__FUNCTION__ << ": money received. height: " << height
+ << ", tx: " << tx_hash
+ << ", amount: " << print_money(amount));
+ if (m_listener) {
+ m_listener->moneyReceived(tx_hash, amount);
+ }
+ }
+
+ virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index,
+ const cryptonote::transaction& spend_tx)
+ {
+ // TODO;
+ std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(spend_tx));
+ uint64_t amount = in_tx.vout[out_index].amount;
+ LOG_PRINT_L3(__FUNCTION__ << ": money spent. height: " << height
+ << ", tx: " << tx_hash
+ << ", amount: " << print_money(amount));
+ if (m_listener) {
+ m_listener->moneySpent(tx_hash, amount);
+ }
+ }
+
+ virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx)
+ {
+ // TODO;
+ }
+
+ WalletListener * m_listener;
+};
+
+Wallet::~Wallet() {}
+
+WalletListener::~WalletListener() {}
+
+string Wallet::displayAmount(uint64_t amount)
+{
+ return cryptonote::print_money(amount);
+}
+
+uint64_t Wallet::amountFromString(const string &amount)
+{
+ uint64_t result;
+ cryptonote::parse_amount(result, amount);
+ return result;
+}
+
+uint64_t Wallet::amountFromDouble(double amount)
+{
+ std::stringstream ss;
+ ss << std::fixed << std::setprecision(CRYPTONOTE_DISPLAY_DECIMAL_POINT) << amount;
+ return amountFromString(ss.str());
+}
+
+std::string Wallet::genPaymentId()
+{
+ crypto::hash8 payment_id = crypto::rand<crypto::hash8>();
+ return epee::string_tools::pod_to_hex(payment_id);
+
+}
+
+
+///////////////////////// WalletImpl implementation ////////////////////////
+WalletImpl::WalletImpl(bool testnet)
+ :m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false),
+ m_wallet2Callback(nullptr)
+{
+ m_wallet = new tools::wallet2(testnet);
+ m_history = new TransactionHistoryImpl(this);
+ m_wallet2Callback = new Wallet2CallbackImpl;
+}
+
+WalletImpl::~WalletImpl()
+{
+ delete m_wallet2Callback;
+ delete m_history;
+ delete m_wallet;
+}
+
+bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language)
+{
+
+ clearStatus();
+
+ bool keys_file_exists;
+ bool wallet_file_exists;
+ tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists);
+ // TODO: figure out how to setup logger;
+ LOG_PRINT_L3("wallet_path: " << path << "");
+ LOG_PRINT_L3("keys_file_exists: " << std::boolalpha << keys_file_exists << std::noboolalpha
+ << " wallet_file_exists: " << std::boolalpha << wallet_file_exists << std::noboolalpha);
+
+
+ // add logic to error out if new wallet requested but named wallet file exists
+ if (keys_file_exists || wallet_file_exists) {
+ m_errorString = "attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting.";
+ LOG_ERROR(m_errorString);
+ m_status = Status_Error;
+ return false;
+ }
+ // TODO: validate language
+ m_wallet->set_seed_language(language);
+ crypto::secret_key recovery_val, secret_key;
+ try {
+ recovery_val = m_wallet->generate(path, password, secret_key, false, false);
+ m_password = password;
+ m_status = Status_Ok;
+ } catch (const std::exception &e) {
+ LOG_ERROR("Error creating wallet: " << e.what());
+ m_status = Status_Error;
+ m_errorString = e.what();
+ return false;
+ }
+
+ return true;
+}
+
+bool WalletImpl::open(const std::string &path, const std::string &password)
+{
+ clearStatus();
+ try {
+ // TODO: handle "deprecated"
+ m_wallet->load(path, password);
+
+ m_password = password;
+ } catch (const std::exception &e) {
+ LOG_ERROR("Error opening wallet: " << e.what());
+ m_status = Status_Error;
+ m_errorString = e.what();
+ }
+ return m_status == Status_Ok;
+}
+
+bool WalletImpl::recover(const std::string &path, const std::string &seed)
+{
+ clearStatus();
+ m_errorString.clear();
+ if (seed.empty()) {
+ m_errorString = "Electrum seed is empty";
+ LOG_ERROR(m_errorString);
+ m_status = Status_Error;
+ return false;
+ }
+
+ crypto::secret_key recovery_key;
+ std::string old_language;
+ if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) {
+ m_errorString = "Electrum-style word list failed verification";
+ m_status = Status_Error;
+ return false;
+ }
+
+ try {
+ m_wallet->set_seed_language(old_language);
+ m_wallet->generate(path, "", recovery_key, true, false);
+ // TODO: wallet->init(daemon_address);
+ } catch (const std::exception &e) {
+ m_status = Status_Error;
+ m_errorString = e.what();
+ }
+ return m_status == Status_Ok;
+}
+
+bool WalletImpl::close()
+{
+ clearStatus();
+ bool result = false;
+ try {
+ m_wallet->store();
+ m_wallet->stop();
+ result = true;
+ } catch (const std::exception &e) {
+ m_status = Status_Error;
+ m_errorString = e.what();
+ LOG_ERROR("Error closing wallet: " << e.what());
+ }
+ return result;
+}
+
+std::string WalletImpl::seed() const
+{
+ std::string seed;
+ if (m_wallet)
+ m_wallet->get_seed(seed);
+ return seed;
+}
+
+std::string WalletImpl::getSeedLanguage() const
+{
+ return m_wallet->get_seed_language();
+}
+
+void WalletImpl::setSeedLanguage(const std::string &arg)
+{
+ m_wallet->set_seed_language(arg);
+}
+
+int WalletImpl::status() const
+{
+ return m_status;
+}
+
+std::string WalletImpl::errorString() const
+{
+ return m_errorString;
+}
+
+bool WalletImpl::setPassword(const std::string &password)
+{
+ clearStatus();
+ try {
+ m_wallet->rewrite(m_wallet->get_wallet_file(), password);
+ m_password = password;
+ } catch (const std::exception &e) {
+ m_status = Status_Error;
+ m_errorString = e.what();
+ }
+ return m_status == Status_Ok;
+}
+
+std::string WalletImpl::address() const
+{
+ return m_wallet->get_account().get_public_address_str(m_wallet->testnet());
+}
+
+std::string WalletImpl::integratedAddress(const std::string &payment_id) const
+{
+ crypto::hash8 pid;
+ if (!tools::wallet2::parse_short_payment_id(payment_id, pid)) {
+ pid = crypto::rand<crypto::hash8>();
+ }
+ return m_wallet->get_account().get_public_integrated_address_str(pid, m_wallet->testnet());
+}
+
+bool WalletImpl::store(const std::string &path)
+{
+ clearStatus();
+ try {
+ if (path.empty()) {
+ m_wallet->store();
+ } else {
+ m_wallet->store_to(path, m_password);
+ }
+ } catch (const std::exception &e) {
+ LOG_ERROR("Error storing wallet: " << e.what());
+ m_status = Status_Error;
+ m_errorString = e.what();
+ }
+
+ return m_status == Status_Ok;
+}
+
+string WalletImpl::filename() const
+{
+ return m_wallet->get_wallet_file();
+}
+
+string WalletImpl::keysFilename() const
+{
+ return m_wallet->get_keys_file();
+}
+
+bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit)
+{
+ clearStatus();
+ try {
+ m_wallet->init(daemon_address, upper_transaction_size_limit);
+ if (Utils::isAddressLocal(daemon_address)) {
+ this->setTrustedDaemon(true);
+ }
+
+ } catch (const std::exception &e) {
+ LOG_ERROR("Error initializing wallet: " << e.what());
+ m_status = Status_Error;
+ m_errorString = e.what();
+ }
+
+ return m_status == Status_Ok;
+}
+
+uint64_t WalletImpl::balance() const
+{
+ return m_wallet->balance();
+}
+
+uint64_t WalletImpl::unlockedBalance() const
+{
+ return m_wallet->unlocked_balance();
+}
+
+
+bool WalletImpl::refresh()
+{
+ clearStatus();
+ try {
+ m_wallet->refresh();
+ } catch (const std::exception &e) {
+ m_status = Status_Error;
+ m_errorString = e.what();
+ }
+ return m_status == Status_Ok;
+}
+
+// TODO:
+// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param)
+// 2 - check / design how "Transaction" can be single interface
+// (instead of few different data structures within wallet2 implementation:
+// - pending_tx;
+// - transfer_details;
+// - payment_details;
+// - unconfirmed_transfer_details;
+// - confirmed_transfer_details)
+
+PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, uint64_t amount, uint32_t mixin_count)
+{
+ clearStatus();
+ vector<cryptonote::tx_destination_entry> dsts;
+ cryptonote::tx_destination_entry de;
+
+ // indicates if dst_addr is integrated address (address + payment_id)
+ bool has_payment_id;
+ crypto::hash8 payment_id_short;
+ // TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441)
+ size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin();
+ if (fake_outs_count == 0)
+ fake_outs_count = DEFAULT_MIXIN;
+
+ PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
+
+ do {
+ if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, payment_id_short, m_wallet->testnet(), dst_addr)) {
+ // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982
+ m_status = Status_Error;
+ m_errorString = "Invalid destination address";
+ break;
+ }
+
+
+ std::vector<uint8_t> extra;
+ // if dst_addr is not an integrated address, parse payment_id
+ if (!has_payment_id && !payment_id.empty()) {
+ // copy-pasted from simplewallet.cpp:2212
+ crypto::hash payment_id_long;
+ bool r = tools::wallet2::parse_long_payment_id(payment_id, payment_id_long);
+ if (r) {
+ std::string extra_nonce;
+ cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_long);
+ r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
+ } else {
+ r = tools::wallet2::parse_short_payment_id(payment_id, payment_id_short);
+ if (r) {
+ std::string extra_nonce;
+ set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_short);
+ r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
+ }
+ }
+
+ if (!r) {
+ m_status = Status_Error;
+ m_errorString = tr("payment id has invalid format, expected 16 or 64 character hex string: ") + payment_id;
+ break;
+ }
+ }
+
+ de.amount = amount;
+ if (de.amount <= 0) {
+ m_status = Status_Error;
+ m_errorString = "Invalid amount";
+ break;
+ }
+
+ dsts.push_back(de);
+ //std::vector<tools::wallet2::pending_tx> ptx_vector;
+
+ try {
+ transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
+ 0 /* unused fee arg*/, extra, m_trustedDaemon);
+
+ } catch (const tools::error::daemon_busy&) {
+ // TODO: make it translatable with "tr"?
+ m_errorString = tr("daemon is busy. Please try again later.");
+ m_status = Status_Error;
+ } catch (const tools::error::no_connection_to_daemon&) {
+ m_errorString = tr("no connection to daemon. Please make sure daemon is running.");
+ m_status = Status_Error;
+ } catch (const tools::error::wallet_rpc_error& e) {
+ m_errorString = tr("RPC error: ") + e.to_string();
+ m_status = Status_Error;
+ } catch (const tools::error::get_random_outs_error&) {
+ m_errorString = tr("failed to get random outputs to mix");
+ m_status = Status_Error;
+
+ } catch (const tools::error::not_enough_money& e) {
+ m_status = Status_Error;
+ std::ostringstream writer;
+
+ writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) %
+ print_money(e.available()) %
+ print_money(e.tx_amount() + e.fee()) %
+ print_money(e.tx_amount()) %
+ print_money(e.fee());
+ m_errorString = writer.str();
+
+ } catch (const tools::error::not_enough_outs_to_mix& e) {
+ std::ostringstream writer;
+ writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":";
+ for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs()) {
+ writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size();
+ }
+ m_errorString = writer.str();
+ m_status = Status_Error;
+ } catch (const tools::error::tx_not_constructed&) {
+ m_errorString = tr("transaction was not constructed");
+ m_status = Status_Error;
+ } catch (const tools::error::tx_rejected& e) {
+ std::ostringstream writer;
+ writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
+ m_errorString = writer.str();
+ m_status = Status_Error;
+ } catch (const tools::error::tx_sum_overflow& e) {
+ m_errorString = e.what();
+ m_status = Status_Error;
+ } catch (const tools::error::zero_destination&) {
+ m_errorString = tr("one of destinations is zero");
+ m_status = Status_Error;
+ } catch (const tools::error::tx_too_big& e) {
+ m_errorString = tr("failed to find a suitable way to split transactions");
+ m_status = Status_Error;
+ } catch (const tools::error::transfer_error& e) {
+ m_errorString = string(tr("unknown transfer error: ")) + e.what();
+ m_status = Status_Error;
+ } catch (const tools::error::wallet_internal_error& e) {
+ m_errorString = string(tr("internal error: ")) + e.what();
+ m_status = Status_Error;
+ } catch (const std::exception& e) {
+ m_errorString = string(tr("unexpected error: ")) + e.what();
+ m_status = Status_Error;
+ } catch (...) {
+ m_errorString = tr("unknown error");
+ m_status = Status_Error;
+ }
+ } while (false);
+
+ transaction->m_status = m_status;
+ transaction->m_errorString = m_errorString;
+ return transaction;
+}
+
+void WalletImpl::disposeTransaction(PendingTransaction *t)
+{
+ delete t;
+}
+
+TransactionHistory *WalletImpl::history() const
+{
+ return m_history;
+}
+
+void WalletImpl::setListener(WalletListener *l)
+{
+ // TODO thread synchronization;
+ m_wallet2Callback->setListener(l);
+}
+
+uint32_t WalletImpl::defaultMixin() const
+{
+ return m_wallet->default_mixin();
+}
+
+void WalletImpl::setDefaultMixin(uint32_t arg)
+{
+ m_wallet->default_mixin(arg);
+}
+
+
+bool WalletImpl::connectToDaemon()
+{
+ bool result = m_wallet->check_connection();
+ m_status = result ? Status_Ok : Status_Error;
+ if (!result) {
+ m_errorString = "Error connecting to daemon at " + m_wallet->get_daemon_address();
+ }
+ return result;
+}
+
+void WalletImpl::setTrustedDaemon(bool arg)
+{
+ m_trustedDaemon = arg;
+}
+
+bool WalletImpl::trustedDaemon() const
+{
+ return m_trustedDaemon;
+}
+
+void WalletImpl::clearStatus()
+{
+ m_status = Status_Ok;
+ m_errorString.clear();
+}
+
+
+} // namespace
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
new file mode 100644
index 000000000..164aede1a
--- /dev/null
+++ b/src/wallet/api/wallet.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#ifndef WALLET_IMPL_H
+#define WALLET_IMPL_H
+
+#include "wallet/wallet2_api.h"
+#include "wallet/wallet2.h"
+
+#include <string>
+
+
+namespace Bitmonero {
+class TransactionHistoryImpl;
+class PendingTransactionImpl;
+struct Wallet2CallbackImpl;
+
+class WalletImpl : public Wallet
+{
+public:
+ WalletImpl(bool testnet = false);
+ ~WalletImpl();
+ bool create(const std::string &path, const std::string &password,
+ const std::string &language);
+ bool open(const std::string &path, const std::string &password);
+ bool recover(const std::string &path, const std::string &seed);
+ bool close();
+ std::string seed() const;
+ std::string getSeedLanguage() const;
+ void setSeedLanguage(const std::string &arg);
+ // void setListener(Listener *) {}
+ int status() const;
+ std::string errorString() const;
+ bool setPassword(const std::string &password);
+ std::string address() const;
+ std::string integratedAddress(const std::string &payment_id) const;
+ bool store(const std::string &path);
+ std::string filename() const;
+ std::string keysFilename() const;
+ bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit);
+ bool connectToDaemon();
+ void setTrustedDaemon(bool arg);
+ bool trustedDaemon() const;
+ uint64_t balance() const;
+ uint64_t unlockedBalance() const;
+ bool refresh();
+ PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
+ uint64_t amount, uint32_t mixin_count);
+ virtual void disposeTransaction(PendingTransaction * t);
+ virtual TransactionHistory * history() const;
+ virtual void setListener(WalletListener * l);
+ virtual uint32_t defaultMixin() const;
+ virtual void setDefaultMixin(uint32_t arg);
+
+private:
+ void clearStatus();
+
+private:
+ friend class PendingTransactionImpl;
+ friend class TransactionHistoryImpl;
+
+ tools::wallet2 * m_wallet;
+ int m_status;
+ std::string m_errorString;
+ std::string m_password;
+ TransactionHistoryImpl * m_history;
+ bool m_trustedDaemon;
+ WalletListener * m_walletListener;
+ Wallet2CallbackImpl * m_wallet2Callback;
+};
+
+
+} // namespace
+
+#endif
+
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
new file mode 100644
index 000000000..4ed6e09fb
--- /dev/null
+++ b/src/wallet/api/wallet_manager.cpp
@@ -0,0 +1,142 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+
+#include "wallet_manager.h"
+#include "wallet.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/regex.hpp>
+
+
+namespace epee {
+ unsigned int g_test_dbg_lock_sleep = 0;
+}
+
+namespace Bitmonero {
+
+Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password,
+ const std::string &language, bool testnet)
+{
+ WalletImpl * wallet = new WalletImpl(testnet);
+ wallet->create(path, password, language);
+ return wallet;
+}
+
+Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, bool testnet)
+{
+ WalletImpl * wallet = new WalletImpl(testnet);
+ wallet->open(path, password);
+ return wallet;
+}
+
+Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &memo, bool testnet)
+{
+ WalletImpl * wallet = new WalletImpl(testnet);
+ wallet->recover(path, memo);
+ return wallet;
+}
+
+bool WalletManagerImpl::closeWallet(Wallet *wallet)
+{
+ WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet);
+ bool result = wallet_->close();
+ if (!result) {
+ m_errorString = wallet_->errorString();
+ } else {
+ delete wallet_;
+ }
+ return result;
+}
+
+bool WalletManagerImpl::walletExists(const std::string &path)
+{
+ return false;
+}
+
+
+std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path)
+{
+ std::vector<std::string> result;
+ const boost::regex wallet_rx("(.*)\\.(keys)$"); // searching for <wallet_name>.keys files
+ boost::filesystem::recursive_directory_iterator end_itr; // Default ctor yields past-the-end
+ boost::filesystem::path work_dir(path);
+
+ for (boost::filesystem::recursive_directory_iterator itr(path); itr != end_itr; ++itr) {
+ // Skip if not a file
+ if (!boost::filesystem::is_regular_file(itr->status()))
+ continue;
+ boost::smatch what;
+ std::string filename = itr->path().filename().string();
+
+ LOG_PRINT_L3("Checking filename: " << filename);
+
+ bool matched = boost::regex_match(filename, what, wallet_rx);
+ if (matched) {
+ // if keys file found, checking if there's wallet file itself
+ std::string wallet_file = (itr->path().parent_path() /= what[1]).string();
+ if (boost::filesystem::exists(wallet_file)) {
+ LOG_PRINT_L3("Found wallet: " << wallet_file);
+ result.push_back(wallet_file);
+ }
+ }
+ }
+ return result;
+}
+
+std::string WalletManagerImpl::errorString() const
+{
+ return m_errorString;
+}
+
+void WalletManagerImpl::setDaemonHost(const std::string &hostname)
+{
+
+}
+
+
+
+///////////////////// WalletManagerFactory implementation //////////////////////
+WalletManager *WalletManagerFactory::getWalletManager()
+{
+
+ static WalletManagerImpl * g_walletManager = nullptr;
+
+ if (!g_walletManager) {
+ epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_MAX);
+ g_walletManager = new WalletManagerImpl();
+ }
+
+ return g_walletManager;
+}
+
+
+
+}
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
new file mode 100644
index 000000000..7585c1af7
--- /dev/null
+++ b/src/wallet/api/wallet_manager.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2014-2016, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+
+#include "wallet/wallet2_api.h"
+#include <string>
+
+namespace Bitmonero {
+
+class WalletManagerImpl : public WalletManager
+{
+public:
+ Wallet * createWallet(const std::string &path, const std::string &password,
+ const std::string &language, bool testnet);
+ Wallet * openWallet(const std::string &path, const std::string &password, bool testnet);
+ virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet);
+ virtual bool closeWallet(Wallet *wallet);
+ bool walletExists(const std::string &path);
+ std::vector<std::string> findWallets(const std::string &path);
+ std::string errorString() const;
+ void setDaemonHost(const std::string &hostname);
+
+private:
+ WalletManagerImpl() {}
+ friend struct WalletManagerFactory;
+ std::string m_errorString;
+};
+
+} // namespace
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index a9d69627c..a153967ce 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1552,6 +1552,42 @@ void wallet2::check_genesis(const crypto::hash& genesis_hash) const {
//----------------------------------------------------------------------------------------------------
void wallet2::store()
{
+ store_to("", "");
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::store_to(const std::string &path, const std::string &password)
+{
+ // if file is the same, we do:
+ // 1. save wallet to the *.new file
+ // 2. remove old wallet file
+ // 3. rename *.new to wallet_name
+
+ // handle if we want just store wallet state to current files (ex store() replacement);
+ bool same_file = true;
+ if (!path.empty())
+ {
+ std::string canonical_path = boost::filesystem::canonical(m_wallet_file).string();
+ size_t pos = canonical_path.find(path);
+ same_file = pos != std::string::npos;
+ }
+
+
+ if (!same_file)
+ {
+ // check if we want to store to directory which doesn't exists yet
+ boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path();
+
+ // if path is not exists, try to create it
+ if (!parent_path.empty() && !boost::filesystem::exists(parent_path))
+ {
+ boost::system::error_code ec;
+ if (!boost::filesystem::create_directories(parent_path, ec))
+ {
+ throw std::logic_error(ec.message());
+ }
+ }
+ }
+ // preparing wallet data
std::stringstream oss;
boost::archive::binary_oarchive ar(oss);
ar << *this;
@@ -1566,10 +1602,10 @@ void wallet2::store()
crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]);
cache_file_data.cache_data = cipher;
- // save to new file, rename main to old, rename new to main
- // at all times, there should be a valid file on disk
- const std::string new_file = m_wallet_file + ".new";
- const std::string old_file = m_wallet_file + ".old";
+ const std::string new_file = same_file ? m_wallet_file + ".new" : path;
+ const std::string old_file = m_wallet_file;
+ const std::string old_keys_file = m_keys_file;
+ const std::string old_address_file = m_wallet_file + ".address.txt";
// save to new file
std::ofstream ostr;
@@ -1579,87 +1615,35 @@ void wallet2::store()
ostr.close();
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
- // rename
- boost::filesystem::remove(old_file); // probably does not exist
- if (boost::filesystem::exists(m_wallet_file)) {
- std::error_code e = tools::replace_file(m_wallet_file, old_file);
- THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
- }
- std::error_code e = tools::replace_file(new_file, m_wallet_file);
- THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
- boost::filesystem::remove(old_file);
-}
-
-void wallet2::store_to(const std::string &path, const std::string &password)
-{
- // TODO: merge it with wallet2::store() function
-
- // check if we want to store to directory which doesn't exists yet
- boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path();
-
- // if path is not exists, try to create it
- if (!parent_path.empty() && !boost::filesystem::exists(parent_path)) {
- boost::system::error_code ec;
- if (!boost::filesystem::create_directories(parent_path, ec)) {
- throw std::logic_error(ec.message());
- }
- }
-
-
- std::stringstream oss;
- boost::archive::binary_oarchive ar(oss);
- ar << *this;
-
- wallet2::cache_file_data cache_file_data = boost::value_initialized<wallet2::cache_file_data>();
- cache_file_data.cache_data = oss.str();
- crypto::chacha8_key key;
- generate_chacha8_key_from_secret_keys(key);
- std::string cipher;
- cipher.resize(cache_file_data.cache_data.size());
- cache_file_data.iv = crypto::rand<crypto::chacha8_iv>();
- crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]);
- cache_file_data.cache_data = cipher;
-
-
- const std::string new_file = path;
- const std::string old_file = m_wallet_file;
- const std::string old_keys_file = m_keys_file;
- const std::string old_address_file = m_wallet_file + ".address.txt";
-
- // save to new file
- std::ofstream ostr;
- ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
- binary_archive<true> oar(ostr);
- bool success = ::serialization::serialize(oar, cache_file_data);
- ostr.close();
- THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
-
- // save keys to the new file
- // if we here, main wallet file is saved and we only need to save keys and address files
+ // save keys to the new file
+ // if we here, main wallet file is saved and we only need to save keys and address files
+ if (!same_file) {
prepare_file_names(path);
store_keys(m_keys_file, password, false);
-
// save address to the new file
const std::string address_file = m_wallet_file + ".address.txt";
bool r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet));
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file);
-
-
// remove old wallet file
r = boost::filesystem::remove(old_file);
if (!r) {
- LOG_ERROR("error removing file: " << old_file);
+ LOG_ERROR("error removing file: " << old_file);
}
// remove old keys file
r = boost::filesystem::remove(old_keys_file);
if (!r) {
- LOG_ERROR("error removing file: " << old_keys_file);
+ LOG_ERROR("error removing file: " << old_keys_file);
}
// remove old address file
r = boost::filesystem::remove(old_address_file);
if (!r) {
- LOG_ERROR("error removing file: " << old_address_file);
+ LOG_ERROR("error removing file: " << old_address_file);
}
+ } else {
+ // here we have "*.new" file, we need to rename it to be without ".new"
+ std::error_code e = tools::replace_file(new_file, m_wallet_file);
+ THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
+ }
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::unlocked_balance() const
@@ -3097,12 +3081,17 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) c
std::string wallet2::get_wallet_file() const
{
- return m_wallet_file;
+ return m_wallet_file;
}
std::string wallet2::get_keys_file() const
{
- return m_keys_file;
+ return m_keys_file;
+}
+
+std::string wallet2::get_daemon_address() const
+{
+ return m_daemon_address;
}
void wallet2::set_tx_note(const crypto::hash &txid, const std::string &note)
@@ -3117,7 +3106,6 @@ std::string wallet2::get_tx_note(const crypto::hash &txid) const
return std::string();
return i->second;
}
-
//----------------------------------------------------------------------------------------------------
void wallet2::generate_genesis(cryptonote::block& b) {
if (m_testnet)
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index cecf090f4..c5149a10c 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -61,6 +61,7 @@ namespace tools
virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) {}
virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx) {}
virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx) {}
+ virtual ~i_wallet2_callback() {}
};
struct tx_dust_policy
@@ -375,6 +376,7 @@ namespace tools
std::string get_wallet_file() const;
std::string get_keys_file() const;
+ std::string get_daemon_address() const;
std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool trusted_daemon);
std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f);
diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp
deleted file mode 100644
index 0644e3690..000000000
--- a/src/wallet/wallet2_api.cpp
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright (c) 2014-2016, 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.
-//
-// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
-
-#include "wallet2_api.h"
-#include "wallet2.h"
-#include "mnemonics/electrum-words.h"
-#include <memory>
-
-namespace epee {
- unsigned int g_test_dbg_lock_sleep = 0;
-}
-
-namespace Bitmonero {
-
-struct WalletManagerImpl;
-
-namespace {
- static WalletManagerImpl * g_walletManager = nullptr;
-
-
-
-}
-
-Wallet::~Wallet() {}
-
-///////////////////////// Wallet implementation ////////////////////////////////
-class WalletImpl : public Wallet
-{
-public:
- WalletImpl();
- ~WalletImpl();
- bool create(const std::string &path, const std::string &password,
- const std::string &language);
- bool open(const std::string &path, const std::string &password);
- bool recover(const std::string &path, const std::string &seed);
- bool close();
- std::string seed() const;
- std::string getSeedLanguage() const;
- void setSeedLanguage(const std::string &arg);
- void setListener(Listener *) {}
- int status() const;
- std::string errorString() const;
- bool setPassword(const std::string &password);
- std::string address() const;
- bool store(const std::string &path);
-
-private:
- void clearStatus();
-
-private:
- //std::unique_ptr<tools::wallet2> m_wallet;
- tools::wallet2 * m_wallet;
- int m_status;
- std::string m_errorString;
- std::string m_password;
-};
-
-WalletImpl::WalletImpl()
- :m_wallet(nullptr), m_status(Wallet::Status_Ok)
-{
- m_wallet = new tools::wallet2();
-}
-
-WalletImpl::~WalletImpl()
-{
- delete m_wallet;
-}
-
-bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language)
-{
-
- clearStatus();
-
- bool keys_file_exists;
- bool wallet_file_exists;
- tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists);
- // TODO: figure out how to setup logger;
- LOG_PRINT_L3("wallet_path: " << path << "");
- LOG_PRINT_L3("keys_file_exists: " << std::boolalpha << keys_file_exists << std::noboolalpha
- << " wallet_file_exists: " << std::boolalpha << wallet_file_exists << std::noboolalpha);
-
-
- // add logic to error out if new wallet requested but named wallet file exists
- if (keys_file_exists || wallet_file_exists) {
- m_errorString = "attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting.";
- LOG_ERROR(m_errorString);
- m_status = Status_Error;
- return false;
- }
- // TODO: validate language
- m_wallet->set_seed_language(language);
- crypto::secret_key recovery_val, secret_key;
- try {
- recovery_val = m_wallet->generate(path, password, secret_key, false, false);
- m_password = password;
- m_status = Status_Ok;
- } catch (const std::exception &e) {
- LOG_ERROR("Error creating wallet: " << e.what());
- m_status = Status_Error;
- m_errorString = e.what();
- return false;
- }
-
- return true;
-}
-
-bool WalletImpl::open(const std::string &path, const std::string &password)
-{
- clearStatus();
- try {
- // TODO: handle "deprecated"
- m_wallet->load(path, password);
-
- m_password = password;
- } catch (const std::exception &e) {
- LOG_ERROR("Error opening wallet: " << e.what());
- m_status = Status_Error;
- m_errorString = e.what();
- }
- return m_status == Status_Ok;
-}
-
-bool WalletImpl::recover(const std::string &path, const std::string &seed)
-{
- clearStatus();
- m_errorString.clear();
- if (seed.empty()) {
- m_errorString = "Electrum seed is empty";
- LOG_ERROR(m_errorString);
- m_status = Status_Error;
- return false;
- }
-
- crypto::secret_key recovery_key;
- std::string old_language;
- if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) {
- m_errorString = "Electrum-style word list failed verification";
- m_status = Status_Error;
- return false;
- }
-
- try {
- m_wallet->set_seed_language(old_language);
- m_wallet->generate(path, "", recovery_key, true, false);
- // TODO: wallet->init(daemon_address);
- } catch (const std::exception &e) {
- m_status = Status_Error;
- m_errorString = e.what();
- }
- return m_status == Status_Ok;
-}
-
-bool WalletImpl::close()
-{
- clearStatus();
- bool result = false;
- try {
- m_wallet->store();
- m_wallet->stop();
- result = true;
- } catch (const std::exception &e) {
- m_status = Status_Error;
- m_errorString = e.what();
- LOG_ERROR("Error closing wallet: " << e.what());
- }
- return result;
-}
-
-std::string WalletImpl::seed() const
-{
- std::string seed;
- if (m_wallet)
- m_wallet->get_seed(seed);
- return seed;
-}
-
-std::string WalletImpl::getSeedLanguage() const
-{
- return m_wallet->get_seed_language();
-}
-
-void WalletImpl::setSeedLanguage(const std::string &arg)
-{
- m_wallet->set_seed_language(arg);
-}
-
-int WalletImpl::status() const
-{
- return m_status;
-}
-
-std::string WalletImpl::errorString() const
-{
- return m_errorString;
-}
-
-bool WalletImpl::setPassword(const std::string &password)
-{
- clearStatus();
- try {
- m_wallet->rewrite(m_wallet->get_wallet_file(), password);
- m_password = password;
- } catch (const std::exception &e) {
- m_status = Status_Error;
- m_errorString = e.what();
- }
- return m_status == Status_Ok;
-}
-
-std::string WalletImpl::address() const
-{
- return m_wallet->get_account().get_public_address_str(m_wallet->testnet());
-}
-
-bool WalletImpl::store(const std::string &path)
-{
- clearStatus();
- try {
- if (path.empty()) {
- m_wallet->store();
- } else {
- m_wallet->store_to(path, m_password);
- }
- } catch (const std::exception &e) {
- LOG_ERROR("Error storing wallet: " << e.what());
- m_status = Status_Error;
- m_errorString = e.what();
- }
-
- return m_status == Status_Ok;
-}
-
-void WalletImpl::clearStatus()
-{
- m_status = Status_Ok;
- m_errorString.clear();
-}
-
-
-
-///////////////////////// WalletManager implementation /////////////////////////
-class WalletManagerImpl : public WalletManager
-{
-public:
- Wallet * createWallet(const std::string &path, const std::string &password,
- const std::string &language);
- Wallet * openWallet(const std::string &path, const std::string &password);
- virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo);
- virtual bool closeWallet(Wallet *wallet);
- bool walletExists(const std::string &path);
- std::string errorString() const;
-
-
-private:
- WalletManagerImpl() {}
- friend struct WalletManagerFactory;
-
- std::string m_errorString;
-};
-
-Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password,
- const std::string &language)
-{
- WalletImpl * wallet = new WalletImpl();
- wallet->create(path, password, language);
- return wallet;
-}
-
-Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password)
-{
- WalletImpl * wallet = new WalletImpl();
- wallet->open(path, password);
- return wallet;
-}
-
-Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &memo)
-{
- WalletImpl * wallet = new WalletImpl();
- wallet->recover(path, memo);
- return wallet;
-}
-
-bool WalletManagerImpl::closeWallet(Wallet *wallet)
-{
- WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet);
- bool result = wallet_->close();
- if (!result) {
- m_errorString = wallet_->errorString();
- } else {
- delete wallet_;
- }
- return result;
-}
-
-bool WalletManagerImpl::walletExists(const std::string &path)
-{
- return false;
-}
-
-std::string WalletManagerImpl::errorString() const
-{
- return m_errorString;
-}
-
-
-
-///////////////////// WalletManagerFactory implementation //////////////////////
-WalletManager *WalletManagerFactory::getWalletManager()
-{
-
- if (!g_walletManager) {
- epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0);
- g_walletManager = new WalletManagerImpl();
- }
-
- return g_walletManager;
-}
-
-}
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index c7e7c536c..66987e4c5 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -32,10 +32,85 @@
#include <string>
+#include <vector>
+#include <ctime>
// Public interface for libwallet library
namespace Bitmonero {
+ namespace Utils {
+ bool isAddressLocal(const std::string &hostaddr);
+ }
+/**
+ * @brief Transaction-like interface for sending money
+ */
+struct PendingTransaction
+{
+ enum Status {
+ Status_Ok,
+ Status_Error
+ };
+ virtual ~PendingTransaction() = 0;
+ virtual int status() const = 0;
+ virtual std::string errorString() const = 0;
+ virtual bool commit() = 0;
+ virtual uint64_t amount() const = 0;
+ virtual uint64_t dust() const = 0;
+ virtual uint64_t fee() const = 0;
+};
+
+/**
+ * @brief The TransactionInfo - interface for displaying transaction information
+ */
+struct TransactionInfo
+{
+ enum Direction {
+ Direction_In,
+ Direction_Out
+ };
+
+ 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;
+ virtual bool isPending() const = 0;
+ virtual bool isFailed() const = 0;
+ virtual uint64_t amount() const = 0;
+ virtual uint64_t fee() const = 0;
+ virtual uint64_t blockHeight() const = 0;
+ //! transaction_id
+ virtual std::string hash() const = 0;
+ virtual std::time_t timestamp() const = 0;
+ virtual std::string paymentId() const = 0;
+ //! only applicable for output transactions
+ virtual const std::vector<Transfer> & transfers() const = 0;
+};
+/**
+ * @brief The TransactionHistory - interface for displaying transaction history
+ */
+struct TransactionHistory
+{
+ virtual ~TransactionHistory() = 0;
+ virtual int count() const = 0;
+ virtual TransactionInfo * transaction(int index) const = 0;
+ virtual TransactionInfo * transaction(const std::string &id) const = 0;
+ virtual std::vector<TransactionInfo*> getAll() const = 0;
+ virtual void refresh() = 0;
+};
+
+
+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;
+ // TODO: on_skip_transaction;
+};
+
/**
* @brief Interface for wallet operations.
@@ -43,30 +118,93 @@ namespace Bitmonero {
*/
struct Wallet
{
- // TODO define wallet interface (decide what needed from wallet2)
enum Status {
Status_Ok,
Status_Error
};
- struct Listener
- {
- // TODO
- };
-
virtual ~Wallet() = 0;
virtual std::string seed() const = 0;
virtual std::string getSeedLanguage() const = 0;
virtual void setSeedLanguage(const std::string &arg) = 0;
- virtual void setListener(Listener * listener) = 0;
//! returns wallet status (Status_Ok | Status_Error)
virtual int status() const = 0;
//! in case error status, returns error string
virtual std::string errorString() const = 0;
virtual bool setPassword(const std::string &password) = 0;
virtual std::string address() const = 0;
+
+ /*!
+ * \brief integratedAddress - returns integrated address for current wallet address and given payment_id.
+ * if passed "payment_id" param is an empty string or not-valid payment id string
+ * (16 characters hexadecimal string) - random payment_id will be generated
+ *
+ * \param payment_id - 16 characters hexadecimal string or empty string if new random payment id needs to be
+ * generated
+ * \return - 106 characters string representing integrated address
+ */
+ virtual std::string integratedAddress(const std::string &payment_id) const = 0;
+
+ /*!
+ * \brief store - stores wallet to file.
+ * \param path - main filename to store wallet to. additionally stores address file and keys file.
+ * to store to the same file - just pass empty string;
+ * \return
+ */
virtual bool store(const std::string &path) = 0;
+ /*!
+ * \brief filename - returns wallet filename
+ * \return
+ */
+ virtual std::string filename() const = 0;
+ /*!
+ * \brief keysFilename - returns keys filename. usually this formed as "wallet_filename".keys
+ * \return
+ */
+ virtual std::string keysFilename() const = 0;
+
+ virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0;
+ virtual bool connectToDaemon() = 0;
+ virtual void setTrustedDaemon(bool arg) = 0;
+ virtual bool trustedDaemon() const = 0;
+ virtual uint64_t balance() const = 0;
+ virtual uint64_t unlockedBalance() const = 0;
+
+ static std::string displayAmount(uint64_t amount);
+ static uint64_t amountFromString(const std::string &amount);
+ static uint64_t amountFromDouble(double amount);
+ static std::string genPaymentId();
+
+ // TODO?
+ // virtual uint64_t unlockedDustBalance() const = 0;
+ virtual bool refresh() = 0;
+ /*!
+ * \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
+ * \param dst_addr destination address as string
+ * \param payment_id optional payment_id, can be empty string
+ * \param amount amount
+ * \param mixin_count mixin count. if 0 passed, wallet will use default value
+ * \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
+ * after object returned
+ */
+
+ virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
+ uint64_t amount, uint32_t mixin_count) = 0;
+
+ virtual void disposeTransaction(PendingTransaction * t) = 0;
+ virtual TransactionHistory * history() const = 0;
+ virtual void setListener(WalletListener *) = 0;
+ /*!
+ * \brief defaultMixin - returns number of mixins used in transactions
+ * \return
+ */
+ virtual uint32_t defaultMixin() const = 0;
+ /*!
+ * \brief setDefaultMixin - setum number of mixins to be used for new transactions
+ * \param arg
+ */
+ virtual void setDefaultMixin(uint32_t arg) = 0;
};
/**
@@ -82,7 +220,7 @@ struct WalletManager
* \param language Language to be used to generate electrum seed memo
* \return Wallet instance (Wallet::status() needs to be called to check if created successfully)
*/
- virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language) = 0;
+ virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet = false) = 0;
/*!
* \brief Opens existing wallet
@@ -90,7 +228,7 @@ struct WalletManager
* \param password Password of wallet file
* \return Wallet instance (Wallet::status() needs to be called to check if opened successfully)
*/
- virtual Wallet * openWallet(const std::string &path, const std::string &password) = 0;
+ virtual Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) = 0;
/*!
* \brief recovers existing wallet using memo (electrum seed)
@@ -98,7 +236,7 @@ struct WalletManager
* \param memo memo (25 words electrum seed)
* \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully)
*/
- virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo) = 0;
+ virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet = false) = 0;
/*!
* \brief Closes wallet. In case operation succeded, wallet object deleted. in case operation failed, wallet object not deleted
@@ -107,9 +245,25 @@ struct WalletManager
*/
virtual bool closeWallet(Wallet *wallet) = 0;
- //! checks if wallet with the given name already exists
+ /*
+ * ! checks if wallet with the given name already exists
+ */
+
+ /*!
+ * @brief TODO: delme walletExists - check if the given filename is the wallet
+ * @param path - filename
+ * @return
+ */
virtual bool walletExists(const std::string &path) = 0;
+ /*!
+ * \brief findWallets - searches for the wallet files by given path name recursively
+ * \param path - starting point to search
+ * \return - list of strings with found wallets (absolute paths);
+ */
+ virtual std::vector<std::string> findWallets(const std::string &path) = 0;
+
+ //! returns verbose error string regarding last error;
virtual std::string errorString() const = 0;
};
diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp
index 9701c300c..f6f1b0832 100644
--- a/tests/libwallet_api_tests/main.cpp
+++ b/tests/libwallet_api_tests/main.cpp
@@ -29,37 +29,116 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include "gtest/gtest.h"
+
#include "wallet/wallet2_api.h"
+
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <vector>
+#include <mutex>
+#include <thread>
using namespace std;
//unsigned int epee::g_test_dbg_lock_sleep = 0;
+namespace Consts
+{
+
+
+// TODO: get rid of hardcoded paths
+
+const char * WALLET_NAME = "testwallet";
+const char * WALLET_NAME_COPY = "testwallet_copy";
+const char * WALLET_NAME_WITH_DIR = "walletdir/testwallet_test";
+const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "/var/walletdir/testwallet_test";
+const char * WALLET_PASS = "password";
+const char * WALLET_PASS2 = "password22";
+const char * WALLET_LANG = "English";
+
+// change this according your environment
+
+const std::string WALLETS_ROOT_DIR = "/home/mbg033/dev/monero/testnet/";
+
+const std::string TESTNET_WALLET1_NAME = WALLETS_ROOT_DIR + "wallet_01.bin";
+const std::string TESTNET_WALLET2_NAME = WALLETS_ROOT_DIR + "wallet_02.bin";
+const std::string TESTNET_WALLET3_NAME = WALLETS_ROOT_DIR + "wallet_03.bin";
+const std::string TESTNET_WALLET4_NAME = WALLETS_ROOT_DIR + "wallet_04.bin";
+const std::string TESTNET_WALLET5_NAME = WALLETS_ROOT_DIR + "wallet_05.bin";
+const std::string TESTNET_WALLET6_NAME = WALLETS_ROOT_DIR + "wallet_06.bin";
+
+const char * TESTNET_WALLET_PASS = "";
+
+const std::string CURRENT_SRC_WALLET = TESTNET_WALLET1_NAME;
+const std::string CURRENT_DST_WALLET = TESTNET_WALLET6_NAME;
+
+const char * TESTNET_DAEMON_ADDRESS = "localhost:38081";
+const uint64_t AMOUNT_10XMR = 10000000000000L;
+const uint64_t AMOUNT_5XMR = 5000000000000L;
+const uint64_t AMOUNT_1XMR = 1000000000000L;
+
+const std::string PAYMENT_ID_EMPTY = "";
+
+}
+
+
+
+using namespace Consts;
+
+struct Utils
+{
+ static void deleteWallet(const std::string & walletname)
+ {
+ std::cout << "** deleting wallet: " << walletname << std::endl;
+ boost::filesystem::remove(walletname);
+ boost::filesystem::remove(walletname + ".address.txt");
+ boost::filesystem::remove(walletname + ".keys");
+ }
+
+ static void deleteDir(const std::string &path)
+ {
+ std::cout << "** removing dir recursively: " << path << std::endl;
+ boost::filesystem::remove_all(path);
+ }
+
+ static void print_transaction(Bitmonero::TransactionInfo * t)
+ {
+
+ std::cout << "d: "
+ << (t->direction() == Bitmonero::TransactionInfo::Direction_In ? "in" : "out")
+ << ", pe: " << (t->isPending() ? "true" : "false")
+ << ", bh: " << t->blockHeight()
+ << ", a: " << Bitmonero::Wallet::displayAmount(t->amount())
+ << ", f: " << Bitmonero::Wallet::displayAmount(t->fee())
+ << ", h: " << t->hash()
+ << ", pid: " << t->paymentId()
+ << std::endl;
+ }
+
+ static std::string get_wallet_address(const std::string &filename, const std::string &password)
+ {
+ Bitmonero::WalletManager *wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
+ Bitmonero::Wallet * w = wmgr->openWallet(filename, password, true);
+ std::string result = w->address();
+ wmgr->closeWallet(w);
+ return result;
+ }
+};
struct WalletManagerTest : public testing::Test
{
Bitmonero::WalletManager * wmgr;
- const char * WALLET_NAME = "testwallet";
- const char * WALLET_NAME_COPY = "testwallet_copy";
- const char * WALLET_NAME_WITH_DIR = "walletdir/testwallet_test";
- const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "/var/walletdir/testwallet_test";
- const char * WALLET_PASS = "password";
- const char * WALLET_PASS2 = "password22";
- const char * WALLET_LANG = "English";
WalletManagerTest()
{
std::cout << __FUNCTION__ << std::endl;
wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
- deleteWallet(WALLET_NAME);
- deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string());
+ Utils::deleteWallet(WALLET_NAME);
+ Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string());
}
@@ -69,21 +148,32 @@ struct WalletManagerTest : public testing::Test
//deleteWallet(WALLET_NAME);
}
+};
+
- void deleteWallet(const std::string & walletname)
+struct WalletTest1 : public testing::Test
+{
+ Bitmonero::WalletManager * wmgr;
+
+ WalletTest1()
{
- std::cout << "** deleting wallet: " << walletname << std::endl;
- boost::filesystem::remove(walletname);
- boost::filesystem::remove(walletname + ".address.txt");
- boost::filesystem::remove(walletname + ".keys");
+ wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
}
- void deleteDir(const std::string &path)
+
+};
+
+
+struct WalletTest2 : public testing::Test
+{
+ Bitmonero::WalletManager * wmgr;
+
+ WalletTest2()
{
- std::cout << "** removing dir recursively: " << path << std::endl;
- boost::filesystem::remove_all(path);
+ wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
}
+
};
@@ -116,7 +206,36 @@ TEST_F(WalletManagerTest, WalletManagerOpensWallet)
std::cout << "** seed: " << wallet2->seed() << std::endl;
}
+TEST_F(WalletManagerTest, WalletManagerStoresWallet)
+{
+ Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
+ std::string seed1 = wallet1->seed();
+ wallet1->store("");
+ ASSERT_TRUE(wmgr->closeWallet(wallet1));
+ Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
+ ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);
+ ASSERT_TRUE(wallet2->seed() == seed1);
+}
+
+
+TEST_F(WalletManagerTest, WalletManagerMovesWallet)
+{
+
+ Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
+ std::string WALLET_NAME_MOVED = std::string("/tmp/") + WALLET_NAME + ".moved";
+ std::string seed1 = wallet1->seed();
+ ASSERT_TRUE(wallet1->store(WALLET_NAME_MOVED));
+
+ Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME_MOVED, WALLET_PASS);
+ ASSERT_TRUE(wallet2->filename() == WALLET_NAME_MOVED);
+ ASSERT_TRUE(wallet2->keysFilename() == WALLET_NAME_MOVED + ".keys");
+ ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);
+ ASSERT_TRUE(wallet2->seed() == seed1);
+}
+
+
+/*
TEST_F(WalletManagerTest, WalletManagerChangesPassword)
{
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
@@ -124,7 +243,7 @@ TEST_F(WalletManagerTest, WalletManagerChangesPassword)
ASSERT_TRUE(wallet1->setPassword(WALLET_PASS2));
ASSERT_TRUE(wmgr->closeWallet(wallet1));
Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS2);
- ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);
+ ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);quint64
ASSERT_TRUE(wallet2->seed() == seed1);
ASSERT_TRUE(wmgr->closeWallet(wallet2));
Bitmonero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
@@ -140,7 +259,7 @@ TEST_F(WalletManagerTest, WalletManagerRecoversWallet)
std::string address1 = wallet1->address();
ASSERT_FALSE(address1.empty());
ASSERT_TRUE(wmgr->closeWallet(wallet1));
- deleteWallet(WALLET_NAME);
+ Utils::deleteWallet(WALLET_NAME);
Bitmonero::Wallet * wallet2 = wmgr->recoveryWallet(WALLET_NAME, seed1);
ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);
ASSERT_TRUE(wallet2->seed() == seed1);
@@ -165,6 +284,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet1)
ASSERT_TRUE(wmgr->closeWallet(wallet2));
}
+
TEST_F(WalletManagerTest, WalletManagerStoresWallet2)
{
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
@@ -203,10 +323,363 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet3)
}
+TEST_F(WalletManagerTest, WalletManagerStoresWallet4)
+{
+ Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
+ std::string seed1 = wallet1->seed();
+ std::string address1 = wallet1->address();
+
+ ASSERT_TRUE(wallet1->store(""));
+ ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
+
+ ASSERT_TRUE(wallet1->store(""));
+ ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
+
+ ASSERT_TRUE(wmgr->closeWallet(wallet1));
+
+ wallet1 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
+ ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
+ ASSERT_TRUE(wallet1->seed() == seed1);
+ ASSERT_TRUE(wallet1->address() == address1);
+ ASSERT_TRUE(wmgr->closeWallet(wallet1));
+}
+*/
+
+TEST_F(WalletManagerTest, WalletManagerFindsWallet)
+{
+ std::vector<std::string> wallets = wmgr->findWallets(WALLETS_ROOT_DIR);
+ ASSERT_FALSE(wallets.empty());
+ std::cout << "Found wallets: " << std::endl;
+ for (auto wallet_path: wallets) {
+ std::cout << wallet_path << std::endl;
+ }
+}
+
+
+TEST_F(WalletManagerTest, WalletGeneratesPaymentId)
+{
+ std::string payment_id = Bitmonero::Wallet::genPaymentId();
+ ASSERT_TRUE(payment_id.length() == 16);
+}
+
+
+TEST_F(WalletManagerTest, WalletGeneratesIntegratedAddress)
+{
+ std::string payment_id = Bitmonero::Wallet::genPaymentId();
+
+ Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+ std::string integrated_address = wallet1->integratedAddress(payment_id);
+ ASSERT_TRUE(integrated_address.length() == 106);
+}
+
+
+TEST_F(WalletTest1, WalletShowsBalance)
+{
+ // TODO: temporary disabled;
+ return;
+ Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+ ASSERT_TRUE(wallet1->balance() > 0);
+ ASSERT_TRUE(wallet1->unlockedBalance() > 0);
+
+ uint64_t balance1 = wallet1->balance();
+ uint64_t unlockedBalance1 = wallet1->unlockedBalance();
+ ASSERT_TRUE(wmgr->closeWallet(wallet1));
+ Bitmonero::Wallet * wallet2 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+
+ ASSERT_TRUE(balance1 == wallet2->balance());
+ std::cout << "wallet balance: " << wallet2->balance() << std::endl;
+ ASSERT_TRUE(unlockedBalance1 == wallet2->unlockedBalance());
+ std::cout << "wallet unlocked balance: " << wallet2->unlockedBalance() << std::endl;
+ ASSERT_TRUE(wmgr->closeWallet(wallet2));
+}
+
+TEST_F(WalletTest1, WalletRefresh)
+{
+ Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+ // make sure testnet daemon is running
+ ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
+ ASSERT_TRUE(wallet1->refresh());
+ ASSERT_TRUE(wmgr->closeWallet(wallet1));
+}
+
+
+TEST_F(WalletTest1, WalletConvertsToString)
+{
+ std::string strAmount = Bitmonero::Wallet::displayAmount(AMOUNT_5XMR);
+ ASSERT_TRUE(AMOUNT_5XMR == Bitmonero::Wallet::amountFromString(strAmount));
+
+ ASSERT_TRUE(AMOUNT_5XMR == Bitmonero::Wallet::amountFromDouble(5.0));
+ ASSERT_TRUE(AMOUNT_10XMR == Bitmonero::Wallet::amountFromDouble(10.0));
+ ASSERT_TRUE(AMOUNT_1XMR == Bitmonero::Wallet::amountFromDouble(1.0));
+
+}
+
+
+/*
+TEST_F(WalletTest1, WalletTransaction)
+{
+ Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+ // make sure testnet daemon is running
+ ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
+ ASSERT_TRUE(wallet1->refresh());
+ uint64_t balance = wallet1->balance();
+ ASSERT_TRUE(wallet1->status() == Bitmonero::PendingTransaction::Status_Ok);
+
+ std::string recepient_address = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS);
+ wallet1->setDefaultMixin(1);
+ ASSERT_TRUE(wallet1->defaultMixin() == 1);
+
+ Bitmonero::PendingTransaction * transaction = wallet1->createTransaction(
+ recepient_address, AMOUNT_10XMR);
+ ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok);
+ wallet1->refresh();
+
+ ASSERT_TRUE(wallet1->balance() == balance);
+ ASSERT_TRUE(transaction->amount() == AMOUNT_10XMR);
+ ASSERT_TRUE(transaction->commit());
+ ASSERT_FALSE(wallet1->balance() == balance);
+ ASSERT_TRUE(wmgr->closeWallet(wallet1));
+}
+*/
+
+TEST_F(WalletTest1, WalletTransactionWithMixin)
+{
+
+ std::vector<int> mixins;
+ // 2,3,4,5,6,7,8,9,10,15,20,25 can we do it like that?
+ mixins.push_back(2); mixins.push_back(3); mixins.push_back(4); mixins.push_back(5); mixins.push_back(6);
+ mixins.push_back(7); mixins.push_back(8); mixins.push_back(9); mixins.push_back(10); mixins.push_back(15);
+ mixins.push_back(20); mixins.push_back(25);
+
+
+ std::string payment_id = "";
+
+ Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+
+
+ // make sure testnet daemon is running
+ ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
+ ASSERT_TRUE(wallet1->refresh());
+ uint64_t balance = wallet1->balance();
+ ASSERT_TRUE(wallet1->status() == Bitmonero::PendingTransaction::Status_Ok);
+
+ std::string recepient_address = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS);
+ for (auto mixin : mixins) {
+ std::cerr << "Transaction mixin count: " << mixin << std::endl;
+ Bitmonero::PendingTransaction * transaction = wallet1->createTransaction(
+ recepient_address, payment_id, AMOUNT_5XMR, mixin);
+
+ std::cerr << "Transaction status: " << transaction->status() << std::endl;
+ std::cerr << "Transaction fee: " << Bitmonero::Wallet::displayAmount(transaction->fee()) << std::endl;
+ std::cerr << "Transaction error: " << transaction->errorString() << std::endl;
+ ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok);
+ wallet1->disposeTransaction(transaction);
+ }
+
+ wallet1->refresh();
+
+ ASSERT_TRUE(wallet1->balance() == balance);
+ ASSERT_TRUE(wmgr->closeWallet(wallet1));
+}
+
+TEST_F(WalletTest1, WalletHistory)
+{
+ Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+ // make sure testnet daemon is running
+ ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
+ ASSERT_TRUE(wallet1->refresh());
+ Bitmonero::TransactionHistory * history = wallet1->history();
+ history->refresh();
+ ASSERT_TRUE(history->count() > 0);
+
+
+ for (auto t: history->getAll()) {
+ ASSERT_TRUE(t != nullptr);
+ Utils::print_transaction(t);
+ }
+}
+
+TEST_F(WalletTest1, WalletTransactionAndHistory)
+{
+ return;
+ Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+ // make sure testnet daemon is running
+ ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
+ ASSERT_TRUE(wallet_src->refresh());
+ Bitmonero::TransactionHistory * history = wallet_src->history();
+ history->refresh();
+ ASSERT_TRUE(history->count() > 0);
+ size_t count1 = history->count();
+
+ std::cout << "**** Transactions before transfer (" << count1 << ")" << std::endl;
+ for (auto t: history->getAll()) {
+ ASSERT_TRUE(t != nullptr);
+ Utils::print_transaction(t);
+ }
+
+ std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS);
+
+
+ Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr,
+ PAYMENT_ID_EMPTY,
+ AMOUNT_10XMR * 5, 0);
+
+ ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
+ ASSERT_TRUE(tx->commit());
+ history = wallet_src->history();
+ history->refresh();
+ ASSERT_TRUE(count1 != history->count());
+
+ std::cout << "**** Transactions after transfer (" << history->count() << ")" << std::endl;
+ for (auto t: history->getAll()) {
+ ASSERT_TRUE(t != nullptr);
+ Utils::print_transaction(t);
+ }
+}
+
+
+TEST_F(WalletTest1, WalletTransactionWithPaymentId)
+{
+
+ Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+ // make sure testnet daemon is running
+ ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
+ ASSERT_TRUE(wallet_src->refresh());
+ Bitmonero::TransactionHistory * history = wallet_src->history();
+ history->refresh();
+ ASSERT_TRUE(history->count() > 0);
+ size_t count1 = history->count();
+
+ std::cout << "**** Transactions before transfer (" << count1 << ")" << std::endl;
+ for (auto t: history->getAll()) {
+ ASSERT_TRUE(t != nullptr);
+ Utils::print_transaction(t);
+ }
+
+ std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS);
+
+ std::string payment_id = Bitmonero::Wallet::genPaymentId();
+ ASSERT_TRUE(payment_id.length() == 16);
+
+
+ Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr,
+ payment_id,
+ AMOUNT_1XMR, 1);
+
+ ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
+ ASSERT_TRUE(tx->commit());
+ history = wallet_src->history();
+ history->refresh();
+ ASSERT_TRUE(count1 != history->count());
+
+ bool payment_id_in_history = false;
+
+ std::cout << "**** Transactions after transfer (" << history->count() << ")" << std::endl;
+ for (auto t: history->getAll()) {
+ ASSERT_TRUE(t != nullptr);
+ Utils::print_transaction(t);
+ if (t->paymentId() == payment_id) {
+ payment_id_in_history = true;
+ }
+ }
+
+ ASSERT_TRUE(payment_id_in_history);
+}
+
+struct MyWalletListener : public Bitmonero::WalletListener
+{
+
+ Bitmonero::Wallet * wallet;
+ uint64_t total_tx;
+ uint64_t total_rx;
+ std::timed_mutex guard;
+
+ MyWalletListener(Bitmonero::Wallet * wallet)
+ : total_tx(0), total_rx(0)
+ {
+ this->wallet = wallet;
+ this->wallet->setListener(this);
+ }
+
+ virtual void moneySpent(const string &txId, uint64_t amount)
+ {
+ std::cout << "wallet: " << wallet->address() << " just spent money ("
+ << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl;
+ total_tx += amount;
+ guard.unlock();
+ }
+
+ virtual void moneyReceived(const string &txId, uint64_t amount)
+ {
+ std::cout << "wallet: " << wallet->address() << " just received money ("
+ << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl;
+ total_rx += amount;
+ guard.unlock();
+ }
+};
+
+/*
+TEST_F(WalletTest2, WalletCallbackSent)
+{
+
+ Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true);
+ // make sure testnet daemon is running
+ ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
+ ASSERT_TRUE(wallet_src->refresh());
+ MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src);
+ std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl;
+
+
+ uint64_t amount = AMOUNT_10XMR * 5;
+ std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << TESTNET_WALLET4_ADDRESS;
+ Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_1XMR * 5);
+ ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
+ ASSERT_TRUE(tx->commit());
+
+ std::chrono::seconds wait_for = std::chrono::seconds(60*3);
+
+ wallet_src_listener->guard.lock();
+ wallet_src_listener->guard.try_lock_for(wait_for);
+
+ ASSERT_TRUE(wallet_src_listener->total_tx != 0);
+}
+*/
+
+/*
+TEST_F(WalletTest2, WalletCallbackReceived)
+{
+
+ Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true);
+ // make sure testnet daemon is running
+ ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
+ ASSERT_TRUE(wallet_src->refresh());
+ std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl;
+
+ Bitmonero::Wallet * wallet_dst = wmgr->openWallet(TESTNET_WALLET4_NAME, TESTNET_WALLET_PASS, true);
+ ASSERT_TRUE(wallet_dst->init(TESTNET_DAEMON_ADDRESS, 0));
+ ASSERT_TRUE(wallet_dst->refresh());
+ MyWalletListener * wallet_dst_listener = new MyWalletListener(wallet_dst);
+
+
+ uint64_t amount = AMOUNT_1XMR * 5;
+ std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << TESTNET_WALLET4_ADDRESS;
+ Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_1XMR * 5);
+ ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
+ ASSERT_TRUE(tx->commit());
+
+ std::chrono::seconds wait_for = std::chrono::seconds(60*4);
+
+ wallet_dst_listener->guard.lock();
+ wallet_dst_listener->guard.try_lock_for(wait_for);
+
+ ASSERT_TRUE(wallet_dst_listener->total_tx != 0);
+
+}
+*/
int main(int argc, char** argv)
{
- //epee::debug::get_set_enable_assert(true, false);
+
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/tests/libwallet_api_tests/scripts/create_wallets.sh b/tests/libwallet_api_tests/scripts/create_wallets.sh
new file mode 100755
index 000000000..6abad84f9
--- /dev/null
+++ b/tests/libwallet_api_tests/scripts/create_wallets.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+function create_wallet {
+ wallet_name=$1
+ echo 0 | simplewallet --testnet --trusted-daemon --daemon-address localhost:38081 --generate-new-wallet $wallet_name --password "" --restore-height=1
+}
+
+
+
+create_wallet wallet_01.bin
+create_wallet wallet_02.bin
+create_wallet wallet_03.bin
+create_wallet wallet_04.bin
+create_wallet wallet_05.bin
+create_wallet wallet_06.bin
+
+
+#create_wallet wallet_m
+
+
diff --git a/tests/libwallet_api_tests/scripts/mining_start.sh b/tests/libwallet_api_tests/scripts/mining_start.sh
new file mode 100755
index 000000000..76eabfc55
--- /dev/null
+++ b/tests/libwallet_api_tests/scripts/mining_start.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+rlwrap simplewallet --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_m.log start_mining
+
diff --git a/tests/libwallet_api_tests/scripts/mining_stop.sh b/tests/libwallet_api_tests/scripts/mining_stop.sh
new file mode 100755
index 000000000..640e56943
--- /dev/null
+++ b/tests/libwallet_api_tests/scripts/mining_stop.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+rlwrap simplewallet --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_miner.log stop_mining
+
diff --git a/tests/libwallet_api_tests/scripts/open_wallet_1.sh b/tests/libwallet_api_tests/scripts/open_wallet_1.sh
new file mode 100755
index 000000000..08f4e28ab
--- /dev/null
+++ b/tests/libwallet_api_tests/scripts/open_wallet_1.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+
+rlwrap simplewallet --wallet-file wallet_01.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_01.log
+
diff --git a/tests/libwallet_api_tests/scripts/open_wallet_2.sh b/tests/libwallet_api_tests/scripts/open_wallet_2.sh
new file mode 100755
index 000000000..8a16a6647
--- /dev/null
+++ b/tests/libwallet_api_tests/scripts/open_wallet_2.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+
+rlwrap simplewallet --wallet-file wallet_02.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_01.log
+
diff --git a/tests/libwallet_api_tests/scripts/open_wallet_3.sh b/tests/libwallet_api_tests/scripts/open_wallet_3.sh
new file mode 100755
index 000000000..64a04b3c4
--- /dev/null
+++ b/tests/libwallet_api_tests/scripts/open_wallet_3.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+rlwrap simplewallet --wallet-file wallet_03.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_03.log
+
diff --git a/tests/libwallet_api_tests/scripts/open_wallet_4.sh b/tests/libwallet_api_tests/scripts/open_wallet_4.sh
new file mode 100755
index 000000000..8ebf0a4c7
--- /dev/null
+++ b/tests/libwallet_api_tests/scripts/open_wallet_4.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+rlwrap simplewallet --wallet-file wallet_04.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_04.log
+
diff --git a/tests/libwallet_api_tests/scripts/open_wallet_5.sh b/tests/libwallet_api_tests/scripts/open_wallet_5.sh
new file mode 100755
index 000000000..bbeb702c0
--- /dev/null
+++ b/tests/libwallet_api_tests/scripts/open_wallet_5.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+rlwrap simplewallet --wallet-file wallet_05.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_05.log
+
diff --git a/tests/libwallet_api_tests/scripts/open_wallet_miner.sh b/tests/libwallet_api_tests/scripts/open_wallet_miner.sh
new file mode 100755
index 000000000..07a4e58ea
--- /dev/null
+++ b/tests/libwallet_api_tests/scripts/open_wallet_miner.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+rlwrap simplewallet --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address 127.0.0.1:38081 --log-file wallet_m.log
+
diff --git a/tests/libwallet_api_tests/scripts/send_funds.sh b/tests/libwallet_api_tests/scripts/send_funds.sh
new file mode 100755
index 000000000..306b06a40
--- /dev/null
+++ b/tests/libwallet_api_tests/scripts/send_funds.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+
+
+function send_funds {
+ local amount=$1
+ local dest=$(cat "$2.address.txt")
+
+ simplewallet --wallet-file wallet_m --password "" \
+ --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_m.log \
+ --command transfer $dest $amount
+}
+
+
+send_funds 100 wallet_01.bin
+send_funds 100 wallet_02.bin
+send_funds 100 wallet_03.bin
+send_funds 100 wallet_04.bin
+send_funds 100 wallet_05.bin
+send_funds 100 wallet_06.bin
+
+