diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3a59c45..60e7a36 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,6 +38,7 @@ set(LIBS ${LIBS} "-lcpprest")
include_directories(src)
include_directories(src/wallets)
include_directories(src/exchanges)
+include_directories(src/datasources)
set(CMAKE_CXX_STANDARD 11)
diff --git a/cmake/Modules/Findsqlpp11-connector-mysql.cmake b/cmake/Modules/Findsqlpp11-connector-mysql.cmake
index 301fb2e..20e509a 100644
--- a/cmake/Modules/Findsqlpp11-connector-mysql.cmake
+++ b/cmake/Modules/Findsqlpp11-connector-mysql.cmake
@@ -29,7 +29,7 @@ if (SQLPP11_MYSQL_MAIN_HEADER)
)
if("${check_result}" STREQUAL "")
- string(APPEND SQLPP11_NOT_FOUND_MESSAGE "\nRejecting found '${SQLPP11_MYSQL_MAIN_HEADER}', it seems to be invalid.")
+ string(APPEND SQLPP11_MYSQL_NOT_FOUND_MESSAGE "\nRejecting found '${SQLPP11_MYSQL_MAIN_HEADER}', it seems to be invalid.")
unset(SQLPP11_MYSQL_INCLUDE_DIR CACHE)
else()
# Check succeeded, create target
diff --git a/sql/mysql.schema.sql b/sql/mysql.schema.sql
index 2c0006f..cffd9a4 100644
--- a/sql/mysql.schema.sql
+++ b/sql/mysql.schema.sql
@@ -7,6 +7,37 @@ SET time_zone = "+00:00";
/*!40101 SET NAMES utf8mb4 */;
+CREATE TABLE `blockchain_btc_raw_tx` (
+ `raw_tx_id` int(11) NOT NULL,
+ `blockchain_id` int(11) NOT NULL,
+ `hash` varchar(200) NOT NULL,
+ `unix_time` int(11) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE `blockchain_btc_raw_tx_details` (
+ `raw_tx_detail_id` int(11) NOT NULL,
+ `raw_tx_id` int(11) NOT NULL,
+ `amount` decimal(40,18) NOT NULL,
+ `address` varchar(100) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE `blockchain_eth_raw_tx` (
+ `raw_tx_id` int(11) NOT NULL,
+ `blockchain_id` int(11) NOT NULL,
+ `hash` varchar(200) NOT NULL,
+ `unix_time` int(11) NOT NULL,
+ `fee` decimal(40,18) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE `blockchain_eth_raw_tx_details` (
+ `raw_tx_detail_id` int(11) NOT NULL,
+ `raw_tx_id` int(11) NOT NULL,
+ `address_from` varchar(200) NOT NULL,
+ `address_to` varchar(200) NOT NULL,
+ `amount` decimal(40,18) NOT NULL,
+ `amount_coin_id` int(11) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
CREATE TABLE `coins` (
`coin_id` int(11) NOT NULL,
`coin_name` varchar(50) NOT NULL,
@@ -32,7 +63,7 @@ CREATE TABLE `exchanges_ledgers` (
`account_id` int(11) NOT NULL,
`exchange_ledger_id` varchar(50) NOT NULL,
`exchange_reference_id` varchar(50) NOT NULL,
- `timestamp` int(11) NOT NULL,
+ `unix_time` int(11) NOT NULL,
`operation_type` int(11) NOT NULL,
`coin_id` int(11) NOT NULL,
`amount` decimal(40,18) NOT NULL,
@@ -46,7 +77,7 @@ CREATE TABLE `exchanges_trades` (
`exchange_order_id` varchar(50) NOT NULL,
`base_coin_id` int(11) NOT NULL,
`quote_coin_id` int(11) NOT NULL,
- `timestamp` int(11) NOT NULL,
+ `unix_time` int(11) NOT NULL,
`type` int(11) NOT NULL,
`order_type` int(11) NOT NULL,
`price` decimal(40,18) NOT NULL,
@@ -60,7 +91,8 @@ CREATE TABLE `wallets` (
`wallet_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`type_id` int(11) NOT NULL,
- `wallet_name` varchar(50) NOT NULL
+ `wallet_name` varchar(50) NOT NULL,
+ `active` tinyint(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `wallets_addresses` (
@@ -77,16 +109,40 @@ CREATE TABLE `wallets_balances` (
`balance` decimal(48,18) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+CREATE TABLE `wallets_btc_raw_tx` (
+ `raw_tx_id` int(11) NOT NULL,
+ `wallet_id` int(11) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE `wallets_eth_raw_tx` (
+ `raw_tx_id` int(11) NOT NULL,
+ `wallet_id` int(11) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
CREATE TABLE `wallets_tx` (
`tx_id` int(11) NOT NULL,
- `blockchain_tx_id` varchar(200) NOT NULL,
`wallet_id` int(11) NOT NULL,
`amount` decimal(40,18) NOT NULL,
`fee` decimal(40,18) NOT NULL,
- `timestamp` int(11) NOT NULL
+ `amount_coin_id` int(11) NOT NULL,
+ `fee_coin_id` int(11) NOT NULL,
+ `unix_time` int(11) NOT NULL,
+ `operation_type` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+ALTER TABLE `blockchain_btc_raw_tx`
+ ADD PRIMARY KEY (`raw_tx_id`);
+
+ALTER TABLE `blockchain_btc_raw_tx_details`
+ ADD PRIMARY KEY (`raw_tx_detail_id`);
+
+ALTER TABLE `blockchain_eth_raw_tx`
+ ADD PRIMARY KEY (`raw_tx_id`);
+
+ALTER TABLE `blockchain_eth_raw_tx_details`
+ ADD PRIMARY KEY (`raw_tx_detail_id`);
+
ALTER TABLE `exchanges_accounts`
ADD PRIMARY KEY (`account_id`);
@@ -103,12 +159,20 @@ ALTER TABLE `wallets_addresses`
ADD PRIMARY KEY (`address_id`);
ALTER TABLE `wallets_balances`
- ADD PRIMARY KEY (`wallet_id`);
+ ADD PRIMARY KEY (`wallet_id`,`coin_id`);
ALTER TABLE `wallets_tx`
ADD PRIMARY KEY (`tx_id`);
+ALTER TABLE `blockchain_btc_raw_tx`
+ MODIFY `raw_tx_id` int(11) NOT NULL AUTO_INCREMENT;
+ALTER TABLE `blockchain_btc_raw_tx_details`
+ MODIFY `raw_tx_detail_id` int(11) NOT NULL AUTO_INCREMENT;
+ALTER TABLE `blockchain_eth_raw_tx`
+ MODIFY `raw_tx_id` int(11) NOT NULL AUTO_INCREMENT;
+ALTER TABLE `blockchain_eth_raw_tx_details`
+ MODIFY `raw_tx_detail_id` int(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE `exchanges_accounts`
MODIFY `account_id` int(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE `exchanges_ledgers`
@@ -123,4 +187,4 @@ ALTER TABLE `wallets_tx`
MODIFY `tx_id` int(11) NOT NULL AUTO_INCREMENT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 852e4ef..027fee8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,7 @@
aux_source_directory(. SOURCE_LIST)
aux_source_directory(wallets SOURCE_LIST_WALLETS)
aux_source_directory(exchanges SOURCE_LIST_EXCHANGES)
+aux_source_directory(datasources SOURCE_LIST_DATASOURCES)
-add_executable(${EXECUTABLE} ${SOURCE_LIST} ${SOURCE_LIST_WALLETS} ${SOURCE_LIST_EXCHANGES})
+add_executable(${EXECUTABLE} ${SOURCE_LIST} ${SOURCE_LIST_WALLETS} ${SOURCE_LIST_EXCHANGES} ${SOURCE_LIST_DATASOURCES})
target_link_libraries(${EXECUTABLE} ${LIBS})
diff --git a/src/datasources/blockchain_info.cpp b/src/datasources/blockchain_info.cpp
new file mode 100644
index 0000000..47d2d87
--- /dev/null
+++ b/src/datasources/blockchain_info.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#include "datasources/blockchain_info.h"
+
+list BlockchainDataSourceBTC_BlockchainInfo::getTxDetailsListForAddress(string address)
+{
+ linfo << "Blockchain.info : Analyzing address: " << address;
+
+ list l;
+
+ if (!bfs::exists(getCacheFilenameForAddress(address)))
+ {
+ saveBlockchainAddressDataToCacheFile(address);
+ }
+
+ if (!bfs::exists(getCacheFilenameForAddress(address)))
+ {
+ lerr << "Blockchain.info : cache file could not be found. Address data was not retrieved.";
+ return l;
+ }
+
+ ifstream f;
+ f.open(getCacheFilenameForAddress(address));
+ json::value jvalue = json::value::parse(f);
+ f.close();
+
+ linfo << "Blockchain.info : analyzing address: " << jvalue["address"].as_string();
+
+ for (int i=0;i previousTask)
+ {
+ if (previousTask.get() != json::value::null())
+ {
+ linfo << "Blockchain.info : saving query result to " << m_currentRequestCacheFilename;
+ ofstream f;
+ f.open(m_currentRequestCacheFilename);
+ f << previousTask.get();
+ f.close();
+ }
+ else
+ {
+ lerr << "Blockchain.info : query result is empty. Nothing will be saved to the cache file.";
+ }
+ })
+ .wait();
+ }
+ catch(const http::http_exception& e)
+ {
+ lerr << "Blockchain.info : failed to query API about " << address;
+ }
+}
diff --git a/src/datasources/blockchain_info.h b/src/datasources/blockchain_info.h
new file mode 100644
index 0000000..3a9e062
--- /dev/null
+++ b/src/datasources/blockchain_info.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#ifndef CPFM_DATASOURCE_BLOCKCHAIN_INFO_H_INCLUDED
+#define CPFM_DATASOURCE_BLOCKCHAIN_INFO_H_INCLUDED
+
+#include "datasources/datasource.h"
+
+
+class BlockchainDataSourceBTC_BlockchainInfo
+{
+public:
+ list getTxDetailsListForAddress(string address);
+
+private:
+ string getCacheFilenameForAddress(string address);
+ void saveBlockchainAddressDataToCacheFile(string address);
+
+ string m_currentRequestCacheFilename;
+};
+
+#endif // CPFM_DATASOURCE_BLOCKCHAIN_INFO_H_INCLUDED
\ No newline at end of file
diff --git a/src/datasources/blockchair.cpp b/src/datasources/blockchair.cpp
new file mode 100644
index 0000000..0fcc8b0
--- /dev/null
+++ b/src/datasources/blockchair.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#include "datasources/blockchair.h"
+
+
+Time BlockchainDataSourceTypeBTC_Blockchair::getTimeFromString(string s)
+{
+ std::istringstream in{s};
+ date::sys_time tp;
+ in >> date::parse("%F %T", tp);
+
+ Time t;
+ t.setFromUnixTime(std::chrono::system_clock::to_time_t(tp));
+
+ return t;
+}
+
+list BlockchainDataSourceTypeBTC_Blockchair::getTxDetailsListForAddresses(list addresses)
+{
+ linfo << "Blockchair : analyzing address list";
+
+ list l;
+
+ if (!bfs::exists(getCacheFilenameForAddresses(addresses)))
+ {
+ saveBlockchainAddressesDataToCacheFile(addresses);
+ }
+
+ if (!bfs::exists(getCacheFilenameForAddresses(addresses)))
+ {
+ lerr << "Blockchair : cache file could not be found. Addresses data was not retrieved.";
+ return l;
+ }
+
+ ifstream f;
+ f.open(getCacheFilenameForAddresses(addresses));
+ json::value jvalue = json::value::parse(f);
+ f.close();
+
+ for (int i=0;i addresses)
+{
+ string s;
+
+ for (const auto a: addresses)
+ s = s+a;
+
+ string cacheFilename("data/cache/blockchair/"+m_blockchainName+"/addresses/" + s);
+ return cacheFilename;
+}
+
+string BlockchainDataSourceTypeBTC_Blockchair::getCacheFilenameForTx(string txHash)
+{
+ string cacheFilename("data/cache/blockchair/"+m_blockchainName+"/tx/" + txHash);
+ return cacheFilename;
+}
+
+void BlockchainDataSourceTypeBTC_Blockchair::saveBlockchainAddressesDataToCacheFile(list addresses)
+{
+ try
+ {
+ string s;
+
+ for (const auto a: addresses)
+ {
+ if (s.length())
+ s = s+","+a;
+ else
+ s = a;
+ }
+
+ linfo << "Blockchair : querying API about addresses : " << s;
+
+ string sRequestURL = "/"+m_blockchainName+"/dashboards/addresses/";
+ sRequestURL += s;
+ http_client apiclient("https://api.blockchair.com/");
+
+ m_currentRequestCacheFilename = getCacheFilenameForAddresses(addresses);
+
+ ltrace << "Blockchair : query : " << sRequestURL;
+
+ apiclient.request(methods::GET,sRequestURL).then([](http_response response)
+ {
+ if (response.status_code() == status_codes::OK)
+ {
+ ldebug << "Blockchair : response OK.";
+ return response.extract_json();
+ }
+ else if (response.status_code() == status_codes::TooManyRequests)
+ {
+ lwarn << "Blockchair : too many queries! We are being rate limited.";
+ pplx::task_from_result(json::value());
+ }
+ return pplx::task_from_result(json::value());
+ })
+ .then([this](pplx::task previousTask)
+ {
+ if (previousTask.get() != json::value::null())
+ {
+ linfo << "Blockchair : saving query result to " << m_currentRequestCacheFilename;
+ ofstream f;
+ f.open(m_currentRequestCacheFilename);
+ f << previousTask.get();
+ f.close();
+ }
+ else
+ {
+ lerr << "Blockchair : query result is empty. Nothing will be saved to the cache file.";
+ }
+ })
+ .wait();
+ }
+ catch(const http::http_exception& e)
+ {
+ lerr << "Blockchair : failed to query API";
+ }
+}
+
+void BlockchainDataSourceTypeBTC_Blockchair::saveBlockchainTxDataToCacheFile(string txHash)
+{
+ try
+ {
+ linfo << "Blockchair : querying API about tx : " << txHash;
+
+ string sRequestURL = "/"+m_blockchainName+"/dashboards/transaction/";
+ sRequestURL += txHash;
+ http_client apiclient("https://api.blockchair.com/");
+
+ m_currentRequestCacheFilename = getCacheFilenameForTx(txHash);
+
+ ltrace << "Blockchair : query : " << sRequestURL;
+
+ apiclient.request(methods::GET,sRequestURL).then([](http_response response)
+ {
+ if (response.status_code() == status_codes::OK)
+ {
+ ldebug << "Blockchair : response OK.";
+ return response.extract_json();
+ }
+ else if (response.status_code() == status_codes::TooManyRequests)
+ {
+ lwarn << "Blockchair : too many queries! We are being rate limited.";
+ pplx::task_from_result(json::value());
+ }
+ return pplx::task_from_result(json::value());
+ })
+ .then([this](pplx::task previousTask)
+ {
+ if (previousTask.get() != json::value::null())
+ {
+ linfo << "Blockchair : saving query result to " << m_currentRequestCacheFilename;
+ ofstream f;
+ f.open(m_currentRequestCacheFilename);
+ f << previousTask.get();
+ f.close();
+ }
+ else
+ {
+ lerr << "Blockchair : query result is empty. Nothing will be saved to the cache file.";
+ }
+ })
+ .wait();
+ }
+ catch(const http::http_exception& e)
+ {
+ lerr << "Blockchair : failed to query API about " << txHash;
+ }
+}
diff --git a/src/datasources/blockchair.h b/src/datasources/blockchair.h
new file mode 100644
index 0000000..d4ed472
--- /dev/null
+++ b/src/datasources/blockchair.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#ifndef CPFM_DATASOURCE_BLOCKCHAIR_H_INCLUDED
+#define CPFM_DATASOURCE_BLOCKCHAIR_H_INCLUDED
+
+#include "datasources/datasource.h"
+
+
+class BlockchainDataSourceTypeBTC_Blockchair
+{
+public:
+ list getTxDetailsListForAddresses(list addresses);
+
+private:
+ string getCacheFilenameForAddresses(list address);
+ string getCacheFilenameForTx(string txHash);
+
+ void saveBlockchainAddressesDataToCacheFile(list address);
+ void saveBlockchainTxDataToCacheFile(string txHash);
+
+ Time getTimeFromString(string s);
+
+ string m_currentRequestCacheFilename;
+
+protected:
+ string m_blockchainName;
+
+ virtual void dummyMakeAbstract() = 0;
+};
+
+class BlockchainDataSourceBTC_Blockchair : public BlockchainDataSourceTypeBTC_Blockchair
+{
+public:
+ BlockchainDataSourceBTC_Blockchair() { m_blockchainName = "bitcoin"; }
+
+protected:
+ virtual void dummyMakeAbstract(){};
+};
+
+class BlockchainDataSourceBCH_Blockchair : public BlockchainDataSourceTypeBTC_Blockchair
+{
+public:
+ BlockchainDataSourceBCH_Blockchair() { m_blockchainName = "bitcoin-cash"; }
+
+protected:
+ virtual void dummyMakeAbstract(){};
+};
+
+#endif // CPFM_DATASOURCE_BLOCKCHAIR_H_INCLUDED
\ No newline at end of file
diff --git a/src/datasources/datasource.cpp b/src/datasources/datasource.cpp
new file mode 100644
index 0000000..48648a1
--- /dev/null
+++ b/src/datasources/datasource.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#include "datasources/datasource.h"
+#include "datasources/blockchain_info.h"
+#include "datasources/blockchair.h"
+#include "datasources/etherscan.h"
+
+list BlockchainDataSourceBTC::getTxDetailsListForAddresses(list addresses)
+{
+ list l;
+
+ // Blockchain.info
+ /*
+ BlockchainDataSourceBTC_BlockchainInfo bci;
+ list hashList;
+
+ for (auto const address: addresses)
+ {
+ list listForSingleAddress = bci.getTxDetailsListForAddress(address);
+
+ for (auto const tx: listForSingleAddress)
+ {
+ if (std::find(hashList.begin(), hashList.end(), tx.hash) == hashList.end())
+ {
+ hashList.push_back(tx.hash);
+ l.push_back(tx);
+ }
+ }
+ }
+ */
+
+ // Blockchair
+ BlockchainDataSourceBTC_Blockchair bc;
+ l = bc.getTxDetailsListForAddresses(addresses);
+
+ return l;
+}
+
+list BlockchainDataSourceBCH::getTxDetailsListForAddresses(list addresses)
+{
+ list l;
+
+ // Blockchair
+ BlockchainDataSourceBCH_Blockchair bc;
+ l = bc.getTxDetailsListForAddresses(addresses);
+
+ return l;
+}
+
+list BlockchainDataSourceETH::getTxDetailsListForAddress(string address)
+{
+ list l;
+
+ // Etherscan
+ BlockchainDataSourceETH_Etherscan bc;
+ l = bc.getTxDetailsListForAddress(address);
+
+ return l;
+}
diff --git a/src/datasources/datasource.h b/src/datasources/datasource.h
new file mode 100644
index 0000000..a7da1de
--- /dev/null
+++ b/src/datasources/datasource.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#ifndef CPFM_DATASOURCE_H_INCLUDED
+#define CPFM_DATASOURCE_H_INCLUDED
+
+#include "pf.h"
+
+class BlockchainTxDetailsTypeBTC
+{
+public:
+ string hash;
+ Time time;
+ map inputs;
+ map outputs;
+};
+
+class BlockchainTxOperationTypeETH
+{
+public:
+ string addressFrom;
+ string addressTo;
+ Money amount;
+ int amountCoinId;
+};
+
+class BlockchainTxDetailsTypeETH
+{
+public:
+ string hash;
+ Time time;
+ list operations;
+ Money fee;
+};
+
+class BlockchainDataSourceBTC
+{
+public:
+ list getTxDetailsListForAddresses(list addresses);
+};
+
+class BlockchainDataSourceBCH
+{
+public:
+ list getTxDetailsListForAddresses(list addresses);
+};
+
+class BlockchainDataSourceETH
+{
+public:
+ list getTxDetailsListForAddress(string address);
+};
+
+#endif // CPFM_DATASOURCE_H_INCLUDED
\ No newline at end of file
diff --git a/src/datasources/etherscan.cpp b/src/datasources/etherscan.cpp
new file mode 100644
index 0000000..a28218f
--- /dev/null
+++ b/src/datasources/etherscan.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#include "datasources/etherscan.h"
+
+#define TXLIST_NORMAL "txlist"
+#define TXLIST_INTERNAL "txlistinternal"
+#define TXLIST_TOKENS "tokentx"
+
+list BlockchainDataSourceETH_Etherscan::getTxDetailsListForAddress(string address)
+{
+ linfo << "Etherscan : Analyzing address: " << address;
+
+ if (!retrieveCacheFilesForAddress(address))
+ {
+ list l;
+ lerr << "Etherscan : cache files could not be found. Address data was not retrieved.";
+ return l;
+ }
+
+ list hashListNormal;
+ list hashListInternal;
+ list hashListToken;
+
+ list lNormal = getTxDetailsListForAddressTxType(address,TXLIST_NORMAL,hashListNormal);
+ list lInternal = getTxDetailsListForAddressTxType(address,TXLIST_INTERNAL,hashListInternal);
+ list lToken = getTxDetailsListForAddressTxType(address,TXLIST_TOKENS,hashListToken);
+
+ list l = lNormal;
+
+ // Add internals tx to the list
+ for (auto const tx: lInternal)
+ {
+ BlockchainTxDetailsTypeETH txNew = tx;
+
+ list::iterator it;
+ for (it=l.begin();it!=l.end();it++)
+ {
+ if (it->hash == tx.hash)
+ {
+ txNew = (*it);
+ for (const auto op: tx.operations)
+ {
+ txNew.operations.push_back(op);
+ }
+
+ l.erase(it);
+ break;
+ }
+ }
+
+ l.push_back(txNew);
+ }
+
+ // Add tokens tx to the list
+ for (auto const tx: lToken)
+ {
+ BlockchainTxDetailsTypeETH txNew = tx;
+
+ list::iterator it;
+ for (it=l.begin();it!=l.end();it++)
+ {
+ if (it->hash == tx.hash)
+ {
+ txNew = (*it);
+ for (const auto op: tx.operations)
+ {
+ txNew.operations.push_back(op);
+ }
+
+ l.erase(it);
+ break;
+ }
+ }
+
+ l.push_back(txNew);
+ }
+
+ return l;
+}
+
+list BlockchainDataSourceETH_Etherscan::getTxDetailsListForAddressTxType(string address, string type, list& hashList)
+{
+ list l;
+
+ ifstream f;
+ f.open(getCacheFilenameForAddress(address,type));
+ json::value jvalue = json::value::parse(f);
+ f.close();
+
+ linfo << "Etherscan : analyzing " << type << " for address: " << address;
+
+ if (!jvalue["status"].as_string().compare("1"))
+ {
+ for (int i=0;i::iterator it;
+ for (it=l.begin();it!=l.end();it++)
+ {
+ if (it->hash == jvalue["result"][i]["hash"].as_string())
+ {
+ ltrace << "Tx already existed. Removing from list so it can be updated with new values.";
+ tx = (*it);
+ l.erase(it);
+ break;
+ }
+ }
+
+ tx.hash = jvalue["result"][i]["hash"].as_string();
+ tx.time.setFromUnixTime(strtol(jvalue["result"][i]["timeStamp"].as_string().c_str(),NULL,10));
+
+ Money gasUsed (jvalue["result"][i]["gasUsed"]);
+ Money gasPrice (jvalue["result"][i]["gasPrice"]);
+ Money fee = gasPrice*gasUsed;
+ Money feeDivider("1000000000000000000");
+ fee /= feeDivider;
+ tx.fee = fee;
+
+ if (type == TXLIST_NORMAL)
+ {
+ BlockchainTxOperationTypeETH op;
+ op.addressFrom = jvalue["result"][i]["from"].as_string();
+ op.addressTo = jvalue["result"][i]["to"].as_string();
+ op.amountCoinId = CPFM_COIN_ID_ETH;
+
+ Money divider("1000000000000000000");
+ Money m(jvalue["result"][i]["value"]);
+ m /= divider;
+ op.amount = m;
+
+ ltrace << "Operation. Amount: " << op.amount << ". Coin : " << getCoinName(op.amountCoinId);
+
+ tx.operations.push_back(op);
+ }
+ else if (type == TXLIST_TOKENS)
+ {
+ BlockchainTxOperationTypeETH op;
+ op.addressFrom = jvalue["result"][i]["from"].as_string();
+ op.addressTo = jvalue["result"][i]["to"].as_string();
+ op.amountCoinId = GetCoinIdFromContractAddress(jvalue["result"][i]["contractAddress"].as_string());
+
+ if (!op.amountCoinId)
+ {
+ lerr << "Unknown token : " << jvalue["result"][i]["tokenSymbol"].as_string() << ". Tx will be ignored.";
+ continue;
+ }
+
+ Money divider = 1;
+ int multiplier = strtol(jvalue["result"][i]["tokenDecimal"].as_string().c_str(),NULL,10);
+ for (int i=0;i previousTask)
+ {
+ if (previousTask.get() != json::value::null())
+ {
+ linfo << "Etherscan : saving query result to " << m_currentRequestCacheFilename;
+ ofstream f;
+ f.open(m_currentRequestCacheFilename);
+ f << previousTask.get();
+ f.close();
+ }
+ else
+ {
+ lerr << "Etherscan : query result is empty. Nothing will be saved to the cache file.";
+ }
+ })
+ .wait();
+ }
+ catch(const http::http_exception& e)
+ {
+ lerr << "Etherscan : failed to query API about " << address;
+ }
+}
+
+int BlockchainDataSourceETH_Etherscan::GetCoinIdFromContractAddress(string contractAddress)
+{
+ // LPT - Livepeer Token
+ if (contractAddress == "0x58b6a8a3302369daec383334672404ee733ab239")
+ return CPFM_COIN_ID_LPT;
+
+ // LEND - EthLend - Migrated to AAVE.
+ if (contractAddress == "0x80fb784b7ed66730e8b1dbd9820afd29931aab03")
+ return CPFM_COIN_ID_LEND;
+
+ // AAVE
+ if (contractAddress == "0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9")
+ return CPFM_COIN_ID_AAVE;
+
+ // BCDT - Blockchain Certified Data Token.
+ if (contractAddress == "0xacfa209fb73bf3dd5bbfb1101b9bc999c49062a5")
+ return CPFM_COIN_ID_BCDT;
+
+ // KNC - Kyber Network
+ if (contractAddress == "0xdd974d5c2e2928dea5f71b9825b8b646686bd200")
+ return CPFM_COIN_ID_KNC;
+
+ // AIR - AirToken
+ if (contractAddress == "0x27dce1ec4d3f72c3e457cc50354f1f975ddef488")
+ return CPFM_COIN_ID_AIR;
+
+ lerr << "Unsupported contact address " << contractAddress;
+ return 0;
+}
\ No newline at end of file
diff --git a/src/datasources/etherscan.h b/src/datasources/etherscan.h
new file mode 100644
index 0000000..0aaf10a
--- /dev/null
+++ b/src/datasources/etherscan.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#ifndef CPFM_DATASOURCE_ETHERSCAN_H_INCLUDED
+#define CPFM_DATASOURCE_ETHERSCAN_H_INCLUDED
+
+#include "datasources/datasource.h"
+
+
+class BlockchainDataSourceETH_Etherscan
+{
+public:
+ list getTxDetailsListForAddress(string address);
+
+private:
+ list getTxDetailsListForAddressTxType(string address, string type, list& hashList);
+ void saveBlockchainAddressDataToCacheFile(string address, string type);
+ string getCacheFilenameForAddress(string address, string type);
+ bool retrieveCacheFilesForAddress(string address);
+ int GetCoinIdFromContractAddress(string contractAddress);
+
+ string m_currentRequestCacheFilename;
+};
+
+#endif // CPFM_DATASOURCE_ETHERSCAN_H_INCLUDED
\ No newline at end of file
diff --git a/src/exchanges/kraken.cpp b/src/exchanges/kraken.cpp
index e118193..ee920f5 100644
--- a/src/exchanges/kraken.cpp
+++ b/src/exchanges/kraken.cpp
@@ -47,10 +47,10 @@ void ExchangeHandlerKraken::analyzeUserData()
getAccountBalance();
analyzeAccountBalance();
- //getAccountTrades();
+ getAccountTrades();
//analyzeAccountTrades();
- //getAccountLedgers();
+ getAccountLedgers();
//analyzeAccountLedgers();
}
diff --git a/src/log.cpp b/src/log.cpp
index 8f878e9..0594825 100644
--- a/src/log.cpp
+++ b/src/log.cpp
@@ -23,7 +23,7 @@
#include
#include "log.h"
-using namespace farm;
+using namespace cpfm;
using namespace log;
const char* ErrorLogger::name() { return "ERROR"; }
@@ -34,6 +34,8 @@ const char* InfoLogger::name() { return "INFO "; }
const char* InfoLogger::color() { return L_White; }
const char* DebugLogger::name() { return "DEBUG"; }
const char* DebugLogger::color() { return L_Teal; }
+const char* TraceLogger::name() { return "TRACE"; }
+const char* TraceLogger::color() { return L_Violet; }
LoggerBase::LoggerBase()
{
diff --git a/src/log.h b/src/log.h
index bb15bc2..bf56959 100644
--- a/src/log.h
+++ b/src/log.h
@@ -28,13 +28,14 @@
using namespace std;
-#define llog(X) farm::log::Logger()
-#define lerr llog(farm::log::ErrorLogger)
-#define linfo llog(farm::log::InfoLogger)
-#define lwarn llog(farm::log::WarningLogger)
-#define ldebug llog(farm::log::DebugLogger)
+#define llog(X) cpfm::log::Logger()
+#define lerr llog(cpfm::log::ErrorLogger)
+#define linfo llog(cpfm::log::InfoLogger)
+#define lwarn llog(cpfm::log::WarningLogger)
+#define ldebug llog(cpfm::log::DebugLogger)
+#define ltrace llog(cpfm::log::TraceLogger)
-namespace farm { namespace log {
+namespace cpfm { namespace log {
#define L_Reset "\x1b[0m" // Text Reset
@@ -107,6 +108,7 @@ struct ErrorLogger: public DefaultLogger { static const char* name(); static con
struct WarningLogger: public DefaultLogger { static const char* name(); static const char* color(); };
struct InfoLogger: public DefaultLogger { static const char* name(); static const char* color(); };
struct DebugLogger: public DefaultLogger { static const char* name(); static const char* color(); };
+struct TraceLogger: public DefaultLogger { static const char* name(); static const char* color(); };
class LoggerBase
{
diff --git a/src/money.cpp b/src/money.cpp
index 38a7894..6d3cd3a 100644
--- a/src/money.cpp
+++ b/src/money.cpp
@@ -23,7 +23,7 @@
Money::Money ()
{
-
+ m_amount = 0;
}
Money::Money (bmp::mpf_float_50 x)
diff --git a/src/money.h b/src/money.h
index 3d63826..ae273b1 100644
--- a/src/money.h
+++ b/src/money.h
@@ -54,7 +54,7 @@ public:
Money& operator/=(const Money& x);
friend Money operator/(Money a, const Money& b) { a /= b; return a; }
- Money operator-() { return Money(-m_amount); }
+ //Money operator-() { return Money(-m_amount); }
friend bool operator==(const Money& a, const int& b);
friend bool operator!=(const Money& a, const int& b) { return !operator==(a,b); }
diff --git a/src/pf.cpp b/src/pf.cpp
index 2f8b497..09dce7e 100644
--- a/src/pf.cpp
+++ b/src/pf.cpp
@@ -40,8 +40,8 @@ void PortfolioManager::doTestStuff()
// Test user 1
emptyUserBalances(1);
- ExchangesManager exchangesManager(1);
- exchangesManager.analyzeUserAccounts();
+// ExchangesManager exchangesManager(1);
+// exchangesManager.analyzeUserAccounts();
WalletsManager walletsManager(1);
walletsManager.analyzeUserWallets();
@@ -49,6 +49,7 @@ void PortfolioManager::doTestStuff()
displayUserBalances(1);
// Test user 2
+ /*
emptyUserBalances(2);
ExchangesManager exchangesManagerTwo(2);
@@ -58,6 +59,7 @@ void PortfolioManager::doTestStuff()
walletsManagerTwo.analyzeUserWallets();
displayUserBalances(2);
+ */
}
void PortfolioManager::emptyUserBalances(int userId)
@@ -155,6 +157,24 @@ string getCoinName(int coinId)
case CPFM_COIN_ID_BTG:
s = "BTG";
break;
+ case CPFM_COIN_ID_LPT:
+ s = "LPT";
+ break;
+ case CPFM_COIN_ID_BCDT:
+ s = "BCDT";
+ break;
+ case CPFM_COIN_ID_AIR:
+ s = "AIR";
+ break;
+ case CPFM_COIN_ID_AAVE:
+ s = "AAVE";
+ break;
+ case CPFM_COIN_ID_LEND:
+ s = "LEND";
+ break;
+ case CPFM_COIN_ID_KNC:
+ s = "KNC";
+ break;
default:
s = "Error!";
break;
diff --git a/src/pf.h b/src/pf.h
index e474951..85b3f9d 100644
--- a/src/pf.h
+++ b/src/pf.h
@@ -39,14 +39,31 @@
#include "log.h"
#include "money.h"
-#define CPFM_COIN_ID_BTC 1
-#define CPFM_COIN_ID_LTC 2
-#define CPFM_COIN_ID_EUR 3
-#define CPFM_COIN_ID_ICN 4
-#define CPFM_COIN_ID_ETC 5
-#define CPFM_COIN_ID_ETH 6
-#define CPFM_COIN_ID_BCH 7
-#define CPFM_COIN_ID_BTG 8
+#define CPFM_COIN_ID_BTC 1
+#define CPFM_COIN_ID_LTC 2
+#define CPFM_COIN_ID_EUR 3
+#define CPFM_COIN_ID_ICN 4
+#define CPFM_COIN_ID_ETC 5
+#define CPFM_COIN_ID_ETH 6
+#define CPFM_COIN_ID_BCH 7
+#define CPFM_COIN_ID_BTG 8
+#define CPFM_COIN_ID_KNC 9
+#define CPFM_COIN_ID_AIR 10
+#define CPFM_COIN_ID_LEND 11
+#define CPFM_COIN_ID_AAVE 12
+#define CPFM_COIN_ID_LPT 13
+#define CPFM_COIN_ID_BCDT 14
+
+class Time
+{
+public:
+ void setFromUnixTime(time_t unixTime) { m_unixTime = unixTime; }
+ const time_t toUnixTime() const { return m_unixTime; }
+
+private:
+ time_t m_unixTime;
+ //date::sys_time
+};
namespace bmp = boost::multiprecision;
namespace bfs = boost::filesystem;
diff --git a/src/pricesource.cpp b/src/pricesource.cpp
index 8241638..a2f0136 100644
--- a/src/pricesource.cpp
+++ b/src/pricesource.cpp
@@ -115,7 +115,7 @@ Money PriceSourceCryptoWatch::getCoinPriceFromData(int coinId)
{
Money x (jvalue["result"]["market:kraken:icnbtc"]);
Money y (jvalue["result"]["market:kraken:btceur"]);
- ldebug << "ICN is not quoted in EUR. BTC price is : " << x;
+ // ldebug << "ICN is not quoted in EUR. BTC price is : " << x;
m = x*y;
break;
}
@@ -141,10 +141,51 @@ Money PriceSourceCryptoWatch::getCoinPriceFromData(int coinId)
{
Money x (jvalue["result"]["market:bitfinex:btgbtc"]);
Money y (jvalue["result"]["market:kraken:btceur"]);
- ldebug << "BTG is not quoted in EUR. BTC price is : " << x;
+ // ldebug << "BTG is not quoted in EUR. BTC price is : " << x;
m = x*y;
break;
}
+ case CPFM_COIN_ID_KNC:
+ {
+ Money x (jvalue["result"]["market:binance:kncbtc"]);
+ Money y (jvalue["result"]["market:kraken:btceur"]);
+ // ldebug << "KNC is not quoted in EUR. BTC price is : " << x;
+ m = x*y;
+ break;
+ }
+ case CPFM_COIN_ID_AIR:
+ {
+ // ldebug << "AIR is not quoted. Returning 0.";
+ m = 0;
+ break;
+ }
+ case CPFM_COIN_ID_LEND:
+ {
+ Money x (jvalue["result"]["market:kraken:aaveeur"]);
+ // ldebug << "LEND is not quoted. Using AAVE.";
+ m = x/100;
+ break;
+ }
+ case CPFM_COIN_ID_AAVE:
+ {
+ Money x (jvalue["result"]["market:kraken:aaveeur"]);
+ m = x;
+ break;
+ }
+ case CPFM_COIN_ID_LPT:
+ {
+ Money x (jvalue["result"]["market:poloniex:lptbtc"]);
+ Money y (jvalue["result"]["market:kraken:btceur"]);
+ // ldebug << "LPT is not quoted in EUR. BTC price is : " << x;
+ m = x*y;
+ break;
+ }
+ case CPFM_COIN_ID_BCDT:
+ {
+ // ldebug << "BCDT is not quoted. Returning 0.";
+ m = 0;
+ break;
+ }
default:
{
m = 0;
diff --git a/src/sql.h b/src/sql.h
index f717d63..3420c17 100644
--- a/src/sql.h
+++ b/src/sql.h
@@ -216,9 +216,32 @@ namespace TableWallets_
};
using _traits = sqlpp::make_traits;
};
+
+ struct Active
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "active";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T active;
+ T& operator()()
+ {
+ return active;
+ }
+ const T& operator()() const
+ {
+ return active;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
}
-struct TableWallets : sqlpp::table_t
+struct TableWallets : sqlpp::table_t
{
using _value_type = sqlpp::no_value_t;
struct _alias_t
@@ -430,92 +453,138 @@ namespace TableWalletsTx_
using _traits = sqlpp::make_traits;
};
- struct BlockchainTxId
+ struct Amount
{
struct _alias_t
{
- static constexpr const char _literal[] = "blockchain_tx_id";
+ static constexpr const char _literal[] = "amount";
using _name_t = sqlpp::make_char_sequence;
template
struct _member_t
{
- T blockchain_tx_id;
+ T amount;
T& operator()()
{
- return blockchain_tx_id;
+ return amount;
}
const T& operator()() const
{
- return blockchain_tx_id;
+ return amount;
}
};
};
- using _traits = sqlpp::make_traits;
+ using _traits = sqlpp::make_traits;
};
- struct Amount
+ struct Fee
{
struct _alias_t
{
- static constexpr const char _literal[] = "amount";
+ static constexpr const char _literal[] = "fee";
using _name_t = sqlpp::make_char_sequence;
template
struct _member_t
{
- T amount;
+ T fee;
T& operator()()
{
- return amount;
+ return fee;
}
const T& operator()() const
{
- return amount;
+ return fee;
}
};
};
using _traits = sqlpp::make_traits;
};
- struct Fee
+ struct AmountCoinId
{
struct _alias_t
{
- static constexpr const char _literal[] = "fee";
+ static constexpr const char _literal[] = "amount_coin_id";
using _name_t = sqlpp::make_char_sequence;
template
struct _member_t
{
- T fee;
+ T amount_coin_id;
T& operator()()
{
- return fee;
+ return amount_coin_id;
}
const T& operator()() const
{
- return fee;
+ return amount_coin_id;
}
};
};
- using _traits = sqlpp::make_traits;
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct FeeCoinId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "fee_coin_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T fee_coin_id;
+ T& operator()()
+ {
+ return fee_coin_id;
+ }
+ const T& operator()() const
+ {
+ return fee_coin_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct UnixTime
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "unix_time";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T unix_time;
+ T& operator()()
+ {
+ return unix_time;
+ }
+ const T& operator()() const
+ {
+ return unix_time;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
};
- struct Timestamp
+ struct OperationType
{
struct _alias_t
{
- static constexpr const char _literal[] = "timestamp";
+ static constexpr const char _literal[] = "operation_type";
using _name_t = sqlpp::make_char_sequence;
template
struct _member_t
{
- T timestamp;
+ T operation_type;
T& operator()()
{
- return timestamp;
+ return operation_type;
}
const T& operator()() const
{
- return timestamp;
+ return operation_type;
}
};
};
@@ -523,7 +592,7 @@ namespace TableWalletsTx_
};
}
-struct TableWalletsTx : sqlpp::table_t
+struct TableWalletsTx : sqlpp::table_t
{
using _value_type = sqlpp::no_value_t;
struct _alias_t
@@ -546,6 +615,691 @@ struct TableWalletsTx : sqlpp::table_t;
+ template
+ struct _member_t
+ {
+ T raw_tx_id;
+ T& operator()()
+ {
+ return raw_tx_id;
+ }
+ const T& operator()() const
+ {
+ return raw_tx_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct WalletId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "wallet_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T wallet_id;
+ T& operator()()
+ {
+ return wallet_id;
+ }
+ const T& operator()() const
+ {
+ return wallet_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+}
+
+struct TableWalletsBtcRawTx : sqlpp::table_t
+{
+ using _value_type = sqlpp::no_value_t;
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "wallets_btc_raw_tx";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T wallets_btc_raw_tx;
+ T& operator()()
+ {
+ return wallets_btc_raw_tx;
+ }
+ const T& operator()() const
+ {
+ return wallets_btc_raw_tx;
+ }
+ };
+ };
+};
+
+namespace TableWalletsEthRawTx_
+{
+ struct RawTxId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "raw_tx_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T raw_tx_id;
+ T& operator()()
+ {
+ return raw_tx_id;
+ }
+ const T& operator()() const
+ {
+ return raw_tx_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct WalletId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "wallet_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T wallet_id;
+ T& operator()()
+ {
+ return wallet_id;
+ }
+ const T& operator()() const
+ {
+ return wallet_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+}
+
+struct TableWalletsEthRawTx : sqlpp::table_t
+{
+ using _value_type = sqlpp::no_value_t;
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "wallets_eth_raw_tx";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T wallets_eth_raw_tx;
+ T& operator()()
+ {
+ return wallets_eth_raw_tx;
+ }
+ const T& operator()() const
+ {
+ return wallets_eth_raw_tx;
+ }
+ };
+ };
+};
+
+namespace TableBlockchainBtcRawTx_
+{
+ struct RawTxId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "raw_tx_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T raw_tx_id;
+ T& operator()()
+ {
+ return raw_tx_id;
+ }
+ const T& operator()() const
+ {
+ return raw_tx_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct BlockchainId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "blockchain_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T blockchain_id;
+ T& operator()()
+ {
+ return blockchain_id;
+ }
+ const T& operator()() const
+ {
+ return blockchain_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct Hash
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "hash";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T hash;
+ T& operator()()
+ {
+ return hash;
+ }
+ const T& operator()() const
+ {
+ return hash;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct UnixTime
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "unix_time";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T unix_time;
+ T& operator()()
+ {
+ return unix_time;
+ }
+ const T& operator()() const
+ {
+ return unix_time;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+}
+
+struct TableBlockchainBtcRawTx : sqlpp::table_t
+{
+ using _value_type = sqlpp::no_value_t;
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "blockchain_btc_raw_tx";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T blockchain_btc_raw_tx;
+ T& operator()()
+ {
+ return blockchain_btc_raw_tx;
+ }
+ const T& operator()() const
+ {
+ return blockchain_btc_raw_tx;
+ }
+ };
+ };
+};
+
+namespace TableBlockchainBtcRawTxDetails_
+{
+ struct RawTxDetailId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "raw_tx_detail_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T raw_tx_detail_id;
+ T& operator()()
+ {
+ return raw_tx_detail_id;
+ }
+ const T& operator()() const
+ {
+ return raw_tx_detail_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct RawTxId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "raw_tx_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T raw_tx_id;
+ T& operator()()
+ {
+ return raw_tx_id;
+ }
+ const T& operator()() const
+ {
+ return raw_tx_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct Amount
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "amount";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T amount;
+ T& operator()()
+ {
+ return amount;
+ }
+ const T& operator()() const
+ {
+ return amount;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct Address
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "address";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T address;
+ T& operator()()
+ {
+ return address;
+ }
+ const T& operator()() const
+ {
+ return address;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+}
+
+struct TableBlockchainBtcRawTxDetails : sqlpp::table_t
+{
+ using _value_type = sqlpp::no_value_t;
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "blockchain_btc_raw_tx_details";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T blockchain_btc_raw_tx_details;
+ T& operator()()
+ {
+ return blockchain_btc_raw_tx_details;
+ }
+ const T& operator()() const
+ {
+ return blockchain_btc_raw_tx_details;
+ }
+ };
+ };
+};
+
+namespace TableBlockchainEthRawTx_
+{
+ struct RawTxId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "raw_tx_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T raw_tx_id;
+ T& operator()()
+ {
+ return raw_tx_id;
+ }
+ const T& operator()() const
+ {
+ return raw_tx_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct BlockchainId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "blockchain_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T blockchain_id;
+ T& operator()()
+ {
+ return blockchain_id;
+ }
+ const T& operator()() const
+ {
+ return blockchain_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct Hash
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "hash";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T hash;
+ T& operator()()
+ {
+ return hash;
+ }
+ const T& operator()() const
+ {
+ return hash;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct UnixTime
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "unix_time";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T unix_time;
+ T& operator()()
+ {
+ return unix_time;
+ }
+ const T& operator()() const
+ {
+ return unix_time;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct Fee
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "fee";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T fee;
+ T& operator()()
+ {
+ return fee;
+ }
+ const T& operator()() const
+ {
+ return fee;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+}
+
+struct TableBlockchainEthRawTx : sqlpp::table_t
+{
+ using _value_type = sqlpp::no_value_t;
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "blockchain_eth_raw_tx";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T blockchain_eth_raw_tx;
+ T& operator()()
+ {
+ return blockchain_eth_raw_tx;
+ }
+ const T& operator()() const
+ {
+ return blockchain_eth_raw_tx;
+ }
+ };
+ };
+};
+
+namespace TableBlockchainEthRawTxDetails_
+{
+ struct RawTxDetailId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "raw_tx_detail_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T raw_tx_detail_id;
+ T& operator()()
+ {
+ return raw_tx_detail_id;
+ }
+ const T& operator()() const
+ {
+ return raw_tx_detail_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct RawTxId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "raw_tx_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T raw_tx_id;
+ T& operator()()
+ {
+ return raw_tx_id;
+ }
+ const T& operator()() const
+ {
+ return raw_tx_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct AddressFrom
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "address_from";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T address_from;
+ T& operator()()
+ {
+ return address_from;
+ }
+ const T& operator()() const
+ {
+ return address_from;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct AddressTo
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "address_to";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T address_to;
+ T& operator()()
+ {
+ return address_to;
+ }
+ const T& operator()() const
+ {
+ return address_to;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct AmountCoinId
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "amount_coin_id";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T amount_coin_id;
+ T& operator()()
+ {
+ return amount_coin_id;
+ }
+ const T& operator()() const
+ {
+ return amount_coin_id;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+
+ struct Amount
+ {
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "amount";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T amount;
+ T& operator()()
+ {
+ return amount;
+ }
+ const T& operator()() const
+ {
+ return amount;
+ }
+ };
+ };
+ using _traits = sqlpp::make_traits;
+ };
+};
+
+struct TableBlockchainEthRawTxDetails : sqlpp::table_t
+{
+ using _value_type = sqlpp::no_value_t;
+ struct _alias_t
+ {
+ static constexpr const char _literal[] = "blockchain_eth_raw_tx_details";
+ using _name_t = sqlpp::make_char_sequence;
+ template
+ struct _member_t
+ {
+ T blockchain_eth_raw_tx_details;
+ T& operator()()
+ {
+ return blockchain_eth_raw_tx_details;
+ }
+ const T& operator()() const
+ {
+ return blockchain_eth_raw_tx_details;
+ }
+ };
+ };
+};
+
namespace TableExchangesLedgers_
{
struct LedgerId
@@ -663,23 +1417,23 @@ namespace TableExchangesLedgers_
using _traits = sqlpp::make_traits;
};
- struct Timestamp
+ struct UnixTime
{
struct _alias_t
{
- static constexpr const char _literal[] = "timestamp";
+ static constexpr const char _literal[] = "unix_time";
using _name_t = sqlpp::make_char_sequence;
template
struct _member_t
{
- T timestamp;
+ T unix_time;
T& operator()()
{
- return timestamp;
+ return unix_time;
}
const T& operator()() const
{
- return timestamp;
+ return unix_time;
}
};
};
@@ -756,7 +1510,7 @@ namespace TableExchangesLedgers_
};
}
-struct TableExchangesLedgers : sqlpp::table_t
+struct TableExchangesLedgers : sqlpp::table_t
{
using _value_type = sqlpp::no_value_t;
struct _alias_t
@@ -919,23 +1673,23 @@ namespace TableExchangesTrades_
using _traits = sqlpp::make_traits;
};
- struct Timestamp
+ struct UnixTime
{
struct _alias_t
{
- static constexpr const char _literal[] = "timestamp";
+ static constexpr const char _literal[] = "unix_time";
using _name_t = sqlpp::make_char_sequence;
template
struct _member_t
{
- T timestamp;
+ T unix_time;
T& operator()()
{
- return timestamp;
+ return unix_time;
}
const T& operator()() const
{
- return timestamp;
+ return unix_time;
}
};
};
@@ -1104,7 +1858,7 @@ namespace TableExchangesTrades_
};
}
-struct TableExchangesTrades : sqlpp::table_t
+struct TableExchangesTrades : sqlpp::table_t
{
using _value_type = sqlpp::no_value_t;
struct _alias_t
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 80af3d6..4221fe9 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -19,9 +19,32 @@
*/
#include "wallet.h"
-#include "wallets/btc.h"
-#include "wallets/bch.h"
-#include "wallets/eth.h"
+#include "wallets/wallet_btc.h"
+#include "wallets/wallet_bch.h"
+#include "wallets/wallet_eth.h"
+
+string getBlockchainName(int blockchainId)
+{
+ string s;
+
+ switch(blockchainId)
+ {
+ case CPFM_BLOCKCHAIN_ID_BTC:
+ s = "BTC";
+ break;
+ case CPFM_BLOCKCHAIN_ID_BCH:
+ s = "BCH";
+ break;
+ case CPFM_BLOCKCHAIN_ID_ETH:
+ s = "ETH";
+ break;
+ default:
+ s = "Error!";
+ break;
+ }
+
+ return s;
+}
WalletsManager::WalletsManager(int userId)
{
@@ -38,38 +61,34 @@ void WalletsManager::analyzeUserWallets()
mysql::connection db(getMysqlConfig());
const auto wallets = TableWallets{};
- // Identify coins, we need one analyzer object per coin.
- list handlers;
- for (const auto& row: db.run(select(wallets.type_id).from(wallets).where(wallets.user_id == m_userId).group_by(wallets.type_id)))
+ list userWallets;
+ for (const auto& row: db.run(select(wallets.type_id,wallets.wallet_id).from(wallets).where(wallets.user_id == m_userId and wallets.active == true)))
{
- int typeId = row.type_id;
- WalletHandler* walletHandler;
- switch (typeId)
+ Wallet* wallet;
+ switch (row.type_id)
{
case CPFM_WALLET_TYPE_ID_BTC:
- walletHandler = new WalletHandlerBTC(m_userId);
- handlers.push_back(walletHandler);
+ wallet = new WalletBTC(row.wallet_id);
+ userWallets.push_back(wallet);
break;
case CPFM_WALLET_TYPE_ID_BCH:
- walletHandler = new WalletHandlerBCH(m_userId);
- handlers.push_back(walletHandler);
+ wallet = new WalletBCH(row.wallet_id);
+ userWallets.push_back(wallet);
break;
case CPFM_WALLET_TYPE_ID_ETH:
- walletHandler = new WalletHandlerETH(m_userId);
- handlers.push_back(walletHandler);
+ wallet = new WalletETH(row.wallet_id);
+ userWallets.push_back(wallet);
break;
default:
- lerr << "Unsupported wallet type: " << typeId;
+ lerr << "Unsupported wallet type: " << row.type_id;
break;
}
}
- emptyWalletsTx();
-
- for (auto const& handler: handlers)
+ for (auto const& wallet: userWallets)
{
- handler->analyzeUserWallets();
- delete handler;
+ wallet->update();
+ delete wallet;
}
}
@@ -85,20 +104,16 @@ void WalletsManager::emptyWalletsTx()
userWallets.push_back(row.wallet_id);
}
- for (const auto& id: userWallets)
+ for (const auto& idWallet: userWallets)
{
- db.run(remove_from(wallets_tx).where(wallets_tx.wallet_id == id));
+ list userWalletTx;
+ for (const auto& row: db.run(select(wallets_tx.tx_id).from(wallets_tx).where(wallets_tx.wallet_id == idWallet)))
+ {
+ userWalletTx.push_back(row.tx_id);
+ }
+
+ db.run(remove_from(wallets_tx).where(wallets_tx.wallet_id == idWallet));
}
linfo << "Emptied Wallets Tx DB table for user " << m_userId;
}
-
-WalletHandler::WalletHandler(int userId)
-{
- m_userId = userId;
-}
-
-WalletHandler::~WalletHandler()
-{
-
-}
diff --git a/src/wallet.h b/src/wallet.h
index 970566d..4f746de 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -27,6 +27,17 @@
#define CPFM_WALLET_TYPE_ID_ETH 2
#define CPFM_WALLET_TYPE_ID_BCH 3
+#define CPFM_WALLET_OPERATION_UNKNOWN 0
+#define CPFM_WALLET_OPERATION_MINING_MINTED 1
+#define CPFM_WALLET_OPERATION_MINING_POOL 2
+#define CPFM_WALLET_OPERATION_TRANSFERT 3
+
+#define CPFM_BLOCKCHAIN_ID_BTC 1
+#define CPFM_BLOCKCHAIN_ID_BCH 2
+#define CPFM_BLOCKCHAIN_ID_ETH 3
+
+string getBlockchainName(int blockchainId);
+
class WalletsManager
{
public:
@@ -41,16 +52,15 @@ private:
int m_userId;
};
-class WalletHandler
+class Wallet
{
public:
- WalletHandler(int userId);
- virtual ~WalletHandler();
+ Wallet (int walletId) { m_walletId = walletId; }
- virtual void analyzeUserWallets() = 0;
+ virtual void update() = 0;
protected:
- int m_userId;
+ int m_walletId;
};
#endif // CPFM_WALLET_H_INCLUDED
\ No newline at end of file
diff --git a/src/wallets/bch.cpp b/src/wallets/bch.cpp
deleted file mode 100644
index d4c71de..0000000
--- a/src/wallets/bch.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (c) 2018, evilny0
- *
- * This file is part of cpfm.
- *
- * cpfm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * cpm 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
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with cpfm. If not, see .
- *
- */
-
-#include "wallets/bch.h"
-
-WalletHandlerBCH::WalletHandlerBCH(int userId) : WalletHandler(userId)
-{
-}
-
-WalletHandlerBCH::~WalletHandlerBCH()
-{
-}
-
-void WalletHandlerBCH::analyzeUserWallets()
-{
- linfo << "Analyzing user " << m_userId << " BCH wallets.";
-
- mysql::connection db(getMysqlConfig());
- const auto wallets = TableWallets{};
- const auto wallets_addresses = TableWalletsAddresses{};
-
- map> userWallets;
- list userAddresses;
- for (const auto &row : db.run(select(wallets.wallet_id, wallets.type_id, wallets_addresses.address).from(wallets.cross_join(wallets_addresses)).where(wallets.user_id == m_userId and wallets.wallet_id == wallets_addresses.wallet_id and wallets.type_id == CPFM_WALLET_TYPE_ID_BCH)))
- {
- userWallets[row.wallet_id].push_back(row.address);
- userAddresses.push_back(row.address);
- }
-
- for (const auto &w : userWallets)
- {
- addUserWalletDataToDB(w.first, w.second, userAddresses);
- analyzeUserWalletData(w.first);
- }
-}
-
-void WalletHandlerBCH::analyzeUserWalletData(int walletId)
-{
- mysql::connection db(getMysqlConfig());
- const auto wallets_tx = TableWalletsTx{};
- const auto wallets_balances = TableWalletsBalances{};
-
- // Loop is on blockchain tx id, so first, get blockhain tx id list.
- list blockchainTxs;
- for (const auto &row : db.run(select(wallets_tx.blockchain_tx_id).from(wallets_tx).where(wallets_tx.wallet_id == walletId).group_by(wallets_tx.blockchain_tx_id).order_by(wallets_tx.timestamp.asc())))
- {
- blockchainTxs.push_back(row.blockchain_tx_id);
- }
-
- ldebug << "------------------------------------------------------------";
-
- Money walletBalance = 0;
- Money walletInputs = 0;
- Money walletOutputs = 0;
- Money walletOutputFees = 0;
- for (const auto &txId: blockchainTxs)
- {
- Money txAmount = 0;
- Money txFee = 0;
-
- for (const auto &row : db.run(select(wallets_tx.amount, wallets_tx.fee).from(wallets_tx).where(wallets_tx.blockchain_tx_id == txId and wallets_tx.wallet_id == walletId)))
- {
- Money amount(row.amount);
- Money fee(row.fee);
-
- if (txFee == 0)
- txFee = fee;
-
- txAmount += amount;
- }
-
- txAmount += txFee;
-
- if (txAmount < 0)
- walletOutputs += txAmount;
- else
- walletInputs += txAmount;
-
- walletOutputFees += txFee;
-
- walletBalance = walletInputs + walletOutputs - walletOutputFees;
-
- string sReason = "?";
-
- if (txAmount < 0)
- {
- }
-
- /*
- ldebug << "Tx: " << txId
- << ". Amount: " << txAmount
- << ". Outputs: " << walletOutputs
- << ". Inputs: " << walletInputs
- << ". Fees: " << txFee
- << ". Balance: " << walletBalance
- << ". Reason: " << sReason;
- */
- }
-
- linfo << "Wallet " << walletId << " balance is: " << walletBalance;
-
- db(insert_into(wallets_balances).set(wallets_balances.wallet_id = walletId, wallets_balances.coin_id = CPFM_COIN_ID_BCH, wallets_balances.balance = walletBalance.toBoostMpf()));
-}
-
-void WalletHandlerBCH::addUserWalletDataToDB(int walletId, list walletAddresses, list userAddresses)
-{
- linfo << "Analyzing wallet " << walletId << ".";
-
- for (const auto &a : walletAddresses)
- {
- AddressHandlerBCH addr(a, walletId);
- addr.setWalletAddresses(walletAddresses);
- addr.setUserAddresses(userAddresses);
- addr.addAddressDataToDB();
- }
-}
-
-AddressHandlerBCH::AddressHandlerBCH(string address, int walletId)
-{
- m_address = address;
- m_walletId = walletId;
-}
-
-AddressHandlerBCH::~AddressHandlerBCH()
-{
-}
-
-string AddressHandlerBCH::getCacheFilename()
-{
- string cacheFilename("data/cache/bch/" + m_address);
- return cacheFilename;
-}
-
-void AddressHandlerBCH::getAddressData()
-{
- linfo << "Getting data for address: " << m_address << ".";
-
- if (!bfs::exists(getCacheFilename()))
- {
- getBlockchainAddressData();
- }
-}
-
-void AddressHandlerBCH::addAddressDataToDB()
-{
- linfo << "Analyzing data for address: " << m_address << ".";
-
- getAddressData();
- addCachedAddressDataToDB();
-}
-
-void AddressHandlerBCH::getBlockchainAddressData()
-{
- try
- {
- string sRequestURL = "/insight-api/txs/?address=";
- sRequestURL += m_address;
- http_client apiclient("https://cashexplorer.bitcoin.com");
- apiclient.request(methods::GET, sRequestURL).then([](http_response response)
- {
- if (response.status_code() == status_codes::OK)
- {
- return response.extract_json();
- }
- return pplx::task_from_result(json::value());
- })
- .then([this](pplx::task previousTask) {
- ofstream f;
- f.open(getCacheFilename());
- f << previousTask.get();
- f.close();
- })
- .wait();
- }
- catch (const http::http_exception &e)
- {
- lerr << "Failed to query cashexplorer.bitcoin.com about " << m_address;
- }
-}
-
-void AddressHandlerBCH::addCachedAddressDataToDB()
-{
- ifstream f;
- f.open(getCacheFilename());
- json::value jvalue = json::value::parse(f);
- f.close();
-
- addAddressDataJSONToDB(jvalue);
-}
-
-void AddressHandlerBCH::addAddressDataJSONToDB(json::value jvalue)
-{
- mysql::connection db(getMysqlConfig());
- const auto wallets_tx = TableWalletsTx{};
-
- string myAddr = m_address;
- linfo << "Analyzing address: " << myAddr;
-
- for (int i = 0; i < jvalue["txs"].size(); i++)
- {
- string txid = jvalue["txs"][i]["txid"].as_string();
- int timestamp = jvalue["txs"][i]["time"].as_integer();
-
- Money txTotalOutputAmount;
- Money txTotalInputAmount;
- Money txMyOutputAmount;
- Money txMyInputAmount;
- bool bToMyAddr = false;
- bool bFromMyAddr = false;
- list inputAddrList;
- list outputAddrList;
-
- for (int j = 0; j < jvalue["txs"][i]["vin"].size(); j++)
- {
- string inputAddr = jvalue["txs"][i]["vin"][j]["addr"].as_string();
- Money amount(jvalue["txs"][i]["vin"][j]["value"]);
- txTotalInputAmount += amount;
-
- if (inputAddr == myAddr)
- {
- bFromMyAddr = true;
- txMyInputAmount += amount;
- }
- else
- {
- inputAddrList.push_back(inputAddr);
- }
- }
-
- for (int j = 0; j < jvalue["txs"][i]["vout"].size(); j++)
- {
- string outputAddr = jvalue["txs"][i]["vout"][j]["scriptPubKey"]["addresses"][0].as_string();
- Money amount(jvalue["txs"][i]["vout"][j]["value"]);
- txTotalOutputAmount += amount;
-
- if (outputAddr == myAddr)
- {
- bToMyAddr = true;
- txMyOutputAmount += amount;
- }
- else
- {
- outputAddrList.push_back(outputAddr);
- }
- }
-
- Money amount;
- Money fee;
- if (bFromMyAddr)
- {
- amount = -txMyInputAmount;
- fee = txTotalInputAmount - txTotalOutputAmount;
-
- for (auto const &addr : inputAddrList)
- {
- bool bFoundInUserAddresses = false;
- for (auto const &userAddr : m_userAddresses)
- {
- if (!userAddr.compare(addr))
- {
- bFoundInUserAddresses = true;
- break;
- }
- }
-
- if (!bFoundInUserAddresses)
- {
- lwarn << "User configuration is missing this address: " << addr;
- }
- }
-
- for (auto const &addr : outputAddrList)
- {
- bool bFoundInUserAddresses = false;
- for (auto const &userAddr : m_userAddresses)
- {
- if (!userAddr.compare(addr))
- {
- bFoundInUserAddresses = true;
- break;
- }
- }
-
- if (!bFoundInUserAddresses)
- {
- linfo << "Potential other address to analyze: " << L_Cyan << addr;
- }
- }
- }
-
- if (bToMyAddr)
- {
- amount = txMyOutputAmount;
- fee = 0;
- }
-
- db(insert_into(wallets_tx).set(wallets_tx.wallet_id = m_walletId, wallets_tx.blockchain_tx_id = txid, wallets_tx.amount = amount.toBoostMpf(), wallets_tx.fee = fee.toBoostMpf(), wallets_tx.timestamp = timestamp));
- }
-}
diff --git a/src/wallets/bch.h b/src/wallets/bch.h
deleted file mode 100644
index ddbd080..0000000
--- a/src/wallets/bch.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2018, evilny0
- *
- * This file is part of cpfm.
- *
- * cpfm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * cpm 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
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with cpfm. If not, see .
- *
- */
-
-#ifndef CPFM_WALLET_BCH_H_INCLUDED
-#define CPFM_WALLET_BCH_H_INCLUDED
-
-#include "wallet.h"
-
-
-class WalletHandlerBCH : public WalletHandler
-{
-public:
- WalletHandlerBCH(int userId);
- virtual ~WalletHandlerBCH();
-
- virtual void analyzeUserWallets();
-
-private:
- void addUserWalletDataToDB(int walletId, list walletAddresses, list userAddresses);
- void analyzeUserWalletData(int walletId);
-};
-
-class AddressHandlerBCH
-{
-public:
- AddressHandlerBCH(string address, int walletId);
- virtual ~AddressHandlerBCH();
-
- void getAddressData();
- void addAddressDataToDB();
- void setWalletAddresses(list walletAddresses) { m_walletAddresses = walletAddresses; }
- void setUserAddresses(list userAddresses) { m_userAddresses = userAddresses; }
-
-private:
- void getBlockchainAddressData();
- void addCachedAddressDataToDB();
- void addAddressDataJSONToDB(json::value jvalue);
- string getCacheFilename();
-
- string m_address;
- int m_walletId;
- list m_userAddresses;
- list m_walletAddresses;
-};
-
-#endif // CPFM_WALLET_BTC_H_INCLUDED
\ No newline at end of file
diff --git a/src/wallets/btc.cpp b/src/wallets/btc.cpp
deleted file mode 100644
index 8b3c1da..0000000
--- a/src/wallets/btc.cpp
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (c) 2018, evilny0
- *
- * This file is part of cpfm.
- *
- * cpfm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * cpm 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
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with cpfm. If not, see .
- *
- */
-
-#include "wallets/btc.h"
-
-WalletHandlerBTC::WalletHandlerBTC(int userId) : WalletHandler(userId)
-{
-}
-
-WalletHandlerBTC::~WalletHandlerBTC()
-{
-
-}
-
-void WalletHandlerBTC::analyzeUserWallets()
-{
- linfo << "Analyzing user " << m_userId << " BTC wallets.";
-
- mysql::connection db(getMysqlConfig());
- const auto wallets = TableWallets{};
- const auto wallets_addresses = TableWalletsAddresses{};
-
- map> userWallets;
- list userAddresses;
- for (const auto& row: db.run(select(wallets.wallet_id,wallets.type_id,wallets_addresses.address).from(wallets.cross_join(wallets_addresses)).where(wallets.user_id == m_userId and wallets.wallet_id == wallets_addresses.wallet_id and wallets.type_id == CPFM_WALLET_TYPE_ID_BTC)))
- {
- userWallets[row.wallet_id].push_back(row.address);
- userAddresses.push_back(row.address);
- }
-
- for (const auto& w: userWallets)
- {
- addUserWalletDataToDB(w.first,w.second,userAddresses);
- analyzeUserWalletData(w.first);
- }
-}
-
-void WalletHandlerBTC::analyzeUserWalletData(int walletId)
-{
- mysql::connection db(getMysqlConfig());
- const auto wallets_tx = TableWalletsTx{};
- const auto wallets_balances = TableWalletsBalances{};
-
- // Loop is on blockchain tx id, so first, get blockchain tx list.
- list blockchainTxs;
- for (const auto& row: db.run(select(wallets_tx.blockchain_tx_id).from(wallets_tx).where(wallets_tx.wallet_id == walletId).group_by(wallets_tx.blockchain_tx_id).order_by(wallets_tx.timestamp.asc())))
- {
- blockchainTxs.push_back(row.blockchain_tx_id);
- }
-
- ldebug << "------------------------------------------------------------";
-
- Money walletBalance = 0;
- Money walletInputs = 0;
- Money walletOutputs = 0;
- Money walletOutputFees = 0;
- for (const auto& txId: blockchainTxs)
- {
- Money txAmount = 0;
- Money txFee = 0;
-
- for (const auto& row: db.run(select(wallets_tx.amount, wallets_tx.fee).from(wallets_tx).where(wallets_tx.blockchain_tx_id == txId and wallets_tx.wallet_id == walletId)))
- {
- Money amount(row.amount);
- Money fee(row.fee);
-
- if (txFee == 0)
- txFee = fee;
-
- txAmount += amount;
- }
-
- txAmount += txFee;
-
- if (txAmount<0)
- walletOutputs += txAmount;
- else
- walletInputs += txAmount;
-
- walletOutputFees += txFee;
-
- walletBalance = walletInputs + walletOutputs - walletOutputFees;
-
- string sReason = "?";
-
- if (txAmount < 0)
- {
-
- }
-
- /*
- ldebug << "Tx: " << txId
- << ". Amount: " << txAmount
- << ". Outputs: " << walletOutputs
- << ". Inputs: " << walletInputs
- << ". Fees: " << txFee
- << ". Balance: " << walletBalance
- << ". Reason: " << sReason;
- */
- }
-
- linfo << "Wallet " << walletId << " balance is: " << walletBalance;
-
- db(insert_into(wallets_balances).set(
- wallets_balances.wallet_id = walletId,
- wallets_balances.coin_id = CPFM_COIN_ID_BTC,
- wallets_balances.balance = walletBalance.toBoostMpf()
- ));
-}
-
-void WalletHandlerBTC::addUserWalletDataToDB(int walletId, list walletAddresses, list userAddresses)
-{
- linfo << "Analyzing wallet " << walletId << ".";
-
- for (const auto& a: walletAddresses)
- {
- AddressHandlerBTC addr(a,walletId);
- addr.setWalletAddresses(walletAddresses);
- addr.setUserAddresses(userAddresses);
- addr.addAddressDataToDB();
- }
-}
-
-AddressHandlerBTC::AddressHandlerBTC(string address, int walletId)
-{
- m_address = address;
- m_walletId = walletId;
-}
-
-AddressHandlerBTC::~AddressHandlerBTC()
-{
-
-}
-
-string AddressHandlerBTC::getCacheFilename()
-{
- string cacheFilename("data/cache/btc/" + m_address);
- return cacheFilename;
-}
-
-void AddressHandlerBTC::getAddressData()
-{
- linfo << "Getting data for address: " << m_address << ".";
-
- if (!bfs::exists(getCacheFilename()))
- {
- getBlockchainAddressData();
- }
-}
-
-void AddressHandlerBTC::addAddressDataToDB()
-{
- linfo << "Analyzing data for address: " << m_address << ".";
-
- getAddressData();
- addCachedAddressDataToDB();
-}
-
-void AddressHandlerBTC::getBlockchainAddressData()
-{
- try
- {
- string sRequestURL = "/fr/rawaddr/";
- sRequestURL += m_address;
- http_client apiclient("https://blockchain.info/");
- apiclient.request(methods::GET,sRequestURL).then([](http_response response)
- {
- if (response.status_code() == status_codes::OK)
- {
- return response.extract_json();
- }
- return pplx::task_from_result(json::value());
- })
- .then([this](pplx::task previousTask)
- {
- ofstream f;
- f.open(getCacheFilename());
- f << previousTask.get();
- f.close();
- })
- .wait();
- }
- catch(const http::http_exception& e)
- {
- lerr << "Failed to query blockchain.info about " << m_address;
- }
-}
-
-void AddressHandlerBTC::addCachedAddressDataToDB()
-{
- ifstream f;
- f.open(getCacheFilename());
- json::value jvalue = json::value::parse(f);
- f.close();
-
- addAddressDataJSONToDB(jvalue);
-}
-
-void AddressHandlerBTC::addAddressDataJSONToDB(json::value jvalue)
-{
- mysql::connection db(getMysqlConfig());
- const auto wallets_tx = TableWalletsTx{};
-
- string myAddr = jvalue["address"].as_string();
- linfo << "Analyzing address: " << myAddr;
-
- Money balance = jvalue["final_balance"].as_integer();;
-
- for (int i=0;i inputAddrList;
- list outputAddrList;
-
- for (int j=0;j.
- *
- */
-
-#ifndef CPFM_WALLET_BTC_H_INCLUDED
-#define CPFM_WALLET_BTC_H_INCLUDED
-
-#include "wallet.h"
-
-
-class WalletHandlerBTC : public WalletHandler
-{
-public:
- WalletHandlerBTC(int userId);
- virtual ~WalletHandlerBTC();
-
- virtual void analyzeUserWallets();
-
-private:
- void addUserWalletDataToDB(int walletId, list walletAddresses, list userAddresses);
- void analyzeUserWalletData(int walletId);
-};
-
-class AddressHandlerBTC
-{
-public:
- AddressHandlerBTC(string address, int walletId);
- virtual ~AddressHandlerBTC();
-
- void getAddressData();
- void addAddressDataToDB();
- void setWalletAddresses(list walletAddresses) { m_walletAddresses = walletAddresses; }
- void setUserAddresses(list userAddresses) { m_userAddresses = userAddresses; }
-
-private:
- void getBlockchainAddressData();
- void addCachedAddressDataToDB();
- void addAddressDataJSONToDB(json::value jvalue);
- string getCacheFilename();
-
- string m_address;
- int m_walletId;
- list m_userAddresses;
- list m_walletAddresses;
-};
-
-#endif // CPFM_WALLET_BTC_H_INCLUDED
\ No newline at end of file
diff --git a/src/wallets/eth.cpp b/src/wallets/eth.cpp
deleted file mode 100644
index 9809db8..0000000
--- a/src/wallets/eth.cpp
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (c) 2018, evilny0
- *
- * This file is part of cpfm.
- *
- * cpfm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * cpm 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
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with cpfm. If not, see .
- *
- */
-
-#include "wallets/eth.h"
-
-WalletHandlerETH::WalletHandlerETH(int userId) : WalletHandler(userId)
-{
-}
-
-WalletHandlerETH::~WalletHandlerETH()
-{
-
-}
-
-void WalletHandlerETH::analyzeUserWallets()
-{
- linfo << "Analyzing user " << m_userId << " ETH wallets.";
-
- mysql::connection db(getMysqlConfig());
- const auto wallets = TableWallets{};
- const auto wallets_addresses = TableWalletsAddresses{};
-
- map> userWallets;
- list userAddresses;
- for (const auto& row: db.run(select(wallets.wallet_id,wallets.type_id,wallets_addresses.address).from(wallets.cross_join(wallets_addresses)).where(wallets.user_id == m_userId and wallets.wallet_id == wallets_addresses.wallet_id and wallets.type_id == CPFM_WALLET_TYPE_ID_ETH)))
- {
- userWallets[row.wallet_id].push_back(row.address);
- userAddresses.push_back(row.address);
- }
-
- for (const auto& w: userWallets)
- {
- addUserWalletDataToDB(w.first,w.second,userAddresses);
- //analyzeUserWalletData(w.first);
- }
-}
-
-void WalletHandlerETH::analyzeUserWalletData(int walletId)
-{
- mysql::connection db(getMysqlConfig());
- const auto wallets_tx = TableWalletsTx{};
- const auto wallets_balances = TableWalletsBalances{};
-
- // Loop is on blockchain tx id, so first, get blockchain tx list.
- list blockchainTxs;
- for (const auto& row: db.run(select(wallets_tx.blockchain_tx_id).from(wallets_tx).where(wallets_tx.wallet_id == walletId).group_by(wallets_tx.blockchain_tx_id).order_by(wallets_tx.timestamp.asc())))
- {
- blockchainTxs.push_back(row.blockchain_tx_id);
- }
-
- ldebug << "------------------------------------------------------------";
-
- Money walletBalance = 0;
- Money walletInputs = 0;
- Money walletOutputs = 0;
- Money walletOutputFees = 0;
- for (const auto& txId: blockchainTxs)
- {
- Money txAmount = 0;
- Money txFee = 0;
-
- for (const auto& row: db.run(select(wallets_tx.amount, wallets_tx.fee).from(wallets_tx).where(wallets_tx.blockchain_tx_id == txId and wallets_tx.wallet_id == walletId)))
- {
- Money amount(row.amount);
- Money fee(row.fee);
-
- if (txFee == 0)
- txFee = fee;
-
- txAmount += amount;
- }
-
- txAmount += txFee;
-
- if (txAmount<0)
- walletOutputs += txAmount;
- else
- walletInputs += txAmount;
-
- walletOutputFees += txFee;
-
- walletBalance = walletInputs + walletOutputs - walletOutputFees;
-
- string sReason = "?";
-
- if (txAmount < 0)
- {
-
- }
-
- /*
- ldebug << "Tx: " << txId
- << ". Amount: " << txAmount
- //<< ". Outputs: " << walletOutputs
- //<< ". Inputs: " << walletInputs
- << ". Fees: " << txFee
- << ". Balance: " << walletBalance
- << ". Reason: " << sReason;
- */
- }
-
- linfo << "Wallet " << walletId << " balance is: " << walletBalance;
-
- db(insert_into(wallets_balances).set(
- wallets_balances.wallet_id = walletId,
- wallets_balances.coin_id = CPFM_COIN_ID_ETH,
- wallets_balances.balance = walletBalance.toBoostMpf()
- ));
-}
-
-void WalletHandlerETH::addUserWalletDataToDB(int walletId, list walletAddresses, list userAddresses)
-{
- linfo << "Analyzing wallet " << walletId << ".";
-
- for (const auto& a: walletAddresses)
- {
- AddressHandlerETH addr(a,walletId);
- addr.setWalletAddresses(walletAddresses);
- addr.setUserAddresses(userAddresses);
- addr.addAddressDataToDB();
- }
-}
-
-AddressHandlerETH::AddressHandlerETH(string address, int walletId)
-{
- m_address = address;
- m_walletId = walletId;
-}
-
-AddressHandlerETH::~AddressHandlerETH()
-{
-
-}
-
-string AddressHandlerETH::getCacheFilename()
-{
- string cacheFilename("data/cache/eth/" + m_address);
- return cacheFilename;
-}
-
-void AddressHandlerETH::getAddressData()
-{
- linfo << "Getting data for address: " << m_address << ".";
-
- if (!bfs::exists(getCacheFilename()))
- {
- getBlockchainAddressData();
- }
-}
-
-void AddressHandlerETH::addAddressDataToDB()
-{
- linfo << "Analyzing data for address: " << m_address << ".";
-
- getAddressData();
- addCachedAddressDataToDB();
-}
-
-void AddressHandlerETH::getBlockchainAddressData()
-{
- try
- {
- string sRequestURL = "/api?module=account&action=balance&address=";
- sRequestURL += m_address;
- http_client apiclient("https://api.etherscan.io");
- apiclient.request(methods::GET,sRequestURL).then([](http_response response)
- {
- if (response.status_code() == status_codes::OK)
- {
- return response.extract_json();
- }
- return pplx::task_from_result(json::value());
- })
- .then([this](pplx::task previousTask)
- {
- ofstream f;
- f.open(getCacheFilename());
- f << previousTask.get();
- f.close();
- })
- .wait();
- }
- catch(const http::http_exception& e)
- {
- lerr << "Failed to query cashexplorer.bitcoin.com about " << m_address;
- }
-}
-
-void AddressHandlerETH::addCachedAddressDataToDB()
-{
- ifstream f;
- f.open(getCacheFilename());
- json::value jvalue = json::value::parse(f);
- f.close();
-
- addAddressDataJSONToDB(jvalue);
-}
-
-void AddressHandlerETH::addAddressDataJSONToDB(json::value jvalue)
-{
- mysql::connection db(getMysqlConfig());
- const auto wallets_tx = TableWalletsTx{};
-
- string myAddr = m_address;
- linfo << "Analyzing address: " << myAddr;
-
- if (!jvalue["message"].as_string().compare("OK") && !jvalue["status"].as_string().compare("1"))
- {
- Money walletBalance (jvalue["result"]);
- Money divider("1000000000000000000");
- walletBalance /= divider;
-
- linfo << "Wallet " << m_walletId << " balance is: " << walletBalance;
-
- mysql::connection db(getMysqlConfig());
- const auto wallets_tx = TableWalletsTx{};
- const auto wallets_balances = TableWalletsBalances{};
-
- db(insert_into(wallets_balances).set(
- wallets_balances.wallet_id = m_walletId,
- wallets_balances.coin_id = CPFM_COIN_ID_ETH,
- wallets_balances.balance = walletBalance.toBoostMpf()
- ));
- }
-
- /*
- //Money balance = jvalue["final_balance"].as_integer();;
-
- for (int i=0;i inputAddrList;
- list outputAddrList;
-
- for (int j=0;j.
- *
- */
-
-#ifndef CPFM_WALLET_ETH_H_INCLUDED
-#define CPFM_WALLET_ETH_H_INCLUDED
-
-#include "wallet.h"
-
-
-class WalletHandlerETH : public WalletHandler
-{
-public:
- WalletHandlerETH(int userId);
- virtual ~WalletHandlerETH();
-
- virtual void analyzeUserWallets();
-
-private:
- void addUserWalletDataToDB(int walletId, list walletAddresses, list userAddresses);
- void analyzeUserWalletData(int walletId);
-};
-
-class AddressHandlerETH
-{
-public:
- AddressHandlerETH(string address, int walletId);
- virtual ~AddressHandlerETH();
-
- void getAddressData();
- void addAddressDataToDB();
- void setWalletAddresses(list walletAddresses) { m_walletAddresses = walletAddresses; }
- void setUserAddresses(list userAddresses) { m_userAddresses = userAddresses; }
-
-private:
- void getBlockchainAddressData();
- void addCachedAddressDataToDB();
- void addAddressDataJSONToDB(json::value jvalue);
- string getCacheFilename();
-
- string m_address;
- int m_walletId;
- list m_userAddresses;
- list m_walletAddresses;
-};
-
-#endif // CPFM_WALLET_ETH_H_INCLUDED
\ No newline at end of file
diff --git a/src/wallets/wallet_bch.cpp b/src/wallets/wallet_bch.cpp
new file mode 100644
index 0000000..91c4fbd
--- /dev/null
+++ b/src/wallets/wallet_bch.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#include "wallets/wallet_bch.h"
+
+list WalletBCH::getTxDetailsListForAddresses(list addresses)
+{
+ BlockchainDataSourceBCH src;
+ return src.getTxDetailsListForAddresses(addresses);
+}
diff --git a/src/wallets/wallet_bch.h b/src/wallets/wallet_bch.h
new file mode 100644
index 0000000..096c9c4
--- /dev/null
+++ b/src/wallets/wallet_bch.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#ifndef CPFM_WALLET_BCH_H_INCLUDED
+#define CPFM_WALLET_BCH_H_INCLUDED
+
+#include "wallets/wallet_type_btc.h"
+#include "datasources/datasource.h"
+
+class WalletBCH : public WalletTypeBTC
+{
+public:
+ WalletBCH(int walletId):WalletTypeBTC(walletId) { m_coinId = CPFM_COIN_ID_BCH; m_blockchainId = CPFM_BLOCKCHAIN_ID_BCH; m_walletTypeId = CPFM_WALLET_TYPE_ID_BCH; }
+
+protected:
+ virtual list getTxDetailsListForAddresses(list addresses);
+};
+
+#endif // CPFM_WALLET_BCH_H_INCLUDED
\ No newline at end of file
diff --git a/src/wallets/wallet_btc.cpp b/src/wallets/wallet_btc.cpp
new file mode 100644
index 0000000..99b3ae7
--- /dev/null
+++ b/src/wallets/wallet_btc.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#include "wallets/wallet_btc.h"
+
+list WalletBTC::getTxDetailsListForAddresses(list addresses)
+{
+ BlockchainDataSourceBTC src;
+ return src.getTxDetailsListForAddresses(addresses);
+}
diff --git a/src/wallets/wallet_btc.h b/src/wallets/wallet_btc.h
new file mode 100644
index 0000000..b445e92
--- /dev/null
+++ b/src/wallets/wallet_btc.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#ifndef CPFM_WALLET_BTC_H_INCLUDED
+#define CPFM_WALLET_BTC_H_INCLUDED
+
+#include "wallets/wallet_type_btc.h"
+#include "datasources/datasource.h"
+
+class WalletBTC : public WalletTypeBTC
+{
+public:
+ WalletBTC(int walletId):WalletTypeBTC(walletId) { m_coinId = CPFM_COIN_ID_BTC; m_blockchainId = CPFM_BLOCKCHAIN_ID_BTC; m_walletTypeId = CPFM_WALLET_TYPE_ID_BTC; }
+
+protected:
+ virtual list getTxDetailsListForAddresses(list addresses);
+};
+
+#endif // CPFM_WALLET_BTC_H_INCLUDED
\ No newline at end of file
diff --git a/src/wallets/wallet_eth.cpp b/src/wallets/wallet_eth.cpp
new file mode 100644
index 0000000..69734fe
--- /dev/null
+++ b/src/wallets/wallet_eth.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#include "wallets/wallet_eth.h"
+
+list WalletETH::getTxDetailsListForAddress(string address)
+{
+ BlockchainDataSourceETH src;
+ return src.getTxDetailsListForAddress(address);
+}
diff --git a/src/wallets/wallet_eth.h b/src/wallets/wallet_eth.h
new file mode 100644
index 0000000..0d0c35e
--- /dev/null
+++ b/src/wallets/wallet_eth.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#ifndef CPFM_WALLET_ETH_H_INCLUDED
+#define CPFM_WALLET_ETH_H_INCLUDED
+
+#include "wallets/wallet_type_eth.h"
+#include "datasources/datasource.h"
+
+class WalletETH : public WalletTypeETH
+{
+public:
+ WalletETH(int walletId):WalletTypeETH(walletId) { m_coinId = CPFM_COIN_ID_ETH; m_blockchainId = CPFM_BLOCKCHAIN_ID_ETH; m_walletTypeId = CPFM_WALLET_TYPE_ID_ETH; }
+
+protected:
+ virtual list getTxDetailsListForAddress(string address);
+};
+
+#endif // CPFM_WALLET_ETH_H_INCLUDED
\ No newline at end of file
diff --git a/src/wallets/wallet_type_btc.cpp b/src/wallets/wallet_type_btc.cpp
new file mode 100644
index 0000000..c857e05
--- /dev/null
+++ b/src/wallets/wallet_type_btc.cpp
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#include "wallets/wallet_type_btc.h"
+
+SQLPP_ALIAS_PROVIDER(max_raw_tx_id);
+
+void WalletTypeBTC::update()
+{
+ if (!m_walletId)
+ {
+ lerr << "Wallet id not defined. Ignoring update.";
+ }
+
+ linfo << "Analyzing " << getCoinName(m_coinId) << " wallet " << m_walletId;
+
+ mysql::connection db(getMysqlConfig());
+ const auto wallets = TableWallets{};
+ const auto wallets_addresses = TableWalletsAddresses{};
+ const auto wallets_tx = TableWalletsTx{};
+
+ // Load wallet addresses
+ list addresses;
+ for (const auto& row: db.run(select(wallets.wallet_id,wallets.type_id,wallets_addresses.address).from(wallets.cross_join(wallets_addresses)).where(wallets.wallet_id == wallets_addresses.wallet_id and wallets.wallet_id == m_walletId and wallets.type_id == m_walletTypeId)))
+ {
+ addresses.push_back(row.address);
+ }
+
+ // Get wallet tx data from data source and insert it in the DB raw tables.
+ list l;
+ l = getTxDetailsListForAddresses(addresses);
+ addTxDetailsListToRawDB(m_walletId,l);
+
+ // Load tx data from DB raw tables, analyze data, and insert it in DB tables.
+ l = getTxDetailsListFromRawDB(m_walletId);
+
+ db(remove_from(wallets_tx).where(wallets_tx.wallet_id == m_walletId));
+
+ addTxDetailsListToDB(m_walletId,addresses,l);
+ updateBalanceFromTxDetailsInDB(m_walletId);
+}
+
+void WalletTypeBTC::addTxDetailsListToRawDB(const int walletId, const list& l)
+{
+ mysql::connection db(getMysqlConfig());
+ const auto wallets_btc_raw_tx = TableWalletsBtcRawTx{};
+ const auto blockchain_btc_raw_tx = TableBlockchainBtcRawTx{};
+ const auto blockchain_btc_raw_tx_details = TableBlockchainBtcRawTxDetails{};
+
+ linfo << "Clearing tx raw data links for " << getCoinName(m_coinId) << " wallet " << walletId << ".";
+
+ const auto result = db(remove_from(wallets_btc_raw_tx).where(wallets_btc_raw_tx.wallet_id == walletId));
+
+ linfo << "Now adding raw data to DB for " << getCoinName(m_coinId) << " wallet " << walletId << ".";
+
+ for (const auto& tx: l)
+ {
+ string hash = tx.hash;
+
+ ldebug << "Adding raw data to DB for tx " << hash << ".";
+
+ const auto result = db(select(blockchain_btc_raw_tx.raw_tx_id).from(blockchain_btc_raw_tx).where(blockchain_btc_raw_tx.hash == hash and blockchain_btc_raw_tx.blockchain_id == m_blockchainId));
+ if (!result.empty())
+ {
+ ldebug << "Raw data for tx " << hash << " is already in DB. Ignoring.";
+
+ db(insert_into(wallets_btc_raw_tx).set(
+ wallets_btc_raw_tx.raw_tx_id = result.front().raw_tx_id,
+ wallets_btc_raw_tx.wallet_id = walletId
+ ));
+ }
+ else
+ {
+ db(insert_into(blockchain_btc_raw_tx).set(
+ blockchain_btc_raw_tx.hash = hash,
+ blockchain_btc_raw_tx.unix_time = tx.time.toUnixTime(),
+ blockchain_btc_raw_tx.blockchain_id = m_blockchainId
+ ));
+
+ int rawTxId = db(select(max(blockchain_btc_raw_tx.raw_tx_id).as(max_raw_tx_id)).from(blockchain_btc_raw_tx).unconditionally()).front().max_raw_tx_id;
+
+ ldebug << "Raw tax id created : " << rawTxId << ".";
+
+ ldebug << "Adding inputs raw data to DB for tx " << hash << ".";
+
+ for (const auto& input : tx.inputs)
+ {
+ // Inputs are positive.
+ Money amount = input.second;
+
+ db(insert_into(blockchain_btc_raw_tx_details).set(
+ blockchain_btc_raw_tx_details.raw_tx_id = rawTxId,
+ blockchain_btc_raw_tx_details.amount = amount.toBoostMpf(),
+ blockchain_btc_raw_tx_details.address = input.first
+ ));
+ }
+
+ ldebug << "Adding outputs raw data to DB for tx " << hash << ".";
+
+ for (const auto& output : tx.outputs)
+ {
+ // Outputs are negative.
+ Money amount = 0-output.second;
+
+ db(insert_into(blockchain_btc_raw_tx_details).set(
+ blockchain_btc_raw_tx_details.raw_tx_id = rawTxId,
+ blockchain_btc_raw_tx_details.amount = amount.toBoostMpf(),
+ blockchain_btc_raw_tx_details.address = output.first
+ ));
+ }
+
+ db(insert_into(wallets_btc_raw_tx).set(
+ wallets_btc_raw_tx.raw_tx_id = rawTxId,
+ wallets_btc_raw_tx.wallet_id = walletId
+ ));
+ }
+ }
+}
+
+list WalletTypeBTC::getTxDetailsListFromRawDB(const int walletId)
+{
+ mysql::connection db(getMysqlConfig());
+ const auto wallets_btc_raw_tx = TableWalletsBtcRawTx{};
+ const auto blockchain_btc_raw_tx = TableBlockchainBtcRawTx{};
+ const auto blockchain_btc_raw_tx_details = TableBlockchainBtcRawTxDetails{};
+
+ linfo << "Retrieving data from raw DB for " << getCoinName(m_coinId) << " wallet " << walletId << ".";
+
+ list l;
+ for (const auto& rowTx: db.run(select(blockchain_btc_raw_tx.raw_tx_id,blockchain_btc_raw_tx.hash,blockchain_btc_raw_tx.unix_time).from(blockchain_btc_raw_tx.cross_join(wallets_btc_raw_tx)).where(blockchain_btc_raw_tx.raw_tx_id == wallets_btc_raw_tx.raw_tx_id and wallets_btc_raw_tx.wallet_id == walletId)))
+ {
+ ldebug << "Retrieving data from raw DB for tx " << rowTx.hash << ".";
+
+ BlockchainTxDetailsTypeBTC tx;
+
+ tx.hash = rowTx.hash;
+ tx.time.setFromUnixTime(rowTx.unix_time);
+
+ ldebug << "Retrieving inputs/outputs data from raw DB for tx " << rowTx.hash << ".";
+
+ for (const auto& row: db.run(select(blockchain_btc_raw_tx_details.amount,blockchain_btc_raw_tx_details.address).from(blockchain_btc_raw_tx_details).where(blockchain_btc_raw_tx_details.raw_tx_id == rowTx.raw_tx_id)))
+ {
+ Money m (row.amount);
+
+ if (m >= 0)
+ tx.inputs[row.address] = m;
+ else
+ tx.outputs[row.address] = 0-m;
+ }
+
+ l.push_back(tx);
+ }
+
+ return l;
+}
+
+void WalletTypeBTC::addTxDetailsListToDB(const int walletId, const list walletAddresses, const list& l)
+{
+ mysql::connection db(getMysqlConfig());
+ const auto wallets_tx = TableWalletsTx{};
+
+ linfo << "Now adding data to DB for " << getCoinName(m_coinId) << " wallet " << walletId << ".";
+
+ for (const auto& tx: l)
+ {
+ Money txTotalOutputAmount;
+ Money txTotalInputAmount;
+ Money txWalletOutputAmount;
+ Money txWalletInputAmount;
+ bool bToWallet = false;
+ bool bFromWallet = false;
+ list inputAddresses;
+ list outputAddresses;
+
+ ltrace << "Now adding data to DB for tx " << tx.hash << ".";
+
+ for (const auto& input : tx.inputs)
+ {
+ //ltrace << "Input : " << input.first << ", amount : " << input.second;
+
+ txTotalInputAmount += input.second;
+
+ if (std::find(walletAddresses.begin(), walletAddresses.end(), input.first) != walletAddresses.end())
+ {
+ bFromWallet = true;
+ txWalletInputAmount += input.second;
+ }
+ else
+ {
+ inputAddresses.push_back(input.first);
+ }
+ }
+
+ for (const auto& output : tx.outputs)
+ {
+ //ltrace << "Output : " << output.first << ", amount : " << output.second;
+
+ txTotalOutputAmount += output.second;
+
+ if (std::find(walletAddresses.begin(), walletAddresses.end(), output.first) != walletAddresses.end())
+ {
+ bToWallet = true;
+ txWalletOutputAmount += output.second;
+ }
+ else
+ {
+ outputAddresses.push_back(output.first);
+ }
+ }
+
+ if (bFromWallet)
+ {
+ // In case at least one address was in the inputs, then ALL other inputs should be.
+ for (auto const& addr: inputAddresses)
+ {
+ if (std::find(walletAddresses.begin(), walletAddresses.end(), addr) == walletAddresses.end())
+ {
+ lwarn << "User configuration is missing this address: " << addr;
+ }
+ }
+
+ // In case at least one address was in the inputs, the outputs might be either another wallet for this user,
+ // or one of the wallet addresses might be missing from the configuration.
+ for (auto const& addr: outputAddresses)
+ {
+ if (std::find(walletAddresses.begin(), walletAddresses.end(), addr) == walletAddresses.end())
+ {
+ linfo << "Potential other address to analyze: " << L_Cyan << addr;
+ }
+ }
+ }
+
+ Money amount;
+ Money fee;
+
+ if (bFromWallet)
+ {
+ // The fee only applies in case this tx was initiated by the wallet
+ fee = txTotalInputAmount - txTotalOutputAmount;
+
+ amount = txWalletOutputAmount - txWalletInputAmount + fee;
+ }
+ else
+ {
+ amount = txWalletOutputAmount;
+ fee = 0;
+ }
+
+ db(insert_into(wallets_tx).set(
+ wallets_tx.wallet_id = walletId,
+ wallets_tx.amount = amount.toBoostMpf(),
+ wallets_tx.fee = fee.toBoostMpf(),
+ wallets_tx.unix_time = tx.time.toUnixTime(),
+ wallets_tx.amount_coin_id = m_coinId,
+ wallets_tx.fee_coin_id = m_coinId,
+ wallets_tx.operation_type = CPFM_WALLET_OPERATION_UNKNOWN
+ ));
+ }
+}
+
+void WalletTypeBTC::updateBalanceFromTxDetailsInDB(int walletId)
+{
+ mysql::connection db(getMysqlConfig());
+ const auto wallets_tx = TableWalletsTx{};
+ const auto wallets_balances = TableWalletsBalances{};
+
+ ldebug << "------------------------------------------------------------";
+
+ Money walletBalance = 0;
+ Money walletInputs = 0;
+ Money walletOutputs = 0;
+ Money walletFees = 0;
+
+ for (const auto& row: db.run(select(wallets_tx.amount, wallets_tx.fee).from(wallets_tx).where(wallets_tx.wallet_id == walletId).order_by(wallets_tx.unix_time.asc())))
+ {
+ Money txAmount(row.amount);
+ Money txFee(row.fee);
+
+ if (txAmount<0)
+ walletOutputs += txAmount;
+ else
+ walletInputs += txAmount;
+
+ walletFees += txFee;
+
+ walletBalance = walletInputs + walletOutputs - walletFees;
+
+ string sReason = "?";
+
+ ltrace << "Tx Amount: " << txAmount
+ << ". Reason: " << sReason
+ << ". Tx Fees: " << txFee
+ << ". Total outputs: " << walletOutputs
+ << ". Total inputs: " << walletInputs
+ << ". Total Balance: " << walletBalance;
+ }
+
+ linfo << "Wallet " << walletId << " balance is: " << walletBalance;
+
+ db(remove_from(wallets_balances).where(wallets_balances.wallet_id == walletId));
+
+ db(insert_into(wallets_balances).set(
+ wallets_balances.wallet_id = walletId,
+ wallets_balances.coin_id = m_coinId,
+ wallets_balances.balance = walletBalance.toBoostMpf()
+ ));
+}
diff --git a/src/wallets/wallet_type_btc.h b/src/wallets/wallet_type_btc.h
new file mode 100644
index 0000000..3bfdde3
--- /dev/null
+++ b/src/wallets/wallet_type_btc.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#ifndef CPFM_WALLET_TYPE_BTC_H_INCLUDED
+#define CPFM_WALLET_TYPE_BTC_H_INCLUDED
+
+#include "wallet.h"
+#include "datasources/datasource.h"
+
+class WalletTypeBTC : public Wallet
+{
+public:
+ WalletTypeBTC(int walletId):Wallet(walletId) {}
+
+ virtual void update();
+
+private:
+ void addTxDetailsListToRawDB(const int walletId, const list& l);
+ void addTxDetailsListToDB(const int walletId, const list walletAddresses, const list& l);
+ list getTxDetailsListFromRawDB(const int walletId);
+ void updateBalanceFromTxDetailsInDB(int walletId);
+
+protected:
+ virtual list getTxDetailsListForAddresses(list addresses) = 0;
+
+ int m_coinId;
+ int m_walletTypeId;
+ int m_blockchainId;
+};
+
+#endif // CPFM_WALLET_TYPE_BTC_H_INCLUDED
\ No newline at end of file
diff --git a/src/wallets/wallet_type_eth.cpp b/src/wallets/wallet_type_eth.cpp
new file mode 100644
index 0000000..8fd62e8
--- /dev/null
+++ b/src/wallets/wallet_type_eth.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2021, evilny0
+ *
+ * This file is part of cpfm.
+ *
+ * cpfm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cpm 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
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with cpfm. If not, see .
+ *
+ */
+
+#include "wallets/wallet_type_eth.h"
+
+SQLPP_ALIAS_PROVIDER(max_raw_tx_id);
+
+void WalletTypeETH::update()
+{
+ if (!m_walletId)
+ {
+ lerr << "Wallet id not defined. Ignoring update.";
+ }
+
+ linfo << "Analyzing " << getBlockchainName(m_blockchainId) << " wallet " << m_walletId;
+
+ mysql::connection db(getMysqlConfig());
+ const auto wallets = TableWallets{};
+ const auto wallets_addresses = TableWalletsAddresses{};
+ const auto wallets_tx = TableWalletsTx{};
+
+ // Load wallet address
+ string address = db(select(wallets.wallet_id,wallets.type_id,wallets_addresses.address).from(wallets.cross_join(wallets_addresses)).where(wallets.wallet_id == wallets_addresses.wallet_id and wallets.wallet_id == m_walletId and wallets.type_id == m_walletTypeId)).front().address;
+
+ // Get wallet tx data from data source and insert it in the DB raw tables.
+ list l;
+ l = getTxDetailsListForAddress(address);
+ addTxDetailsListToRawDB(m_walletId,l);
+
+ // Load tx data from DB raw tables, analyze data, and insert it in DB tables.
+ l = getTxDetailsListFromRawDB(m_walletId);
+
+ db(remove_from(wallets_tx).where(wallets_tx.wallet_id == m_walletId));
+
+ addTxDetailsListToDB(m_walletId,address,l);
+ updateBalanceFromTxDetailsInDB(m_walletId);
+}
+
+void WalletTypeETH::addTxDetailsListToRawDB(const int walletId, const list& l)
+{
+ mysql::connection db(getMysqlConfig());
+ const auto wallets_eth_raw_tx = TableWalletsEthRawTx{};
+ const auto blockchain_eth_raw_tx = TableBlockchainEthRawTx{};
+ const auto blockchain_eth_raw_tx_details = TableBlockchainEthRawTxDetails{};
+
+ linfo << "Clearing tx raw data links for " << getBlockchainName(m_blockchainId) << " wallet " << walletId << ".";
+
+ const auto result = db(remove_from(wallets_eth_raw_tx).where(wallets_eth_raw_tx.wallet_id == walletId));
+
+ linfo << "Now adding raw data to DB for " << getBlockchainName(m_blockchainId) << " wallet " << walletId << ".";
+
+ for (const auto& tx: l)
+ {
+ string hash = tx.hash;
+
+ ldebug << "Adding raw data to DB for tx " << hash << ".";
+
+ const auto result = db(select(blockchain_eth_raw_tx.raw_tx_id).from(blockchain_eth_raw_tx).where(blockchain_eth_raw_tx.hash == hash and blockchain_eth_raw_tx.blockchain_id == m_blockchainId));
+ if (!result.empty())
+ {
+ ldebug << "Raw data for tx " << hash << " is already in DB. Ignoring.";
+
+ db(insert_into(wallets_eth_raw_tx).set(
+ wallets_eth_raw_tx.raw_tx_id = result.front().raw_tx_id,
+ wallets_eth_raw_tx.wallet_id = walletId
+ ));
+ }
+ else
+ {
+ Money fee = tx.fee;
+
+ db(insert_into(blockchain_eth_raw_tx).set(
+ blockchain_eth_raw_tx.hash = hash,
+ blockchain_eth_raw_tx.unix_time = tx.time.toUnixTime(),
+ blockchain_eth_raw_tx.blockchain_id = m_blockchainId,
+ blockchain_eth_raw_tx.fee = fee.toBoostMpf()
+ ));
+
+ int rawTxId = db(select(max(blockchain_eth_raw_tx.raw_tx_id).as(max_raw_tx_id)).from(blockchain_eth_raw_tx).unconditionally()).front().max_raw_tx_id;
+
+ ldebug << "Raw tax id created : " << rawTxId << ".";
+
+ ldebug << "Adding raw data operations to DB for tx " << hash << ".";
+
+ for (const auto& op : tx.operations)
+ {
+ Money amount = op.amount;
+
+ db(insert_into(blockchain_eth_raw_tx_details).set(
+ blockchain_eth_raw_tx_details.raw_tx_id = rawTxId,
+ blockchain_eth_raw_tx_details.address_from = op.addressFrom,
+ blockchain_eth_raw_tx_details.address_to = op.addressTo,
+ blockchain_eth_raw_tx_details.amount = amount.toBoostMpf(),
+ blockchain_eth_raw_tx_details.amount_coin_id = op.amountCoinId
+ ));
+ }
+
+ db(insert_into(wallets_eth_raw_tx).set(
+ wallets_eth_raw_tx.raw_tx_id = rawTxId,
+ wallets_eth_raw_tx.wallet_id = walletId
+ ));
+ }
+ }
+}
+
+list