Compare commits
No commits in common. "a41b13f3b2639674a09b5944f459ea2836408b2d" and "b0bd473e961f6cbcde9d98819087525bbfa0821d" have entirely different histories.
a41b13f3b2
...
b0bd473e96
|
@ -38,7 +38,6 @@ set(LIBS ${LIBS} "-lcpprest")
|
||||||
include_directories(src)
|
include_directories(src)
|
||||||
include_directories(src/wallets)
|
include_directories(src/wallets)
|
||||||
include_directories(src/exchanges)
|
include_directories(src/exchanges)
|
||||||
include_directories(src/datasources)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ Cryptocurrencies portfolio manager.
|
||||||
|
|
||||||
* MySQL
|
* MySQL
|
||||||
* C++ REST SDK : https://github.com/Microsoft/cpprestsdk
|
* C++ REST SDK : https://github.com/Microsoft/cpprestsdk
|
||||||
* OpenSSL (1.1.0+)
|
* OpenSSL
|
||||||
* GMP
|
* GMP
|
||||||
* Boost
|
* Boost
|
||||||
* sqlpp11 (modified to handle decimal type) : https://github.com/evilny0/sqlpp11/tree/decimal
|
* sqlpp11 (modified to handle decimal type) : https://github.com/evilny0/sqlpp11/tree/decimal
|
||||||
|
|
|
@ -29,7 +29,7 @@ if (SQLPP11_MYSQL_MAIN_HEADER)
|
||||||
)
|
)
|
||||||
|
|
||||||
if("${check_result}" STREQUAL "")
|
if("${check_result}" STREQUAL "")
|
||||||
string(APPEND SQLPP11_MYSQL_NOT_FOUND_MESSAGE "\nRejecting found '${SQLPP11_MYSQL_MAIN_HEADER}', it seems to be invalid.")
|
string(APPEND SQLPP11_NOT_FOUND_MESSAGE "\nRejecting found '${SQLPP11_MYSQL_MAIN_HEADER}', it seems to be invalid.")
|
||||||
unset(SQLPP11_MYSQL_INCLUDE_DIR CACHE)
|
unset(SQLPP11_MYSQL_INCLUDE_DIR CACHE)
|
||||||
else()
|
else()
|
||||||
# Check succeeded, create target
|
# Check succeeded, create target
|
||||||
|
|
|
@ -7,37 +7,6 @@ SET time_zone = "+00:00";
|
||||||
/*!40101 SET NAMES utf8mb4 */;
|
/*!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` (
|
CREATE TABLE `coins` (
|
||||||
`coin_id` int(11) NOT NULL,
|
`coin_id` int(11) NOT NULL,
|
||||||
`coin_name` varchar(50) NOT NULL,
|
`coin_name` varchar(50) NOT NULL,
|
||||||
|
@ -63,7 +32,7 @@ CREATE TABLE `exchanges_ledgers` (
|
||||||
`account_id` int(11) NOT NULL,
|
`account_id` int(11) NOT NULL,
|
||||||
`exchange_ledger_id` varchar(50) NOT NULL,
|
`exchange_ledger_id` varchar(50) NOT NULL,
|
||||||
`exchange_reference_id` varchar(50) NOT NULL,
|
`exchange_reference_id` varchar(50) NOT NULL,
|
||||||
`unix_time` int(11) NOT NULL,
|
`timestamp` int(11) NOT NULL,
|
||||||
`operation_type` int(11) NOT NULL,
|
`operation_type` int(11) NOT NULL,
|
||||||
`coin_id` int(11) NOT NULL,
|
`coin_id` int(11) NOT NULL,
|
||||||
`amount` decimal(40,18) NOT NULL,
|
`amount` decimal(40,18) NOT NULL,
|
||||||
|
@ -77,7 +46,7 @@ CREATE TABLE `exchanges_trades` (
|
||||||
`exchange_order_id` varchar(50) NOT NULL,
|
`exchange_order_id` varchar(50) NOT NULL,
|
||||||
`base_coin_id` int(11) NOT NULL,
|
`base_coin_id` int(11) NOT NULL,
|
||||||
`quote_coin_id` int(11) NOT NULL,
|
`quote_coin_id` int(11) NOT NULL,
|
||||||
`unix_time` int(11) NOT NULL,
|
`timestamp` int(11) NOT NULL,
|
||||||
`type` int(11) NOT NULL,
|
`type` int(11) NOT NULL,
|
||||||
`order_type` int(11) NOT NULL,
|
`order_type` int(11) NOT NULL,
|
||||||
`price` decimal(40,18) NOT NULL,
|
`price` decimal(40,18) NOT NULL,
|
||||||
|
@ -91,8 +60,7 @@ CREATE TABLE `wallets` (
|
||||||
`wallet_id` int(11) NOT NULL,
|
`wallet_id` int(11) NOT NULL,
|
||||||
`user_id` int(11) NOT NULL,
|
`user_id` int(11) NOT NULL,
|
||||||
`type_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;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
CREATE TABLE `wallets_addresses` (
|
CREATE TABLE `wallets_addresses` (
|
||||||
|
@ -109,40 +77,16 @@ CREATE TABLE `wallets_balances` (
|
||||||
`balance` decimal(48,18) NOT NULL
|
`balance` decimal(48,18) NOT NULL
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) 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` (
|
CREATE TABLE `wallets_tx` (
|
||||||
`tx_id` int(11) NOT NULL,
|
`tx_id` int(11) NOT NULL,
|
||||||
|
`blockchain_tx_id` varchar(200) NOT NULL,
|
||||||
`wallet_id` int(11) NOT NULL,
|
`wallet_id` int(11) NOT NULL,
|
||||||
`amount` decimal(40,18) NOT NULL,
|
`amount` decimal(40,18) NOT NULL,
|
||||||
`fee` decimal(40,18) NOT NULL,
|
`fee` decimal(40,18) NOT NULL,
|
||||||
`amount_coin_id` int(11) NOT NULL,
|
`timestamp` 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;
|
) 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`
|
ALTER TABLE `exchanges_accounts`
|
||||||
ADD PRIMARY KEY (`account_id`);
|
ADD PRIMARY KEY (`account_id`);
|
||||||
|
|
||||||
|
@ -159,20 +103,12 @@ ALTER TABLE `wallets_addresses`
|
||||||
ADD PRIMARY KEY (`address_id`);
|
ADD PRIMARY KEY (`address_id`);
|
||||||
|
|
||||||
ALTER TABLE `wallets_balances`
|
ALTER TABLE `wallets_balances`
|
||||||
ADD PRIMARY KEY (`wallet_id`,`coin_id`);
|
ADD PRIMARY KEY (`wallet_id`);
|
||||||
|
|
||||||
ALTER TABLE `wallets_tx`
|
ALTER TABLE `wallets_tx`
|
||||||
ADD PRIMARY KEY (`tx_id`);
|
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`
|
ALTER TABLE `exchanges_accounts`
|
||||||
MODIFY `account_id` int(11) NOT NULL AUTO_INCREMENT;
|
MODIFY `account_id` int(11) NOT NULL AUTO_INCREMENT;
|
||||||
ALTER TABLE `exchanges_ledgers`
|
ALTER TABLE `exchanges_ledgers`
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
aux_source_directory(. SOURCE_LIST)
|
aux_source_directory(. SOURCE_LIST)
|
||||||
aux_source_directory(wallets SOURCE_LIST_WALLETS)
|
aux_source_directory(wallets SOURCE_LIST_WALLETS)
|
||||||
aux_source_directory(exchanges SOURCE_LIST_EXCHANGES)
|
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} ${SOURCE_LIST_DATASOURCES})
|
add_executable(${EXECUTABLE} ${SOURCE_LIST} ${SOURCE_LIST_WALLETS} ${SOURCE_LIST_EXCHANGES})
|
||||||
target_link_libraries(${EXECUTABLE} ${LIBS})
|
target_link_libraries(${EXECUTABLE} ${LIBS})
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "datasources/blockchain_info.h"
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeBTC> BlockchainDataSourceBTC_BlockchainInfo::getTxDetailsListForAddress(string address)
|
|
||||||
{
|
|
||||||
linfo << "Blockchain.info : Analyzing address: " << address;
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeBTC> 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<jvalue["txs"].size();i++)
|
|
||||||
{
|
|
||||||
BlockchainTxDetailsTypeBTC tx;
|
|
||||||
|
|
||||||
tx.hash = jvalue["txs"][i]["hash"].as_string();
|
|
||||||
tx.time.setFromUnixTime(jvalue["txs"][i]["time"].as_integer());
|
|
||||||
|
|
||||||
for (int j=0;j<jvalue["txs"][i]["inputs"].size();j++)
|
|
||||||
{
|
|
||||||
string addr = jvalue["txs"][i]["inputs"][j]["prev_out"]["addr"].as_string();
|
|
||||||
__int64 amount = jvalue["txs"][i]["inputs"][j]["prev_out"]["value"].as_integer();
|
|
||||||
|
|
||||||
Money m = amount;
|
|
||||||
Money mdecimals = m/100000000;
|
|
||||||
|
|
||||||
// The same address can be multiple time in the inputs, so we need to sum the amounts.
|
|
||||||
tx.inputs[addr] += mdecimals;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j=0;j<jvalue["txs"][i]["out"].size();j++)
|
|
||||||
{
|
|
||||||
string addr = jvalue["txs"][i]["out"][j]["addr"].as_string();
|
|
||||||
__int64 amount = jvalue["txs"][i]["out"][j]["value"].as_integer();
|
|
||||||
|
|
||||||
Money m = amount;
|
|
||||||
Money mdecimals = m/100000000;
|
|
||||||
|
|
||||||
// The same address can only be once in the outputs.
|
|
||||||
tx.outputs[addr] = mdecimals;
|
|
||||||
}
|
|
||||||
|
|
||||||
l.push_back(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
string BlockchainDataSourceBTC_BlockchainInfo::getCacheFilenameForAddress(string address)
|
|
||||||
{
|
|
||||||
string cacheFilename("data/cache/blockchain.info/btc/" + address);
|
|
||||||
return cacheFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlockchainDataSourceBTC_BlockchainInfo::saveBlockchainAddressDataToCacheFile(string address)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
linfo << "Blockchain.info : querying API about " << address;
|
|
||||||
|
|
||||||
string sRequestURL = "/rawaddr/";
|
|
||||||
sRequestURL += address;
|
|
||||||
http_client apiclient("https://blockchain.info/");
|
|
||||||
|
|
||||||
m_currentRequestCacheFilename = getCacheFilenameForAddress(address);
|
|
||||||
|
|
||||||
apiclient.request(methods::GET,sRequestURL).then([](http_response response)
|
|
||||||
{
|
|
||||||
if (response.status_code() == status_codes::OK)
|
|
||||||
{
|
|
||||||
ldebug << "Blockchain.info : response OK.";
|
|
||||||
return response.extract_json();
|
|
||||||
}
|
|
||||||
else if (response.status_code() == status_codes::TooManyRequests)
|
|
||||||
{
|
|
||||||
lwarn << "Blockchain.info : 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<json::value> 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CPFM_DATASOURCE_BLOCKCHAIN_INFO_H_INCLUDED
|
|
||||||
#define CPFM_DATASOURCE_BLOCKCHAIN_INFO_H_INCLUDED
|
|
||||||
|
|
||||||
#include "datasources/datasource.h"
|
|
||||||
|
|
||||||
|
|
||||||
class BlockchainDataSourceBTC_BlockchainInfo
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
list<BlockchainTxDetailsTypeBTC> getTxDetailsListForAddress(string address);
|
|
||||||
|
|
||||||
private:
|
|
||||||
string getCacheFilenameForAddress(string address);
|
|
||||||
void saveBlockchainAddressDataToCacheFile(string address);
|
|
||||||
|
|
||||||
string m_currentRequestCacheFilename;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CPFM_DATASOURCE_BLOCKCHAIN_INFO_H_INCLUDED
|
|
|
@ -1,245 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "datasources/blockchair.h"
|
|
||||||
|
|
||||||
|
|
||||||
Time BlockchainDataSourceTypeBTC_Blockchair::getTimeFromString(string s)
|
|
||||||
{
|
|
||||||
std::istringstream in{s};
|
|
||||||
date::sys_time<std::chrono::seconds> tp;
|
|
||||||
in >> date::parse("%F %T", tp);
|
|
||||||
|
|
||||||
Time t;
|
|
||||||
t.setFromUnixTime(std::chrono::system_clock::to_time_t(tp));
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeBTC> BlockchainDataSourceTypeBTC_Blockchair::getTxDetailsListForAddresses(list<string> addresses)
|
|
||||||
{
|
|
||||||
linfo << "Blockchair : analyzing address list";
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeBTC> 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<jvalue["data"]["transactions"].size();i++)
|
|
||||||
{
|
|
||||||
string txHash = jvalue["data"]["transactions"][i].as_string();
|
|
||||||
|
|
||||||
linfo << "Blockchair : found tx " << txHash << ". Starting analysis.";
|
|
||||||
|
|
||||||
if (!bfs::exists(getCacheFilenameForTx(txHash)))
|
|
||||||
{
|
|
||||||
saveBlockchainTxDataToCacheFile(txHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bfs::exists(getCacheFilenameForTx(txHash)))
|
|
||||||
{
|
|
||||||
lerr << "Blockchair : cache file for tx " << txHash << " could not be found. Tx data was not retrieved.";
|
|
||||||
}
|
|
||||||
|
|
||||||
ifstream fTx;
|
|
||||||
fTx.open(getCacheFilenameForTx(txHash));
|
|
||||||
json::value jvalueTx = json::value::parse(fTx);
|
|
||||||
fTx.close();
|
|
||||||
|
|
||||||
BlockchainTxDetailsTypeBTC tx;
|
|
||||||
|
|
||||||
tx.hash = txHash;
|
|
||||||
tx.time = getTimeFromString (jvalueTx["data"][txHash]["transaction"]["time"].as_string());
|
|
||||||
|
|
||||||
for (int j=0;j<jvalueTx["data"][txHash]["inputs"].size();j++)
|
|
||||||
{
|
|
||||||
string addr = jvalueTx["data"][txHash]["inputs"][j]["recipient"].as_string();
|
|
||||||
__int64 amount = jvalueTx["data"][txHash]["inputs"][j]["value"].as_integer();
|
|
||||||
|
|
||||||
Money m = amount;
|
|
||||||
Money mdecimals = m/100000000;
|
|
||||||
|
|
||||||
// The same address can be multiple time in the inputs, so we need to sum the amounts.
|
|
||||||
tx.inputs[addr] += mdecimals;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j=0;j<jvalueTx["data"][txHash]["outputs"].size();j++)
|
|
||||||
{
|
|
||||||
string addr = jvalueTx["data"][txHash]["outputs"][j]["recipient"].as_string();
|
|
||||||
__int64 amount = jvalueTx["data"][txHash]["outputs"][j]["value"].as_integer();
|
|
||||||
|
|
||||||
Money m = amount;
|
|
||||||
Money mdecimals = m/100000000;
|
|
||||||
|
|
||||||
// The same address can only be once in the outputs.
|
|
||||||
tx.outputs[addr] = mdecimals;
|
|
||||||
}
|
|
||||||
|
|
||||||
l.push_back(tx);
|
|
||||||
|
|
||||||
linfo << "Blockchair : finished analysis for tx " << txHash << ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
linfo << "Blockchair : finished analysis for address list.";
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
string BlockchainDataSourceTypeBTC_Blockchair::getCacheFilenameForAddresses(list<string> 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<string> 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<json::value> 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<json::value> 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CPFM_DATASOURCE_BLOCKCHAIR_H_INCLUDED
|
|
||||||
#define CPFM_DATASOURCE_BLOCKCHAIR_H_INCLUDED
|
|
||||||
|
|
||||||
#include "datasources/datasource.h"
|
|
||||||
|
|
||||||
|
|
||||||
class BlockchainDataSourceTypeBTC_Blockchair
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
list<BlockchainTxDetailsTypeBTC> getTxDetailsListForAddresses(list<string> addresses);
|
|
||||||
|
|
||||||
private:
|
|
||||||
string getCacheFilenameForAddresses(list<string> address);
|
|
||||||
string getCacheFilenameForTx(string txHash);
|
|
||||||
|
|
||||||
void saveBlockchainAddressesDataToCacheFile(list<string> 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
|
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "datasources/datasource.h"
|
|
||||||
#include "datasources/blockchain_info.h"
|
|
||||||
#include "datasources/blockchair.h"
|
|
||||||
#include "datasources/etherscan.h"
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeBTC> BlockchainDataSourceBTC::getTxDetailsListForAddresses(list<string> addresses)
|
|
||||||
{
|
|
||||||
list<BlockchainTxDetailsTypeBTC> l;
|
|
||||||
|
|
||||||
// Blockchain.info
|
|
||||||
/*
|
|
||||||
BlockchainDataSourceBTC_BlockchainInfo bci;
|
|
||||||
list<string> hashList;
|
|
||||||
|
|
||||||
for (auto const address: addresses)
|
|
||||||
{
|
|
||||||
list<BlockchainTxDetailsTypeBTC> 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<BlockchainTxDetailsTypeBTC> BlockchainDataSourceBCH::getTxDetailsListForAddresses(list<string> addresses)
|
|
||||||
{
|
|
||||||
list<BlockchainTxDetailsTypeBTC> l;
|
|
||||||
|
|
||||||
// Blockchair
|
|
||||||
BlockchainDataSourceBCH_Blockchair bc;
|
|
||||||
l = bc.getTxDetailsListForAddresses(addresses);
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeETH> BlockchainDataSourceETH::getTxDetailsListForAddress(string address)
|
|
||||||
{
|
|
||||||
list<BlockchainTxDetailsTypeETH> l;
|
|
||||||
|
|
||||||
// Etherscan
|
|
||||||
BlockchainDataSourceETH_Etherscan bc;
|
|
||||||
l = bc.getTxDetailsListForAddress(address);
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CPFM_DATASOURCE_H_INCLUDED
|
|
||||||
#define CPFM_DATASOURCE_H_INCLUDED
|
|
||||||
|
|
||||||
#include "pf.h"
|
|
||||||
|
|
||||||
class BlockchainTxDetailsTypeBTC
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
string hash;
|
|
||||||
Time time;
|
|
||||||
map <string,Money> inputs;
|
|
||||||
map <string,Money> outputs;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BlockchainTxOperationTypeETH
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
string addressFrom;
|
|
||||||
string addressTo;
|
|
||||||
Money amount;
|
|
||||||
int amountCoinId;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BlockchainTxDetailsTypeETH
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
string hash;
|
|
||||||
Time time;
|
|
||||||
list<BlockchainTxOperationTypeETH> operations;
|
|
||||||
Money fee;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BlockchainDataSourceBTC
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
list<BlockchainTxDetailsTypeBTC> getTxDetailsListForAddresses(list<string> addresses);
|
|
||||||
};
|
|
||||||
|
|
||||||
class BlockchainDataSourceBCH
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
list<BlockchainTxDetailsTypeBTC> getTxDetailsListForAddresses(list<string> addresses);
|
|
||||||
};
|
|
||||||
|
|
||||||
class BlockchainDataSourceETH
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
list<BlockchainTxDetailsTypeETH> getTxDetailsListForAddress(string address);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CPFM_DATASOURCE_H_INCLUDED
|
|
|
@ -1,323 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "datasources/etherscan.h"
|
|
||||||
|
|
||||||
#define TXLIST_NORMAL "txlist"
|
|
||||||
#define TXLIST_INTERNAL "txlistinternal"
|
|
||||||
#define TXLIST_TOKENS "tokentx"
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeETH> BlockchainDataSourceETH_Etherscan::getTxDetailsListForAddress(string address)
|
|
||||||
{
|
|
||||||
linfo << "Etherscan : Analyzing address: " << address;
|
|
||||||
|
|
||||||
if (!retrieveCacheFilesForAddress(address))
|
|
||||||
{
|
|
||||||
list<BlockchainTxDetailsTypeETH> l;
|
|
||||||
lerr << "Etherscan : cache files could not be found. Address data was not retrieved.";
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
list<string> hashListNormal;
|
|
||||||
list<string> hashListInternal;
|
|
||||||
list<string> hashListToken;
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeETH> lNormal = getTxDetailsListForAddressTxType(address,TXLIST_NORMAL,hashListNormal);
|
|
||||||
list<BlockchainTxDetailsTypeETH> lInternal = getTxDetailsListForAddressTxType(address,TXLIST_INTERNAL,hashListInternal);
|
|
||||||
list<BlockchainTxDetailsTypeETH> lToken = getTxDetailsListForAddressTxType(address,TXLIST_TOKENS,hashListToken);
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeETH> l = lNormal;
|
|
||||||
|
|
||||||
// Add internals tx to the list
|
|
||||||
for (auto const tx: lInternal)
|
|
||||||
{
|
|
||||||
BlockchainTxDetailsTypeETH txNew = tx;
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeETH>::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<BlockchainTxDetailsTypeETH>::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<BlockchainTxDetailsTypeETH> BlockchainDataSourceETH_Etherscan::getTxDetailsListForAddressTxType(string address, string type, list<string>& hashList)
|
|
||||||
{
|
|
||||||
list<BlockchainTxDetailsTypeETH> 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<jvalue["result"].size();i++)
|
|
||||||
{
|
|
||||||
ltrace << "Found tx " << jvalue["result"][i]["hash"].as_string();
|
|
||||||
|
|
||||||
BlockchainTxDetailsTypeETH tx;
|
|
||||||
|
|
||||||
// Search if the hash is already in the list. If yes, remove the element.
|
|
||||||
// It will be added after the operation list is updated.
|
|
||||||
list<BlockchainTxDetailsTypeETH>::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<multiplier;i++)
|
|
||||||
{
|
|
||||||
divider*=10;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
lerr << "Internal tx are not supported.";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lerr << "Unknown tx type : " << type << ". Tx will be ignored.";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
hashList.push_back(tx.hash);
|
|
||||||
l.push_back(tx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BlockchainDataSourceETH_Etherscan::retrieveCacheFilesForAddress(string address)
|
|
||||||
{
|
|
||||||
if (!bfs::exists(getCacheFilenameForAddress(address,TXLIST_NORMAL)))
|
|
||||||
{
|
|
||||||
saveBlockchainAddressDataToCacheFile(address,TXLIST_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bfs::exists(getCacheFilenameForAddress(address,TXLIST_NORMAL)))
|
|
||||||
{
|
|
||||||
lerr << "Etherscan : cache file for " << TXLIST_NORMAL << " could not be found.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bfs::exists(getCacheFilenameForAddress(address,TXLIST_INTERNAL)))
|
|
||||||
{
|
|
||||||
saveBlockchainAddressDataToCacheFile(address,TXLIST_INTERNAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bfs::exists(getCacheFilenameForAddress(address,TXLIST_INTERNAL)))
|
|
||||||
{
|
|
||||||
lerr << "Etherscan : cache file for " << TXLIST_INTERNAL << " could not be found.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bfs::exists(getCacheFilenameForAddress(address,TXLIST_TOKENS)))
|
|
||||||
{
|
|
||||||
saveBlockchainAddressDataToCacheFile(address,TXLIST_TOKENS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bfs::exists(getCacheFilenameForAddress(address,TXLIST_TOKENS)))
|
|
||||||
{
|
|
||||||
lerr << "Etherscan : cache file for " << TXLIST_TOKENS << " could not be found.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
string BlockchainDataSourceETH_Etherscan::getCacheFilenameForAddress(string address, string type)
|
|
||||||
{
|
|
||||||
string cacheFilename("data/cache/etherscan.io/" + type + "/" + address);
|
|
||||||
return cacheFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlockchainDataSourceETH_Etherscan::saveBlockchainAddressDataToCacheFile(string address, string type)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
sleep (5);
|
|
||||||
|
|
||||||
linfo << "Etherscan : querying API about " << type << " for " << address;
|
|
||||||
|
|
||||||
string sRequestURL = "/api?module=account&action="+type+"&address=";
|
|
||||||
sRequestURL += address;
|
|
||||||
http_client apiclient("https://api.etherscan.io");
|
|
||||||
|
|
||||||
m_currentRequestCacheFilename = getCacheFilenameForAddress(address,type);
|
|
||||||
|
|
||||||
apiclient.request(methods::GET,sRequestURL).then([](http_response response)
|
|
||||||
{
|
|
||||||
if (response.status_code() == status_codes::OK)
|
|
||||||
{
|
|
||||||
ldebug << "Etherscan : response OK.";
|
|
||||||
return response.extract_json();
|
|
||||||
}
|
|
||||||
return pplx::task_from_result(json::value());
|
|
||||||
})
|
|
||||||
.then([this](pplx::task<json::value> 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;
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CPFM_DATASOURCE_ETHERSCAN_H_INCLUDED
|
|
||||||
#define CPFM_DATASOURCE_ETHERSCAN_H_INCLUDED
|
|
||||||
|
|
||||||
#include "datasources/datasource.h"
|
|
||||||
|
|
||||||
|
|
||||||
class BlockchainDataSourceETH_Etherscan
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
list<BlockchainTxDetailsTypeETH> getTxDetailsListForAddress(string address);
|
|
||||||
|
|
||||||
private:
|
|
||||||
list<BlockchainTxDetailsTypeETH> getTxDetailsListForAddressTxType(string address, string type, list<string>& 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
|
|
|
@ -47,10 +47,10 @@ void ExchangeHandlerKraken::analyzeUserData()
|
||||||
getAccountBalance();
|
getAccountBalance();
|
||||||
analyzeAccountBalance();
|
analyzeAccountBalance();
|
||||||
|
|
||||||
getAccountTrades();
|
//getAccountTrades();
|
||||||
//analyzeAccountTrades();
|
//analyzeAccountTrades();
|
||||||
|
|
||||||
getAccountLedgers();
|
//getAccountLedgers();
|
||||||
//analyzeAccountLedgers();
|
//analyzeAccountLedgers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,13 +222,14 @@ vector<unsigned char> ExchangeHandlerKraken::hmac_sha512(const vector<unsigned c
|
||||||
unsigned int len = EVP_MAX_MD_SIZE;
|
unsigned int len = EVP_MAX_MD_SIZE;
|
||||||
vector<unsigned char> digest(len);
|
vector<unsigned char> digest(len);
|
||||||
|
|
||||||
HMAC_CTX* ctx = HMAC_CTX_new();
|
HMAC_CTX ctx;
|
||||||
|
HMAC_CTX_init(&ctx);
|
||||||
|
|
||||||
HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha512(), NULL);
|
HMAC_Init_ex(&ctx, key.data(), key.size(), EVP_sha512(), NULL);
|
||||||
HMAC_Update(ctx, data.data(), data.size());
|
HMAC_Update(&ctx, data.data(), data.size());
|
||||||
HMAC_Final(ctx, digest.data(), &len);
|
HMAC_Final(&ctx, digest.data(), &len);
|
||||||
|
|
||||||
HMAC_CTX_free(ctx);
|
HMAC_CTX_cleanup(&ctx);
|
||||||
|
|
||||||
return digest;
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
using namespace cpfm;
|
using namespace farm;
|
||||||
using namespace log;
|
using namespace log;
|
||||||
|
|
||||||
const char* ErrorLogger::name() { return "ERROR"; }
|
const char* ErrorLogger::name() { return "ERROR"; }
|
||||||
|
@ -34,8 +34,6 @@ const char* InfoLogger::name() { return "INFO "; }
|
||||||
const char* InfoLogger::color() { return L_White; }
|
const char* InfoLogger::color() { return L_White; }
|
||||||
const char* DebugLogger::name() { return "DEBUG"; }
|
const char* DebugLogger::name() { return "DEBUG"; }
|
||||||
const char* DebugLogger::color() { return L_Teal; }
|
const char* DebugLogger::color() { return L_Teal; }
|
||||||
const char* TraceLogger::name() { return "TRACE"; }
|
|
||||||
const char* TraceLogger::color() { return L_Violet; }
|
|
||||||
|
|
||||||
LoggerBase::LoggerBase()
|
LoggerBase::LoggerBase()
|
||||||
{
|
{
|
||||||
|
|
14
src/log.h
14
src/log.h
|
@ -28,14 +28,13 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define llog(X) cpfm::log::Logger<X>()
|
#define llog(X) farm::log::Logger<X>()
|
||||||
#define lerr llog(cpfm::log::ErrorLogger)
|
#define lerr llog(farm::log::ErrorLogger)
|
||||||
#define linfo llog(cpfm::log::InfoLogger)
|
#define linfo llog(farm::log::InfoLogger)
|
||||||
#define lwarn llog(cpfm::log::WarningLogger)
|
#define lwarn llog(farm::log::WarningLogger)
|
||||||
#define ldebug llog(cpfm::log::DebugLogger)
|
#define ldebug llog(farm::log::DebugLogger)
|
||||||
#define ltrace llog(cpfm::log::TraceLogger)
|
|
||||||
|
|
||||||
namespace cpfm { namespace log {
|
namespace farm { namespace log {
|
||||||
|
|
||||||
#define L_Reset "\x1b[0m" // Text Reset
|
#define L_Reset "\x1b[0m" // Text Reset
|
||||||
|
|
||||||
|
@ -108,7 +107,6 @@ struct ErrorLogger: public DefaultLogger { static const char* name(); static con
|
||||||
struct WarningLogger: public DefaultLogger { static const char* name(); static const char* color(); };
|
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 InfoLogger: public DefaultLogger { static const char* name(); static const char* color(); };
|
||||||
struct DebugLogger: 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
|
class LoggerBase
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
Money::Money ()
|
Money::Money ()
|
||||||
{
|
{
|
||||||
m_amount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Money::Money (bmp::mpf_float_50 x)
|
Money::Money (bmp::mpf_float_50 x)
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
Money& operator/=(const Money& x);
|
Money& operator/=(const Money& x);
|
||||||
friend Money operator/(Money a, const Money& b) { a /= b; return a; }
|
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);
|
||||||
friend bool operator!=(const Money& a, const int& b) { return !operator==(a,b); }
|
friend bool operator!=(const Money& a, const int& b) { return !operator==(a,b); }
|
||||||
|
|
24
src/pf.cpp
24
src/pf.cpp
|
@ -40,8 +40,8 @@ void PortfolioManager::doTestStuff()
|
||||||
// Test user 1
|
// Test user 1
|
||||||
emptyUserBalances(1);
|
emptyUserBalances(1);
|
||||||
|
|
||||||
// ExchangesManager exchangesManager(1);
|
ExchangesManager exchangesManager(1);
|
||||||
// exchangesManager.analyzeUserAccounts();
|
exchangesManager.analyzeUserAccounts();
|
||||||
|
|
||||||
WalletsManager walletsManager(1);
|
WalletsManager walletsManager(1);
|
||||||
walletsManager.analyzeUserWallets();
|
walletsManager.analyzeUserWallets();
|
||||||
|
@ -49,7 +49,6 @@ void PortfolioManager::doTestStuff()
|
||||||
displayUserBalances(1);
|
displayUserBalances(1);
|
||||||
|
|
||||||
// Test user 2
|
// Test user 2
|
||||||
/*
|
|
||||||
emptyUserBalances(2);
|
emptyUserBalances(2);
|
||||||
|
|
||||||
ExchangesManager exchangesManagerTwo(2);
|
ExchangesManager exchangesManagerTwo(2);
|
||||||
|
@ -59,7 +58,6 @@ void PortfolioManager::doTestStuff()
|
||||||
walletsManagerTwo.analyzeUserWallets();
|
walletsManagerTwo.analyzeUserWallets();
|
||||||
|
|
||||||
displayUserBalances(2);
|
displayUserBalances(2);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortfolioManager::emptyUserBalances(int userId)
|
void PortfolioManager::emptyUserBalances(int userId)
|
||||||
|
@ -157,24 +155,6 @@ string getCoinName(int coinId)
|
||||||
case CPFM_COIN_ID_BTG:
|
case CPFM_COIN_ID_BTG:
|
||||||
s = "BTG";
|
s = "BTG";
|
||||||
break;
|
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:
|
default:
|
||||||
s = "Error!";
|
s = "Error!";
|
||||||
break;
|
break;
|
||||||
|
|
33
src/pf.h
33
src/pf.h
|
@ -39,31 +39,14 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "money.h"
|
#include "money.h"
|
||||||
|
|
||||||
#define CPFM_COIN_ID_BTC 1
|
#define CPFM_COIN_ID_BTC 1
|
||||||
#define CPFM_COIN_ID_LTC 2
|
#define CPFM_COIN_ID_LTC 2
|
||||||
#define CPFM_COIN_ID_EUR 3
|
#define CPFM_COIN_ID_EUR 3
|
||||||
#define CPFM_COIN_ID_ICN 4
|
#define CPFM_COIN_ID_ICN 4
|
||||||
#define CPFM_COIN_ID_ETC 5
|
#define CPFM_COIN_ID_ETC 5
|
||||||
#define CPFM_COIN_ID_ETH 6
|
#define CPFM_COIN_ID_ETH 6
|
||||||
#define CPFM_COIN_ID_BCH 7
|
#define CPFM_COIN_ID_BCH 7
|
||||||
#define CPFM_COIN_ID_BTG 8
|
#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<std::chrono::milliseconds>
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace bmp = boost::multiprecision;
|
namespace bmp = boost::multiprecision;
|
||||||
namespace bfs = boost::filesystem;
|
namespace bfs = boost::filesystem;
|
||||||
|
|
|
@ -96,13 +96,13 @@ Money PriceSourceCryptoWatch::getCoinPriceFromData(int coinId)
|
||||||
{
|
{
|
||||||
case CPFM_COIN_ID_BTC:
|
case CPFM_COIN_ID_BTC:
|
||||||
{
|
{
|
||||||
Money x (jvalue["result"]["market:kraken:btceur"]);
|
Money x (jvalue["result"]["kraken:btceur"]);
|
||||||
m = x;
|
m = x;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CPFM_COIN_ID_LTC:
|
case CPFM_COIN_ID_LTC:
|
||||||
{
|
{
|
||||||
Money x (jvalue["result"]["market:kraken:ltceur"]);
|
Money x (jvalue["result"]["kraken:ltceur"]);
|
||||||
m = x;
|
m = x;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -113,79 +113,38 @@ Money PriceSourceCryptoWatch::getCoinPriceFromData(int coinId)
|
||||||
}
|
}
|
||||||
case CPFM_COIN_ID_ICN:
|
case CPFM_COIN_ID_ICN:
|
||||||
{
|
{
|
||||||
Money x (jvalue["result"]["market:kraken:icnbtc"]);
|
Money x (jvalue["result"]["kraken:icnbtc"]);
|
||||||
Money y (jvalue["result"]["market:kraken:btceur"]);
|
Money y (jvalue["result"]["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;
|
m = x*y;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CPFM_COIN_ID_ETC:
|
case CPFM_COIN_ID_ETC:
|
||||||
{
|
{
|
||||||
Money x (jvalue["result"]["market:kraken:etceur"]);
|
Money x (jvalue["result"]["kraken:etceur"]);
|
||||||
m = x;
|
m = x;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CPFM_COIN_ID_ETH:
|
case CPFM_COIN_ID_ETH:
|
||||||
{
|
{
|
||||||
Money x (jvalue["result"]["market:kraken:etheur"]);
|
Money x (jvalue["result"]["kraken:etheur"]);
|
||||||
m = x;
|
m = x;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CPFM_COIN_ID_BCH:
|
case CPFM_COIN_ID_BCH:
|
||||||
{
|
{
|
||||||
Money x (jvalue["result"]["market:kraken:bcheur"]);
|
Money x (jvalue["result"]["kraken:bcheur"]);
|
||||||
m = x;
|
m = x;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CPFM_COIN_ID_BTG:
|
case CPFM_COIN_ID_BTG:
|
||||||
{
|
{
|
||||||
Money x (jvalue["result"]["market:bitfinex:btgbtc"]);
|
Money x (jvalue["result"]["bitfinex:btgbtc"]);
|
||||||
Money y (jvalue["result"]["market:kraken:btceur"]);
|
Money y (jvalue["result"]["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;
|
m = x*y;
|
||||||
break;
|
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:
|
default:
|
||||||
{
|
{
|
||||||
m = 0;
|
m = 0;
|
||||||
|
|
838
src/sql.h
838
src/sql.h
|
@ -216,32 +216,9 @@ namespace TableWallets_
|
||||||
};
|
};
|
||||||
using _traits = sqlpp::make_traits<sqlpp::varchar>;
|
using _traits = sqlpp::make_traits<sqlpp::varchar>;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Active
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "active";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T active;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return active;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return active;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::boolean>;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TableWallets : sqlpp::table_t<TableWallets,TableWallets_::WalletId,TableWallets_::UserId,TableWallets_::TypeId,TableWallets_::WalletName,TableWallets_::Active>
|
struct TableWallets : sqlpp::table_t<TableWallets,TableWallets_::WalletId,TableWallets_::UserId,TableWallets_::TypeId,TableWallets_::WalletName>
|
||||||
{
|
{
|
||||||
using _value_type = sqlpp::no_value_t;
|
using _value_type = sqlpp::no_value_t;
|
||||||
struct _alias_t
|
struct _alias_t
|
||||||
|
@ -453,6 +430,29 @@ namespace TableWalletsTx_
|
||||||
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BlockchainTxId
|
||||||
|
{
|
||||||
|
struct _alias_t
|
||||||
|
{
|
||||||
|
static constexpr const char _literal[] = "blockchain_tx_id";
|
||||||
|
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
||||||
|
template <typename T>
|
||||||
|
struct _member_t
|
||||||
|
{
|
||||||
|
T blockchain_tx_id;
|
||||||
|
T& operator()()
|
||||||
|
{
|
||||||
|
return blockchain_tx_id;
|
||||||
|
}
|
||||||
|
const T& operator()() const
|
||||||
|
{
|
||||||
|
return blockchain_tx_id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
using _traits = sqlpp::make_traits<sqlpp::varchar>;
|
||||||
|
};
|
||||||
|
|
||||||
struct Amount
|
struct Amount
|
||||||
{
|
{
|
||||||
struct _alias_t
|
struct _alias_t
|
||||||
|
@ -499,92 +499,23 @@ namespace TableWalletsTx_
|
||||||
using _traits = sqlpp::make_traits<sqlpp::decimal>;
|
using _traits = sqlpp::make_traits<sqlpp::decimal>;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AmountCoinId
|
struct Timestamp
|
||||||
{
|
{
|
||||||
struct _alias_t
|
struct _alias_t
|
||||||
{
|
{
|
||||||
static constexpr const char _literal[] = "amount_coin_id";
|
static constexpr const char _literal[] = "timestamp";
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct _member_t
|
struct _member_t
|
||||||
{
|
{
|
||||||
T amount_coin_id;
|
T timestamp;
|
||||||
T& operator()()
|
T& operator()()
|
||||||
{
|
{
|
||||||
return amount_coin_id;
|
return timestamp;
|
||||||
}
|
}
|
||||||
const T& operator()() const
|
const T& operator()() const
|
||||||
{
|
{
|
||||||
return amount_coin_id;
|
return timestamp;
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FeeCoinId
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "fee_coin_id";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UnixTime
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "unix_time";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T unix_time;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return unix_time;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return unix_time;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct OperationType
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "operation_type";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T operation_type;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return operation_type;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return operation_type;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -592,7 +523,7 @@ namespace TableWalletsTx_
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TableWalletsTx : sqlpp::table_t<TableWalletsTx,TableWalletsTx_::TxId,TableWalletsTx_::WalletId,TableWalletsTx_::Amount,TableWalletsTx_::Fee,TableWalletsTx_::AmountCoinId,TableWalletsTx_::FeeCoinId,TableWalletsTx_::UnixTime,TableWalletsTx_::OperationType>
|
struct TableWalletsTx : sqlpp::table_t<TableWalletsTx,TableWalletsTx_::TxId,TableWalletsTx_::WalletId,TableWalletsTx_::BlockchainTxId,TableWalletsTx_::Amount,TableWalletsTx_::Fee,TableWalletsTx_::Timestamp>
|
||||||
{
|
{
|
||||||
using _value_type = sqlpp::no_value_t;
|
using _value_type = sqlpp::no_value_t;
|
||||||
struct _alias_t
|
struct _alias_t
|
||||||
|
@ -615,691 +546,6 @@ struct TableWalletsTx : sqlpp::table_t<TableWalletsTx,TableWalletsTx_::TxId,Tabl
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace TableWalletsBtcRawTx_
|
|
||||||
{
|
|
||||||
struct RawTxId
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "raw_tx_id";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WalletId
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "wallet_id";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T wallet_id;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return wallet_id;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return wallet_id;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TableWalletsBtcRawTx : sqlpp::table_t<TableWalletsBtcRawTx,TableWalletsBtcRawTx_::RawTxId,TableWalletsBtcRawTx_::WalletId>
|
|
||||||
{
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WalletId
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "wallet_id";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T wallet_id;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return wallet_id;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return wallet_id;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TableWalletsEthRawTx : sqlpp::table_t<TableWalletsEthRawTx,TableWalletsEthRawTx_::RawTxId,TableWalletsEthRawTx_::WalletId>
|
|
||||||
{
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BlockchainId
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "blockchain_id";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T blockchain_id;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return blockchain_id;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return blockchain_id;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Hash
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "hash";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T hash;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::varchar>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UnixTime
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "unix_time";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T unix_time;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return unix_time;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return unix_time;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TableBlockchainBtcRawTx : sqlpp::table_t<TableBlockchainBtcRawTx,TableBlockchainBtcRawTx_::RawTxId,TableBlockchainBtcRawTx_::BlockchainId,TableBlockchainBtcRawTx_::Hash,TableBlockchainBtcRawTx_::UnixTime>
|
|
||||||
{
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RawTxId
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "raw_tx_id";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Amount
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "amount";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T amount;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::decimal>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Address
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "address";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T address;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::varchar>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TableBlockchainBtcRawTxDetails : sqlpp::table_t<TableBlockchainBtcRawTxDetails,TableBlockchainBtcRawTxDetails_::RawTxDetailId,TableBlockchainBtcRawTxDetails_::RawTxId,TableBlockchainBtcRawTxDetails_::Amount,TableBlockchainBtcRawTxDetails_::Address>
|
|
||||||
{
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BlockchainId
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "blockchain_id";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T blockchain_id;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return blockchain_id;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return blockchain_id;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Hash
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "hash";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T hash;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::varchar>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UnixTime
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "unix_time";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T unix_time;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return unix_time;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return unix_time;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Fee
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "fee";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T fee;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return fee;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return fee;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::decimal>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TableBlockchainEthRawTx : sqlpp::table_t<TableBlockchainEthRawTx,TableBlockchainEthRawTx_::RawTxId,TableBlockchainEthRawTx_::BlockchainId,TableBlockchainEthRawTx_::Hash,TableBlockchainEthRawTx_::UnixTime,TableBlockchainEthRawTx_::Fee>
|
|
||||||
{
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RawTxId
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "raw_tx_id";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AddressFrom
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "address_from";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T address_from;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return address_from;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return address_from;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::varchar>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AddressTo
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "address_to";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T address_to;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return address_to;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return address_to;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::varchar>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AmountCoinId
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "amount_coin_id";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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<sqlpp::bigint>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Amount
|
|
||||||
{
|
|
||||||
struct _alias_t
|
|
||||||
{
|
|
||||||
static constexpr const char _literal[] = "amount";
|
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
struct _member_t
|
|
||||||
{
|
|
||||||
T amount;
|
|
||||||
T& operator()()
|
|
||||||
{
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
const T& operator()() const
|
|
||||||
{
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
using _traits = sqlpp::make_traits<sqlpp::decimal>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TableBlockchainEthRawTxDetails : sqlpp::table_t<TableBlockchainEthRawTxDetails,TableBlockchainEthRawTxDetails_::RawTxDetailId,TableBlockchainEthRawTxDetails_::RawTxId,TableBlockchainEthRawTxDetails_::AddressFrom,TableBlockchainEthRawTxDetails_::AddressTo,TableBlockchainEthRawTxDetails_::AmountCoinId,TableBlockchainEthRawTxDetails_::Amount>
|
|
||||||
{
|
|
||||||
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<sizeof(_literal), _literal>;
|
|
||||||
template <typename T>
|
|
||||||
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_
|
namespace TableExchangesLedgers_
|
||||||
{
|
{
|
||||||
struct LedgerId
|
struct LedgerId
|
||||||
|
@ -1417,23 +663,23 @@ namespace TableExchangesLedgers_
|
||||||
using _traits = sqlpp::make_traits<sqlpp::varchar>;
|
using _traits = sqlpp::make_traits<sqlpp::varchar>;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UnixTime
|
struct Timestamp
|
||||||
{
|
{
|
||||||
struct _alias_t
|
struct _alias_t
|
||||||
{
|
{
|
||||||
static constexpr const char _literal[] = "unix_time";
|
static constexpr const char _literal[] = "timestamp";
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct _member_t
|
struct _member_t
|
||||||
{
|
{
|
||||||
T unix_time;
|
T timestamp;
|
||||||
T& operator()()
|
T& operator()()
|
||||||
{
|
{
|
||||||
return unix_time;
|
return timestamp;
|
||||||
}
|
}
|
||||||
const T& operator()() const
|
const T& operator()() const
|
||||||
{
|
{
|
||||||
return unix_time;
|
return timestamp;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1510,7 +756,7 @@ namespace TableExchangesLedgers_
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TableExchangesLedgers : sqlpp::table_t<TableExchangesLedgers,TableExchangesLedgers_::LedgerId,TableExchangesLedgers_::AccountId,TableExchangesLedgers_::ExchangeLedgerId,TableExchangesLedgers_::ExchangeReferenceId,TableExchangesLedgers_::UnixTime,TableExchangesLedgers_::OperationType,TableExchangesLedgers_::CoinId,TableExchangesLedgers_::Amount,TableExchangesLedgers_::Fee>
|
struct TableExchangesLedgers : sqlpp::table_t<TableExchangesLedgers,TableExchangesLedgers_::LedgerId,TableExchangesLedgers_::AccountId,TableExchangesLedgers_::ExchangeLedgerId,TableExchangesLedgers_::ExchangeReferenceId,TableExchangesLedgers_::Timestamp,TableExchangesLedgers_::OperationType,TableExchangesLedgers_::CoinId,TableExchangesLedgers_::Amount,TableExchangesLedgers_::Fee>
|
||||||
{
|
{
|
||||||
using _value_type = sqlpp::no_value_t;
|
using _value_type = sqlpp::no_value_t;
|
||||||
struct _alias_t
|
struct _alias_t
|
||||||
|
@ -1673,23 +919,23 @@ namespace TableExchangesTrades_
|
||||||
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
using _traits = sqlpp::make_traits<sqlpp::bigint>;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UnixTime
|
struct Timestamp
|
||||||
{
|
{
|
||||||
struct _alias_t
|
struct _alias_t
|
||||||
{
|
{
|
||||||
static constexpr const char _literal[] = "unix_time";
|
static constexpr const char _literal[] = "timestamp";
|
||||||
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
using _name_t = sqlpp::make_char_sequence<sizeof(_literal), _literal>;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct _member_t
|
struct _member_t
|
||||||
{
|
{
|
||||||
T unix_time;
|
T timestamp;
|
||||||
T& operator()()
|
T& operator()()
|
||||||
{
|
{
|
||||||
return unix_time;
|
return timestamp;
|
||||||
}
|
}
|
||||||
const T& operator()() const
|
const T& operator()() const
|
||||||
{
|
{
|
||||||
return unix_time;
|
return timestamp;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1858,7 +1104,7 @@ namespace TableExchangesTrades_
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TableExchangesTrades : sqlpp::table_t<TableExchangesTrades,TableExchangesTrades_::TradeId,TableExchangesTrades_::AccountId,TableExchangesTrades_::ExchangeTradeId,TableExchangesTrades_::ExchangeOrderId,TableExchangesTrades_::BaseCoinId,TableExchangesTrades_::QuoteCoinId,TableExchangesTrades_::UnixTime,TableExchangesTrades_::Type,TableExchangesTrades_::OrderType,TableExchangesTrades_::Price,TableExchangesTrades_::Cost,TableExchangesTrades_::Fee,TableExchangesTrades_::Volume,TableExchangesTrades_::FeeCoinId>
|
struct TableExchangesTrades : sqlpp::table_t<TableExchangesTrades,TableExchangesTrades_::TradeId,TableExchangesTrades_::AccountId,TableExchangesTrades_::ExchangeTradeId,TableExchangesTrades_::ExchangeOrderId,TableExchangesTrades_::BaseCoinId,TableExchangesTrades_::QuoteCoinId,TableExchangesTrades_::Timestamp,TableExchangesTrades_::Type,TableExchangesTrades_::OrderType,TableExchangesTrades_::Price,TableExchangesTrades_::Cost,TableExchangesTrades_::Fee,TableExchangesTrades_::Volume,TableExchangesTrades_::FeeCoinId>
|
||||||
{
|
{
|
||||||
using _value_type = sqlpp::no_value_t;
|
using _value_type = sqlpp::no_value_t;
|
||||||
struct _alias_t
|
struct _alias_t
|
||||||
|
|
|
@ -19,32 +19,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "wallet.h"
|
#include "wallet.h"
|
||||||
#include "wallets/wallet_btc.h"
|
#include "wallets/btc.h"
|
||||||
#include "wallets/wallet_bch.h"
|
#include "wallets/bch.h"
|
||||||
#include "wallets/wallet_eth.h"
|
#include "wallets/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)
|
WalletsManager::WalletsManager(int userId)
|
||||||
{
|
{
|
||||||
|
@ -61,34 +38,38 @@ void WalletsManager::analyzeUserWallets()
|
||||||
mysql::connection db(getMysqlConfig());
|
mysql::connection db(getMysqlConfig());
|
||||||
const auto wallets = TableWallets{};
|
const auto wallets = TableWallets{};
|
||||||
|
|
||||||
list<Wallet*> userWallets;
|
// Identify coins, we need one analyzer object per coin.
|
||||||
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)))
|
list<WalletHandler*> handlers;
|
||||||
|
for (const auto& row: db.run(select(wallets.type_id).from(wallets).where(wallets.user_id == m_userId).group_by(wallets.type_id)))
|
||||||
{
|
{
|
||||||
Wallet* wallet;
|
int typeId = row.type_id;
|
||||||
switch (row.type_id)
|
WalletHandler* walletHandler;
|
||||||
|
switch (typeId)
|
||||||
{
|
{
|
||||||
case CPFM_WALLET_TYPE_ID_BTC:
|
case CPFM_WALLET_TYPE_ID_BTC:
|
||||||
wallet = new WalletBTC(row.wallet_id);
|
walletHandler = new WalletHandlerBTC(m_userId);
|
||||||
userWallets.push_back(wallet);
|
handlers.push_back(walletHandler);
|
||||||
break;
|
break;
|
||||||
case CPFM_WALLET_TYPE_ID_BCH:
|
case CPFM_WALLET_TYPE_ID_BCH:
|
||||||
wallet = new WalletBCH(row.wallet_id);
|
walletHandler = new WalletHandlerBCH(m_userId);
|
||||||
userWallets.push_back(wallet);
|
handlers.push_back(walletHandler);
|
||||||
break;
|
break;
|
||||||
case CPFM_WALLET_TYPE_ID_ETH:
|
case CPFM_WALLET_TYPE_ID_ETH:
|
||||||
wallet = new WalletETH(row.wallet_id);
|
walletHandler = new WalletHandlerETH(m_userId);
|
||||||
userWallets.push_back(wallet);
|
handlers.push_back(walletHandler);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
lerr << "Unsupported wallet type: " << row.type_id;
|
lerr << "Unsupported wallet type: " << typeId;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& wallet: userWallets)
|
emptyWalletsTx();
|
||||||
|
|
||||||
|
for (auto const& handler: handlers)
|
||||||
{
|
{
|
||||||
wallet->update();
|
handler->analyzeUserWallets();
|
||||||
delete wallet;
|
delete handler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,16 +85,20 @@ void WalletsManager::emptyWalletsTx()
|
||||||
userWallets.push_back(row.wallet_id);
|
userWallets.push_back(row.wallet_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& idWallet: userWallets)
|
for (const auto& id: userWallets)
|
||||||
{
|
{
|
||||||
list<int> userWalletTx;
|
db.run(remove_from(wallets_tx).where(wallets_tx.wallet_id == id));
|
||||||
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;
|
linfo << "Emptied Wallets Tx DB table for user " << m_userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WalletHandler::WalletHandler(int userId)
|
||||||
|
{
|
||||||
|
m_userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
WalletHandler::~WalletHandler()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
20
src/wallet.h
20
src/wallet.h
|
@ -27,17 +27,6 @@
|
||||||
#define CPFM_WALLET_TYPE_ID_ETH 2
|
#define CPFM_WALLET_TYPE_ID_ETH 2
|
||||||
#define CPFM_WALLET_TYPE_ID_BCH 3
|
#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
|
class WalletsManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -52,15 +41,16 @@ private:
|
||||||
int m_userId;
|
int m_userId;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Wallet
|
class WalletHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Wallet (int walletId) { m_walletId = walletId; }
|
WalletHandler(int userId);
|
||||||
|
virtual ~WalletHandler();
|
||||||
|
|
||||||
virtual void update() = 0;
|
virtual void analyzeUserWallets() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int m_walletId;
|
int m_userId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CPFM_WALLET_H_INCLUDED
|
#endif // CPFM_WALLET_H_INCLUDED
|
316
src/wallets/bch.cpp
Normal file
316
src/wallets/bch.cpp
Normal file
|
@ -0,0 +1,316 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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<int, list<string>> userWallets;
|
||||||
|
list<string> 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<string> 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<string> walletAddresses, list<string> 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<json::value> 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<string> inputAddrList;
|
||||||
|
list<string> 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));
|
||||||
|
}
|
||||||
|
}
|
63
src/wallets/bch.h
Normal file
63
src/wallets/bch.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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<string> walletAddresses, list<string> userAddresses);
|
||||||
|
void analyzeUserWalletData(int walletId);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddressHandlerBCH
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddressHandlerBCH(string address, int walletId);
|
||||||
|
virtual ~AddressHandlerBCH();
|
||||||
|
|
||||||
|
void getAddressData();
|
||||||
|
void addAddressDataToDB();
|
||||||
|
void setWalletAddresses(list<string> walletAddresses) { m_walletAddresses = walletAddresses; }
|
||||||
|
void setUserAddresses(list<string> userAddresses) { m_userAddresses = userAddresses; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void getBlockchainAddressData();
|
||||||
|
void addCachedAddressDataToDB();
|
||||||
|
void addAddressDataJSONToDB(json::value jvalue);
|
||||||
|
string getCacheFilename();
|
||||||
|
|
||||||
|
string m_address;
|
||||||
|
int m_walletId;
|
||||||
|
list<string> m_userAddresses;
|
||||||
|
list<string> m_walletAddresses;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CPFM_WALLET_BTC_H_INCLUDED
|
332
src/wallets/btc.cpp
Normal file
332
src/wallets/btc.cpp
Normal file
|
@ -0,0 +1,332 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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<int,list<string>> userWallets;
|
||||||
|
list<string> 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<string> 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<string> walletAddresses, list<string> 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<json::value> 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<jvalue["txs"].size();i++)
|
||||||
|
{
|
||||||
|
string hash = jvalue["txs"][i]["hash"].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<string> inputAddrList;
|
||||||
|
list<string> outputAddrList;
|
||||||
|
|
||||||
|
for (int j=0;j<jvalue["txs"][i]["inputs"].size();j++)
|
||||||
|
{
|
||||||
|
string inputAddr = jvalue["txs"][i]["inputs"][j]["prev_out"]["addr"].as_string();
|
||||||
|
__int64 amount = jvalue["txs"][i]["inputs"][j]["prev_out"]["value"].as_integer();
|
||||||
|
txTotalInputAmount += amount;
|
||||||
|
|
||||||
|
if (inputAddr == myAddr)
|
||||||
|
{
|
||||||
|
bFromMyAddr = true;
|
||||||
|
txMyInputAmount += amount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inputAddrList.push_back(inputAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j=0;j<jvalue["txs"][i]["out"].size();j++)
|
||||||
|
{
|
||||||
|
string outputAddr = jvalue["txs"][i]["out"][j]["addr"].as_string();
|
||||||
|
__int64 amount = jvalue["txs"][i]["out"][j]["value"].as_integer();
|
||||||
|
txTotalOutputAmount += amount;
|
||||||
|
|
||||||
|
if (outputAddr == myAddr)
|
||||||
|
{
|
||||||
|
bToMyAddr = true;
|
||||||
|
txMyOutputAmount += amount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outputAddrList.push_back(outputAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Money amount;
|
||||||
|
Money fee;
|
||||||
|
if (bFromMyAddr)
|
||||||
|
{
|
||||||
|
amount = -txMyInputAmount/100000000;
|
||||||
|
fee = txTotalInputAmount/100000000 - txTotalOutputAmount/100000000;
|
||||||
|
|
||||||
|
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/100000000;
|
||||||
|
fee = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
db(insert_into(wallets_tx).set(
|
||||||
|
wallets_tx.wallet_id = m_walletId,
|
||||||
|
wallets_tx.blockchain_tx_id = hash,
|
||||||
|
wallets_tx.amount = amount.toBoostMpf(),
|
||||||
|
wallets_tx.fee = fee.toBoostMpf(),
|
||||||
|
wallets_tx.timestamp = timestamp
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
63
src/wallets/btc.h
Normal file
63
src/wallets/btc.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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<string> walletAddresses, list<string> userAddresses);
|
||||||
|
void analyzeUserWalletData(int walletId);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddressHandlerBTC
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddressHandlerBTC(string address, int walletId);
|
||||||
|
virtual ~AddressHandlerBTC();
|
||||||
|
|
||||||
|
void getAddressData();
|
||||||
|
void addAddressDataToDB();
|
||||||
|
void setWalletAddresses(list<string> walletAddresses) { m_walletAddresses = walletAddresses; }
|
||||||
|
void setUserAddresses(list<string> userAddresses) { m_userAddresses = userAddresses; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void getBlockchainAddressData();
|
||||||
|
void addCachedAddressDataToDB();
|
||||||
|
void addAddressDataJSONToDB(json::value jvalue);
|
||||||
|
string getCacheFilename();
|
||||||
|
|
||||||
|
string m_address;
|
||||||
|
int m_walletId;
|
||||||
|
list<string> m_userAddresses;
|
||||||
|
list<string> m_walletAddresses;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CPFM_WALLET_BTC_H_INCLUDED
|
353
src/wallets/eth.cpp
Normal file
353
src/wallets/eth.cpp
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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<int,list<string>> userWallets;
|
||||||
|
list<string> 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<string> 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<string> walletAddresses, list<string> 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<json::value> 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<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<string> inputAddrList;
|
||||||
|
list<string> 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.tx_hash = txid,
|
||||||
|
wallets_tx.amount = amount.toBoostMpf(),
|
||||||
|
wallets_tx.fee = fee.toBoostMpf(),
|
||||||
|
wallets_tx.timestamp = timestamp
|
||||||
|
));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
63
src/wallets/eth.h
Normal file
63
src/wallets/eth.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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<string> walletAddresses, list<string> userAddresses);
|
||||||
|
void analyzeUserWalletData(int walletId);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddressHandlerETH
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddressHandlerETH(string address, int walletId);
|
||||||
|
virtual ~AddressHandlerETH();
|
||||||
|
|
||||||
|
void getAddressData();
|
||||||
|
void addAddressDataToDB();
|
||||||
|
void setWalletAddresses(list<string> walletAddresses) { m_walletAddresses = walletAddresses; }
|
||||||
|
void setUserAddresses(list<string> userAddresses) { m_userAddresses = userAddresses; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void getBlockchainAddressData();
|
||||||
|
void addCachedAddressDataToDB();
|
||||||
|
void addAddressDataJSONToDB(json::value jvalue);
|
||||||
|
string getCacheFilename();
|
||||||
|
|
||||||
|
string m_address;
|
||||||
|
int m_walletId;
|
||||||
|
list<string> m_userAddresses;
|
||||||
|
list<string> m_walletAddresses;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CPFM_WALLET_ETH_H_INCLUDED
|
|
@ -1,27 +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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "wallets/wallet_bch.h"
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeBTC> WalletBCH::getTxDetailsListForAddresses(list<string> addresses)
|
|
||||||
{
|
|
||||||
BlockchainDataSourceBCH src;
|
|
||||||
return src.getTxDetailsListForAddresses(addresses);
|
|
||||||
}
|
|
|
@ -1,36 +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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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<BlockchainTxDetailsTypeBTC> getTxDetailsListForAddresses(list<string> addresses);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CPFM_WALLET_BCH_H_INCLUDED
|
|
|
@ -1,27 +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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "wallets/wallet_btc.h"
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeBTC> WalletBTC::getTxDetailsListForAddresses(list<string> addresses)
|
|
||||||
{
|
|
||||||
BlockchainDataSourceBTC src;
|
|
||||||
return src.getTxDetailsListForAddresses(addresses);
|
|
||||||
}
|
|
|
@ -1,36 +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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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<BlockchainTxDetailsTypeBTC> getTxDetailsListForAddresses(list<string> addresses);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CPFM_WALLET_BTC_H_INCLUDED
|
|
|
@ -1,27 +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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "wallets/wallet_eth.h"
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeETH> WalletETH::getTxDetailsListForAddress(string address)
|
|
||||||
{
|
|
||||||
BlockchainDataSourceETH src;
|
|
||||||
return src.getTxDetailsListForAddress(address);
|
|
||||||
}
|
|
|
@ -1,36 +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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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<BlockchainTxDetailsTypeETH> getTxDetailsListForAddress(string address);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CPFM_WALLET_ETH_H_INCLUDED
|
|
|
@ -1,324 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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<string> 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<BlockchainTxDetailsTypeBTC> 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<BlockchainTxDetailsTypeBTC>& 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<BlockchainTxDetailsTypeBTC> 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<BlockchainTxDetailsTypeBTC> 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<string> walletAddresses, const list<BlockchainTxDetailsTypeBTC>& 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<string> inputAddresses;
|
|
||||||
list<string> 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()
|
|
||||||
));
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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<BlockchainTxDetailsTypeBTC>& l);
|
|
||||||
void addTxDetailsListToDB(const int walletId, const list<string> walletAddresses, const list<BlockchainTxDetailsTypeBTC>& l);
|
|
||||||
list<BlockchainTxDetailsTypeBTC> getTxDetailsListFromRawDB(const int walletId);
|
|
||||||
void updateBalanceFromTxDetailsInDB(int walletId);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual list<BlockchainTxDetailsTypeBTC> getTxDetailsListForAddresses(list<string> addresses) = 0;
|
|
||||||
|
|
||||||
int m_coinId;
|
|
||||||
int m_walletTypeId;
|
|
||||||
int m_blockchainId;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CPFM_WALLET_TYPE_BTC_H_INCLUDED
|
|
|
@ -1,248 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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<BlockchainTxDetailsTypeETH> 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<BlockchainTxDetailsTypeETH>& 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<BlockchainTxDetailsTypeETH> WalletTypeETH::getTxDetailsListFromRawDB(const int walletId)
|
|
||||||
{
|
|
||||||
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 << "Retrieving data from raw DB for " << getBlockchainName(m_blockchainId) << " wallet " << walletId << ".";
|
|
||||||
|
|
||||||
list<BlockchainTxDetailsTypeETH> l;
|
|
||||||
for (const auto& rowTx: db.run(select(blockchain_eth_raw_tx.raw_tx_id,blockchain_eth_raw_tx.hash,blockchain_eth_raw_tx.unix_time,blockchain_eth_raw_tx.fee).from(blockchain_eth_raw_tx.cross_join(wallets_eth_raw_tx)).where(blockchain_eth_raw_tx.raw_tx_id == wallets_eth_raw_tx.raw_tx_id and wallets_eth_raw_tx.wallet_id == walletId)))
|
|
||||||
{
|
|
||||||
ldebug << "Retrieving data from raw DB for tx " << rowTx.hash << ".";
|
|
||||||
|
|
||||||
BlockchainTxDetailsTypeETH tx;
|
|
||||||
|
|
||||||
tx.hash = rowTx.hash;
|
|
||||||
tx.time.setFromUnixTime(rowTx.unix_time);
|
|
||||||
tx.fee = rowTx.fee;
|
|
||||||
|
|
||||||
ldebug << "Retrieving operations data from raw DB for tx " << rowTx.hash << ".";
|
|
||||||
|
|
||||||
for (const auto& rowOp: db.run(select(blockchain_eth_raw_tx_details.amount,blockchain_eth_raw_tx_details.amount_coin_id,blockchain_eth_raw_tx_details.address_from,blockchain_eth_raw_tx_details.address_to).from(blockchain_eth_raw_tx_details).where(blockchain_eth_raw_tx_details.raw_tx_id == rowTx.raw_tx_id)))
|
|
||||||
{
|
|
||||||
BlockchainTxOperationTypeETH op;
|
|
||||||
op.addressFrom = rowOp.address_from;
|
|
||||||
op.addressTo = rowOp.address_to;
|
|
||||||
op.amount = rowOp.amount;
|
|
||||||
op.amountCoinId = rowOp.amount_coin_id;
|
|
||||||
|
|
||||||
tx.operations.push_back(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
l.push_back(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WalletTypeETH::addTxDetailsListToDB(const int walletId, string address, const list<BlockchainTxDetailsTypeETH>& l)
|
|
||||||
{
|
|
||||||
mysql::connection db(getMysqlConfig());
|
|
||||||
const auto wallets_tx = TableWalletsTx{};
|
|
||||||
|
|
||||||
linfo << "Now adding data to DB for " << getBlockchainName(m_blockchainId) << " wallet " << walletId << ".";
|
|
||||||
|
|
||||||
for (const auto& tx: l)
|
|
||||||
{
|
|
||||||
ltrace << "Now adding data to DB for tx " << tx.hash << ".";
|
|
||||||
|
|
||||||
bool bFeeAdded = false;
|
|
||||||
|
|
||||||
for (const auto& op: tx.operations)
|
|
||||||
{
|
|
||||||
Money amount;
|
|
||||||
Money fee;
|
|
||||||
|
|
||||||
if (address == op.addressFrom)
|
|
||||||
{
|
|
||||||
// Even if we have multiple operations for the same tx, the fee only applies once.
|
|
||||||
if (!bFeeAdded)
|
|
||||||
{
|
|
||||||
// The fee only applies in case this tx was initiated by the wallet
|
|
||||||
fee = tx.fee;
|
|
||||||
}
|
|
||||||
|
|
||||||
amount = 0-op.amount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
amount = op.amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = op.amountCoinId,
|
|
||||||
wallets_tx.fee_coin_id = m_coinId,
|
|
||||||
wallets_tx.operation_type = CPFM_WALLET_OPERATION_UNKNOWN
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WalletTypeETH::updateBalanceFromTxDetailsInDB(int walletId)
|
|
||||||
{
|
|
||||||
mysql::connection db(getMysqlConfig());
|
|
||||||
const auto wallets_tx = TableWalletsTx{};
|
|
||||||
const auto wallets_balances = TableWalletsBalances{};
|
|
||||||
|
|
||||||
ldebug << "------------------------------------------------------------";
|
|
||||||
|
|
||||||
map<int,Money> walletBalances;
|
|
||||||
|
|
||||||
for (const auto& row: db.run(select(wallets_tx.amount, wallets_tx.amount_coin_id, 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);
|
|
||||||
|
|
||||||
walletBalances[row.amount_coin_id] += txAmount;
|
|
||||||
walletBalances[m_coinId] -= txFee;
|
|
||||||
|
|
||||||
string sReason = "?";
|
|
||||||
|
|
||||||
ltrace << "Tx Amount: " << txAmount
|
|
||||||
<< ", Coin: " << getCoinName(row.amount_coin_id)
|
|
||||||
<< ". Reason: " << sReason
|
|
||||||
<< ". Tx Fees: " << txFee;
|
|
||||||
}
|
|
||||||
|
|
||||||
db(remove_from(wallets_balances).where(wallets_balances.wallet_id == walletId));
|
|
||||||
|
|
||||||
for (const auto b: walletBalances)
|
|
||||||
{
|
|
||||||
linfo << "Wallet " << walletId << " " << getCoinName(b.first) << " balance is: " << b.second;
|
|
||||||
|
|
||||||
Money m = b.second;
|
|
||||||
db(insert_into(wallets_balances).set(
|
|
||||||
wallets_balances.wallet_id = walletId,
|
|
||||||
wallets_balances.coin_id = b.first,
|
|
||||||
wallets_balances.balance = m.toBoostMpf()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CPFM_WALLET_TYPE_ETH_H_INCLUDED
|
|
||||||
#define CPFM_WALLET_TYPE_ETH_H_INCLUDED
|
|
||||||
|
|
||||||
#include "wallet.h"
|
|
||||||
#include "datasources/datasource.h"
|
|
||||||
|
|
||||||
class WalletTypeETH : public Wallet
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WalletTypeETH(int walletId):Wallet(walletId) {}
|
|
||||||
|
|
||||||
virtual void update();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void addTxDetailsListToRawDB(const int walletId, const list<BlockchainTxDetailsTypeETH>& l);
|
|
||||||
void addTxDetailsListToDB(const int walletId, string address, const list<BlockchainTxDetailsTypeETH>& l);
|
|
||||||
list<BlockchainTxDetailsTypeETH> getTxDetailsListFromRawDB(const int walletId);
|
|
||||||
void updateBalanceFromTxDetailsInDB(int walletId);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual list<BlockchainTxDetailsTypeETH> getTxDetailsListForAddress(string address) = 0;
|
|
||||||
|
|
||||||
int m_walletTypeId;
|
|
||||||
int m_blockchainId;
|
|
||||||
int m_coinId;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CPFM_WALLET_TYPE_ETH_H_INCLUDED
|
|
Loading…
Reference in New Issue
Block a user