2022-10-14 10:38:41 +00:00
|
|
|
#include <StatusGo/SignalsManager.h>
|
|
|
|
|
2022-07-07 18:16:59 +00:00
|
|
|
#include <StatusGo/Accounts/AccountsAPI.h>
|
2022-07-26 11:49:03 +00:00
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
#include <StatusGo/Wallet/Transfer/Event.h>
|
2022-07-07 18:16:59 +00:00
|
|
|
#include <StatusGo/Wallet/WalletApi.h>
|
2022-10-14 10:38:41 +00:00
|
|
|
#include <StatusGo/Wallet/wallet_types.h>
|
2022-07-26 11:49:03 +00:00
|
|
|
|
2022-07-07 18:16:59 +00:00
|
|
|
#include <StatusGo/Metadata/api_response.h>
|
|
|
|
|
2022-07-15 07:30:16 +00:00
|
|
|
#include <Onboarding/Accounts/AccountsService.h>
|
2022-10-14 10:38:41 +00:00
|
|
|
#include <Onboarding/Accounts/AccountsServiceInterface.h>
|
2022-07-07 18:16:59 +00:00
|
|
|
#include <Onboarding/Common/Constants.h>
|
|
|
|
#include <Onboarding/OnboardingController.h>
|
|
|
|
|
|
|
|
#include <ScopedTestAccount.h>
|
|
|
|
#include <StatusGo/Utils.h>
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
#include <chrono>
|
2022-07-07 18:16:59 +00:00
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
|
|
namespace Wallet = Status::StatusGo::Wallet;
|
2022-07-15 07:30:16 +00:00
|
|
|
namespace Accounts = Status::StatusGo::Accounts;
|
2022-07-07 18:16:59 +00:00
|
|
|
namespace Utils = Status::StatusGo::Utils;
|
2022-07-15 07:30:16 +00:00
|
|
|
namespace General = Status::Constants::General;
|
2022-07-07 18:16:59 +00:00
|
|
|
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
using namespace std::chrono_literals;
|
|
|
|
|
2022-07-07 18:16:59 +00:00
|
|
|
/// \warning for now this namespace contains integration test to check the basic assumptions of status-go while building the C++ wrapper.
|
|
|
|
/// \warning the tests depend on IO and are not deterministic, fast, focused or reliable. They are here for validation only
|
|
|
|
/// \todo after status-go API coverage all the integration tests should go away and only test the thin wrapper code
|
2022-10-14 10:38:41 +00:00
|
|
|
namespace Status::Testing
|
|
|
|
{
|
2022-07-07 18:16:59 +00:00
|
|
|
|
2022-07-15 07:30:16 +00:00
|
|
|
TEST(WalletApi, TestGetDerivedAddressesForPath_FromRootAccount)
|
2022-07-07 18:16:59 +00:00
|
|
|
{
|
|
|
|
constexpr auto testRootAccountName = "test_root_account-name";
|
2022-07-15 07:30:16 +00:00
|
|
|
ScopedTestAccount testAccount(test_info_->name(), testRootAccountName);
|
2022-07-07 18:16:59 +00:00
|
|
|
|
|
|
|
const auto walletAccount = testAccount.firstWalletAccount();
|
|
|
|
const auto rootAccount = testAccount.onboardingController()->accountsService()->getLoggedInAccount();
|
|
|
|
ASSERT_EQ(rootAccount.address, walletAccount.derivedFrom.value());
|
|
|
|
|
2022-07-15 07:30:16 +00:00
|
|
|
const auto testPath = General::PathWalletRoot;
|
2022-07-07 18:16:59 +00:00
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto derivedAddresses = Wallet::getDerivedAddressesForPath(
|
|
|
|
testAccount.hashedPassword(), walletAccount.derivedFrom.value(), testPath, 3, 1);
|
2022-07-15 07:30:16 +00:00
|
|
|
// Check that accounts are generated in memory and none is saved
|
2022-07-07 18:16:59 +00:00
|
|
|
const auto updatedAccounts = Accounts::getAccounts();
|
|
|
|
ASSERT_EQ(updatedAccounts.size(), 2);
|
|
|
|
|
2022-07-15 07:30:16 +00:00
|
|
|
ASSERT_EQ(derivedAddresses.size(), 3);
|
2022-10-14 10:38:41 +00:00
|
|
|
auto defaultWalletAccountIt =
|
|
|
|
std::find_if(derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) { return a.alreadyCreated; });
|
2022-07-15 07:30:16 +00:00
|
|
|
ASSERT_NE(defaultWalletAccountIt, derivedAddresses.end());
|
|
|
|
const auto& defaultWalletAccount = *defaultWalletAccountIt;
|
|
|
|
ASSERT_EQ(defaultWalletAccount.path, General::PathDefaultWallet);
|
|
|
|
ASSERT_EQ(defaultWalletAccount.address, walletAccount.address);
|
|
|
|
ASSERT_TRUE(defaultWalletAccount.alreadyCreated);
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_EQ(1, std::count_if(derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) {
|
|
|
|
return a.alreadyCreated;
|
|
|
|
}));
|
2022-07-07 18:16:59 +00:00
|
|
|
// all hasActivity are false
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_TRUE(
|
|
|
|
std::none_of(derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) { return a.hasActivity; }));
|
2022-07-07 18:16:59 +00:00
|
|
|
// all address are valid
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_TRUE(std::none_of(
|
|
|
|
derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) { return a.address.get().isEmpty(); }));
|
2022-07-15 07:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Accounts, TestGetDerivedAddressesForPath_AfterLogin)
|
|
|
|
{
|
|
|
|
constexpr auto testRootAccountName = "test-generate_account_with_derived_path-name";
|
|
|
|
ScopedTestAccount testAccount(test_info_->name(), testRootAccountName);
|
|
|
|
|
|
|
|
testAccount.logOut();
|
|
|
|
|
|
|
|
auto accountsService = std::make_shared<Onboarding::AccountsService>();
|
2022-10-14 10:38:41 +00:00
|
|
|
auto result = accountsService->init(testAccount.testDataDir());
|
2022-07-15 07:30:16 +00:00
|
|
|
ASSERT_TRUE(result);
|
|
|
|
auto onboarding = std::make_shared<Onboarding::OnboardingController>(accountsService);
|
|
|
|
EXPECT_EQ(onboarding->getOpenedAccounts().size(), 1);
|
|
|
|
|
|
|
|
auto accounts = accountsService->openAndListAccounts();
|
|
|
|
ASSERT_GT(accounts.size(), 0);
|
|
|
|
|
|
|
|
int accountLoggedInCount = 0;
|
|
|
|
QObject::connect(onboarding.get(), &Onboarding::OnboardingController::accountLoggedIn, [&accountLoggedInCount]() {
|
|
|
|
accountLoggedInCount++;
|
|
|
|
});
|
|
|
|
bool accountLoggedInError = false;
|
2022-10-14 10:38:41 +00:00
|
|
|
QObject::connect(onboarding.get(),
|
|
|
|
&Onboarding::OnboardingController::accountLoginError,
|
|
|
|
[&accountLoggedInError](const QString& error) {
|
|
|
|
accountLoggedInError = true;
|
|
|
|
qDebug() << "Failed logging in in test" << test_info_->name() << "with error:" << error;
|
|
|
|
});
|
|
|
|
|
|
|
|
auto ourAccountRes = std::find_if(accounts.begin(), accounts.end(), [testRootAccountName](const auto& a) {
|
|
|
|
return a.name == testRootAccountName;
|
2022-07-15 07:30:16 +00:00
|
|
|
});
|
|
|
|
auto errorString = accountsService->login(*ourAccountRes, testAccount.password());
|
|
|
|
ASSERT_EQ(errorString.length(), 0);
|
2022-07-07 18:16:59 +00:00
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
testAccount.processMessages(1000, [&accountLoggedInCount, &accountLoggedInError]() {
|
2022-07-15 07:30:16 +00:00
|
|
|
return accountLoggedInCount == 0 && !accountLoggedInError;
|
|
|
|
});
|
|
|
|
ASSERT_EQ(accountLoggedInCount, 1);
|
|
|
|
ASSERT_EQ(accountLoggedInError, 0);
|
|
|
|
|
|
|
|
const auto testPath = General::PathWalletRoot;
|
|
|
|
|
|
|
|
const auto walletAccount = testAccount.firstWalletAccount();
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto derivedAddresses = Wallet::getDerivedAddressesForPath(
|
|
|
|
testAccount.hashedPassword(), walletAccount.derivedFrom.value(), testPath, 3, 1);
|
2022-07-15 07:30:16 +00:00
|
|
|
// Check that accounts are generated in memory and none is saved
|
|
|
|
const auto updatedAccounts = Accounts::getAccounts();
|
|
|
|
ASSERT_EQ(updatedAccounts.size(), 2);
|
|
|
|
|
|
|
|
ASSERT_EQ(derivedAddresses.size(), 3);
|
2022-10-14 10:38:41 +00:00
|
|
|
auto defaultWalletAccountIt =
|
|
|
|
std::find_if(derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) { return a.alreadyCreated; });
|
2022-07-15 07:30:16 +00:00
|
|
|
ASSERT_NE(defaultWalletAccountIt, derivedAddresses.end());
|
|
|
|
const auto& defaultWalletAccount = *defaultWalletAccountIt;
|
|
|
|
ASSERT_EQ(defaultWalletAccount.path, General::PathDefaultWallet);
|
|
|
|
ASSERT_EQ(defaultWalletAccount.address, walletAccount.address);
|
|
|
|
ASSERT_TRUE(defaultWalletAccount.alreadyCreated);
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_EQ(1, std::count_if(derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) {
|
|
|
|
return a.alreadyCreated;
|
|
|
|
}));
|
2022-07-15 07:30:16 +00:00
|
|
|
// all hasActivity are false
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_TRUE(
|
|
|
|
std::none_of(derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) { return a.hasActivity; }));
|
2022-07-15 07:30:16 +00:00
|
|
|
// all address are valid
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_TRUE(std::none_of(
|
|
|
|
derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) { return a.address.get().isEmpty(); }));
|
2022-07-15 07:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// getDerivedAddresses@api.go fron statys-go has a special case when requesting the 6 path will return only one account
|
|
|
|
TEST(WalletApi, TestGetDerivedAddressesForPath_FromWalletAccount_FirstLevel_SixPathSpecialCase)
|
|
|
|
{
|
|
|
|
constexpr auto testRootAccountName = "test_root_account-name";
|
|
|
|
ScopedTestAccount testAccount(test_info_->name(), testRootAccountName);
|
|
|
|
|
|
|
|
const auto walletAccount = testAccount.firstWalletAccount();
|
|
|
|
|
|
|
|
const auto testPath = General::PathDefaultWallet;
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto derivedAddresses =
|
|
|
|
Wallet::getDerivedAddressesForPath(testAccount.hashedPassword(), walletAccount.address, testPath, 4, 1);
|
2022-07-15 07:30:16 +00:00
|
|
|
ASSERT_EQ(derivedAddresses.size(), 1);
|
|
|
|
const auto& onlyAccount = derivedAddresses[0];
|
2022-07-07 18:16:59 +00:00
|
|
|
// all alreadyCreated are false
|
2022-07-15 07:30:16 +00:00
|
|
|
ASSERT_FALSE(onlyAccount.alreadyCreated);
|
|
|
|
ASSERT_EQ(onlyAccount.path, General::PathDefaultWallet);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(WalletApi, TestGetDerivedAddressesForPath_FromWalletAccount_SecondLevel)
|
|
|
|
{
|
|
|
|
constexpr auto testRootAccountName = "test_root_account-name";
|
|
|
|
ScopedTestAccount testAccount(test_info_->name(), testRootAccountName);
|
|
|
|
|
|
|
|
const auto walletAccount = testAccount.firstWalletAccount();
|
|
|
|
const auto firstLevelPath = General::PathDefaultWallet;
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto firstLevelAddresses =
|
|
|
|
Wallet::getDerivedAddressesForPath(testAccount.hashedPassword(), walletAccount.address, firstLevelPath, 4, 1);
|
2022-07-15 07:30:16 +00:00
|
|
|
|
|
|
|
const auto testPath = Accounts::DerivationPath{General::PathDefaultWallet.get() + u"/0"_qs};
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto derivedAddresses =
|
|
|
|
Wallet::getDerivedAddressesForPath(testAccount.hashedPassword(), walletAccount.address, testPath, 4, 1);
|
2022-07-15 07:30:16 +00:00
|
|
|
ASSERT_EQ(derivedAddresses.size(), 4);
|
|
|
|
|
|
|
|
// all alreadyCreated are false
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_TRUE(
|
|
|
|
std::none_of(derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) { return a.alreadyCreated; }));
|
2022-07-15 07:30:16 +00:00
|
|
|
// all hasActivity are false
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_TRUE(
|
|
|
|
std::none_of(derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) { return a.hasActivity; }));
|
2022-07-15 07:30:16 +00:00
|
|
|
// all address are valid
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_TRUE(std::none_of(
|
|
|
|
derivedAddresses.begin(), derivedAddresses.end(), [](const auto& a) { return a.address.get().isEmpty(); }));
|
|
|
|
ASSERT_TRUE(std::all_of(derivedAddresses.begin(), derivedAddresses.end(), [testPath](const auto& a) {
|
|
|
|
return a.path.get().startsWith(testPath.get());
|
|
|
|
}));
|
2022-07-07 18:16:59 +00:00
|
|
|
}
|
|
|
|
|
2022-07-21 18:04:11 +00:00
|
|
|
TEST(WalletApi, TestGetEthereumChains)
|
|
|
|
{
|
|
|
|
ScopedTestAccount testAccount(test_info_->name());
|
|
|
|
|
|
|
|
auto networks = Wallet::getEthereumChains(false);
|
|
|
|
ASSERT_GT(networks.size(), 0);
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& network = networks[0];
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_FALSE(network.chainName.isEmpty());
|
|
|
|
ASSERT_TRUE(network.rpcUrl.isValid());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(WalletApi, TestGetTokens)
|
|
|
|
{
|
|
|
|
ScopedTestAccount testAccount(test_info_->name());
|
|
|
|
|
|
|
|
auto networks = Wallet::getEthereumChains(false);
|
|
|
|
ASSERT_GT(networks.size(), 0);
|
2022-10-14 10:38:41 +00:00
|
|
|
auto mainNetIt =
|
2022-11-15 21:48:59 +00:00
|
|
|
std::find_if(networks.begin(), networks.end(), [](const auto& n) { return n.chainName == "Ethereum Mainnet"; });
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_NE(mainNetIt, networks.end());
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& mainNet = *mainNetIt;
|
2022-07-21 18:04:11 +00:00
|
|
|
|
|
|
|
auto tokens = Wallet::getTokens(mainNet.chainId);
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
auto sntIt = std::find_if(tokens.begin(), tokens.end(), [](const auto& t) { return t.symbol == "SNT"; });
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_NE(sntIt, tokens.end());
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& snt = *sntIt;
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_EQ(snt.chainId, mainNet.chainId);
|
|
|
|
ASSERT_TRUE(snt.color.isValid());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(WalletApi, TestGetTokensBalancesForChainIDs)
|
|
|
|
{
|
|
|
|
ScopedTestAccount testAccount(test_info_->name());
|
|
|
|
|
|
|
|
auto networks = Wallet::getEthereumChains(false);
|
|
|
|
ASSERT_GT(networks.size(), 1);
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
auto mainNetIt =
|
2022-11-15 21:48:59 +00:00
|
|
|
std::find_if(networks.begin(), networks.end(), [](const auto& n) { return n.chainName == "Ethereum Mainnet"; });
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_NE(mainNetIt, networks.end());
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& mainNet = *mainNetIt;
|
2022-07-21 18:04:11 +00:00
|
|
|
|
|
|
|
auto mainTokens = Wallet::getTokens(mainNet.chainId);
|
2022-10-14 10:38:41 +00:00
|
|
|
auto sntMainIt =
|
|
|
|
std::find_if(mainTokens.begin(), mainTokens.end(), [](const auto& t) { return t.symbol == "SNT"; });
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_NE(sntMainIt, mainTokens.end());
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& sntMain = *sntMainIt;
|
2022-07-21 18:04:11 +00:00
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
auto testNetIt =
|
|
|
|
std::find_if(networks.begin(), networks.end(), [](const auto& n) { return n.chainName == "Ropsten"; });
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_NE(testNetIt, networks.end());
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& testNet = *testNetIt;
|
2022-07-21 18:04:11 +00:00
|
|
|
|
|
|
|
auto testTokens = Wallet::getTokens(testNet.chainId);
|
2022-10-14 10:38:41 +00:00
|
|
|
auto sntTestIt =
|
|
|
|
std::find_if(testTokens.begin(), testTokens.end(), [](const auto& t) { return t.symbol == "STT"; });
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_NE(sntTestIt, testTokens.end());
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& sntTest = *sntTestIt;
|
2022-07-21 18:04:11 +00:00
|
|
|
|
|
|
|
auto testAddress = testAccount.firstWalletAccount().address;
|
2022-10-14 10:38:41 +00:00
|
|
|
auto balances = Wallet::getTokensBalancesForChainIDs(
|
|
|
|
{mainNet.chainId, testNet.chainId}, {testAddress}, {sntMain.address, sntTest.address});
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_GT(balances.size(), 0);
|
|
|
|
|
|
|
|
ASSERT_TRUE(balances.contains(testAddress));
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& addressBalance = balances[testAddress];
|
2022-07-26 11:49:03 +00:00
|
|
|
ASSERT_GT(addressBalance.size(), 0);
|
2022-07-21 18:04:11 +00:00
|
|
|
|
2022-07-26 11:49:03 +00:00
|
|
|
ASSERT_TRUE(addressBalance.contains(sntMain.address));
|
|
|
|
ASSERT_EQ(toQString(addressBalance.at(sntMain.address)), "0");
|
2022-07-21 18:04:11 +00:00
|
|
|
|
2022-07-26 11:49:03 +00:00
|
|
|
ASSERT_TRUE(addressBalance.contains(sntTest.address));
|
|
|
|
ASSERT_EQ(toQString(addressBalance.at(sntTest.address)), "0");
|
2022-07-21 18:04:11 +00:00
|
|
|
}
|
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
struct TestNetwork
|
|
|
|
{
|
|
|
|
QString name;
|
|
|
|
bool isTest;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TestParams
|
|
|
|
{
|
|
|
|
Accounts::EOAddress walletAddress;
|
|
|
|
std::vector<TestNetwork> networks;
|
|
|
|
QString token;
|
|
|
|
QString newTestAccountName;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const std::vector<TestParams> allTestParams{
|
|
|
|
// [0] - Goerli ERC20 token test account set
|
|
|
|
TestParams{Accounts::EOAddress("0x586e3bd2c40b0f243162ea563a1f43ae9ef25ef9"),
|
|
|
|
{{QString("Goerli"), true}},
|
|
|
|
QString("USDC"),
|
|
|
|
u"test_watch_only-name"_qs},
|
|
|
|
// [1] - Main net ERC20 token test account set
|
|
|
|
TestParams{Accounts::EOAddress("0xae0c364acb9b105766fea91cfa5aaea31a1821c1"),
|
|
|
|
{{QString("Ethereum Mainnet"), false}},
|
|
|
|
QString("SNT"),
|
|
|
|
u"test_watch_only-name"_qs},
|
|
|
|
// [2] - Main net native token account set
|
|
|
|
TestParams{Accounts::EOAddress("0x0182e671dfd5f7d21b13714cbe9f92d26b59eeb9"),
|
|
|
|
{{QString("Ethereum Mainnet"), false}},
|
|
|
|
QString("USDC"),
|
|
|
|
u"test_watch_only-name"_qs},
|
|
|
|
// [3] - Main net ERC20 test account set
|
|
|
|
TestParams{Accounts::EOAddress("0x473780deAF4a2Ac070BBbA936B0cdefe7F267dFc"),
|
|
|
|
{{QString("Ethereum Mainnet"), false}},
|
|
|
|
QString("ETH"),
|
|
|
|
u"test_watch_only-name"_qs},
|
|
|
|
// [4] - Arbitrum Goerli native token test account set
|
|
|
|
TestParams{Accounts::EOAddress("0xE2d622C817878dA5143bBE06866ca8E35273Ba8a"),
|
|
|
|
{{QString("Arbitrum Goerli"), true}, {QString("Goerli"), true}},
|
|
|
|
QString("ETH"),
|
|
|
|
u"test_watch_only-name"_qs},
|
|
|
|
};
|
|
|
|
|
|
|
|
TestParams getTestParams()
|
|
|
|
{
|
|
|
|
return allTestParams[4];
|
|
|
|
}
|
|
|
|
|
2022-07-21 18:04:11 +00:00
|
|
|
TEST(WalletApi, TestGetTokensBalancesForChainIDs_WatchOnlyAccount)
|
|
|
|
{
|
|
|
|
ScopedTestAccount testAccount(test_info_->name());
|
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
const auto params = getTestParams();
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
Accounts::addAccountWatch(Accounts::EOAddress("0xdb5ac1a559b02e12f29fc0ec0e37be8e046def49"),
|
2022-11-15 21:48:59 +00:00
|
|
|
params.newTestAccountName,
|
2022-10-14 10:38:41 +00:00
|
|
|
QColor("fuchsia"),
|
|
|
|
u""_qs);
|
2022-07-21 18:04:11 +00:00
|
|
|
const auto updatedAccounts = Accounts::getAccounts();
|
|
|
|
ASSERT_EQ(updatedAccounts.size(), 3);
|
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
const auto newAccountIt = std::find_if(updatedAccounts.begin(), updatedAccounts.end(), [¶ms](const auto& a) {
|
|
|
|
return a.name == params.newTestAccountName;
|
|
|
|
});
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_NE(newAccountIt, updatedAccounts.end());
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& newAccount = *newAccountIt;
|
2022-07-21 18:04:11 +00:00
|
|
|
|
|
|
|
auto networks = Wallet::getEthereumChains(false);
|
|
|
|
ASSERT_GT(networks.size(), 1);
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
auto mainNetIt =
|
2022-11-15 21:48:59 +00:00
|
|
|
std::find_if(networks.begin(), networks.end(), [](const auto& n) { return n.chainName == "Ethereum Mainnet"; });
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_NE(mainNetIt, networks.end());
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& mainNet = *mainNetIt;
|
2022-07-21 18:04:11 +00:00
|
|
|
|
|
|
|
auto mainTokens = Wallet::getTokens(mainNet.chainId);
|
2022-10-14 10:38:41 +00:00
|
|
|
auto sntMainIt =
|
|
|
|
std::find_if(mainTokens.begin(), mainTokens.end(), [](const auto& t) { return t.symbol == "SNT"; });
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_NE(sntMainIt, mainTokens.end());
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& sntMain = *sntMainIt;
|
2022-07-21 18:04:11 +00:00
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
auto balances = Wallet::getTokensBalancesForChainIDs({mainNet.chainId}, {newAccount.address}, {sntMain.address});
|
2022-07-21 18:04:11 +00:00
|
|
|
ASSERT_GT(balances.size(), 0);
|
|
|
|
|
|
|
|
ASSERT_TRUE(balances.contains(newAccount.address));
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto& addressBalance = balances[newAccount.address];
|
2022-07-26 11:49:03 +00:00
|
|
|
ASSERT_GT(addressBalance.size(), 0);
|
2022-07-21 18:04:11 +00:00
|
|
|
|
2022-07-26 11:49:03 +00:00
|
|
|
ASSERT_TRUE(addressBalance.contains(sntMain.address));
|
|
|
|
ASSERT_GT(addressBalance.at(sntMain.address), 0);
|
2022-07-21 18:04:11 +00:00
|
|
|
}
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
TEST(WalletApi, TestCheckRecentHistory)
|
|
|
|
{
|
|
|
|
ScopedTestAccount testAccount(test_info_->name());
|
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
const auto params = getTestParams();
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
// Add watch account
|
|
|
|
Accounts::addAccountWatch(Accounts::EOAddress("0xe74E17D586227691Cb7b64ed78b1b7B14828B034"),
|
2022-11-15 21:48:59 +00:00
|
|
|
params.newTestAccountName,
|
2022-10-14 10:38:41 +00:00
|
|
|
QColor("fuchsia"),
|
|
|
|
u""_qs);
|
|
|
|
const auto updatedAccounts = Accounts::getAccounts();
|
|
|
|
ASSERT_EQ(updatedAccounts.size(), 3);
|
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
const auto newAccountIt = std::find_if(updatedAccounts.begin(), updatedAccounts.end(), [¶ms](const auto& a) {
|
|
|
|
return a.name == params.newTestAccountName;
|
|
|
|
});
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_NE(newAccountIt, updatedAccounts.end());
|
|
|
|
const auto& newAccount = *newAccountIt;
|
|
|
|
|
|
|
|
bool startedTransferFetching = false;
|
|
|
|
bool historyReady = false;
|
|
|
|
QObject::connect(StatusGo::SignalsManager::instance(),
|
|
|
|
&StatusGo::SignalsManager::wallet,
|
|
|
|
testAccount.app(),
|
|
|
|
[&startedTransferFetching, &historyReady](QSharedPointer<StatusGo::EventData> data) {
|
|
|
|
Wallet::Transfer::Event event = data->eventInfo();
|
|
|
|
if(event.type == Wallet::Transfer::Events::FetchingRecentHistory)
|
|
|
|
startedTransferFetching = true;
|
|
|
|
else if(event.type == Wallet::Transfer::Events::RecentHistoryReady)
|
|
|
|
historyReady = true;
|
|
|
|
// Wallet::Transfer::Events::NewTransfers might not be emitted if there is no intermediate transfers
|
|
|
|
});
|
|
|
|
|
|
|
|
Wallet::checkRecentHistory({newAccount.address});
|
|
|
|
|
|
|
|
testAccount.processMessages(50000, [&historyReady]() { return !historyReady; });
|
|
|
|
|
|
|
|
ASSERT_TRUE(startedTransferFetching);
|
|
|
|
ASSERT_TRUE(historyReady);
|
|
|
|
}
|
|
|
|
|
2022-10-28 17:17:16 +00:00
|
|
|
TEST(WalletApi, TestGetBalanceHistory)
|
2022-10-14 10:38:41 +00:00
|
|
|
{
|
|
|
|
ScopedTestAccount testAccount(test_info_->name());
|
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
const auto params = getTestParams();
|
|
|
|
|
|
|
|
Accounts::addAccountWatch(params.walletAddress, params.newTestAccountName, QColor("fuchsia"), u""_qs);
|
2022-10-14 10:38:41 +00:00
|
|
|
const auto updatedAccounts = Accounts::getAccounts();
|
|
|
|
ASSERT_EQ(updatedAccounts.size(), 3);
|
|
|
|
|
2022-10-28 17:17:16 +00:00
|
|
|
auto networks = Wallet::getEthereumChains(false);
|
|
|
|
ASSERT_GT(networks.size(), 0);
|
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
std::vector<Wallet::ChainID> chainIDs;
|
|
|
|
for(const auto& net : params.networks)
|
|
|
|
{
|
|
|
|
auto netIt = std::find_if(networks.begin(), networks.end(), [&net](const auto& n) {
|
|
|
|
return n.chainName == net.name && n.isTest == net.isTest;
|
|
|
|
});
|
|
|
|
ASSERT_NE(netIt, networks.end());
|
|
|
|
chainIDs.push_back(netIt->chainId);
|
2022-10-28 17:17:16 +00:00
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
auto nativeIt = std::find_if(networks.begin(), networks.end(), [¶ms](const auto& n) {
|
|
|
|
return n.nativeCurrencySymbol == params.token;
|
2022-10-14 10:38:41 +00:00
|
|
|
});
|
2022-11-15 21:48:59 +00:00
|
|
|
if(nativeIt == networks.end())
|
|
|
|
{
|
|
|
|
auto tokens = Wallet::getTokens(netIt->chainId);
|
|
|
|
auto tokenIt = std::find_if(
|
|
|
|
tokens.begin(), tokens.end(), [¶ms](const auto& t) { return t.symbol == params.token; });
|
|
|
|
ASSERT_NE(tokenIt, tokens.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto newAccountIt = std::find_if(updatedAccounts.begin(), updatedAccounts.end(), [¶ms](const auto& a) {
|
|
|
|
return a.name == params.newTestAccountName;
|
|
|
|
});
|
2022-10-14 10:38:41 +00:00
|
|
|
ASSERT_NE(newAccountIt, updatedAccounts.end());
|
|
|
|
const auto& newAccount = *newAccountIt;
|
|
|
|
|
2022-10-28 17:17:16 +00:00
|
|
|
auto testIntervals = {Wallet::BalanceHistoryTimeInterval::BalanceHistory7Hours,
|
|
|
|
Wallet::BalanceHistoryTimeInterval::BalanceHistory1Month,
|
|
|
|
Wallet::BalanceHistoryTimeInterval::BalanceHistory6Months,
|
|
|
|
Wallet::BalanceHistoryTimeInterval::BalanceHistory1Year,
|
|
|
|
Wallet::BalanceHistoryTimeInterval::BalanceHistoryAllTime};
|
|
|
|
|
|
|
|
std::map<Wallet::BalanceHistoryTimeInterval, QString> testIntervalsStrs{
|
|
|
|
{Wallet::BalanceHistoryTimeInterval::BalanceHistory7Hours, "7H"},
|
|
|
|
{Wallet::BalanceHistoryTimeInterval::BalanceHistory1Month, "1M"},
|
|
|
|
{Wallet::BalanceHistoryTimeInterval::BalanceHistory6Months, "6M"},
|
|
|
|
{Wallet::BalanceHistoryTimeInterval::BalanceHistory1Year, "1Y"},
|
|
|
|
{Wallet::BalanceHistoryTimeInterval::BalanceHistoryAllTime, "All"}};
|
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
// Fetch first and watch for finished signal of newAccount.address
|
|
|
|
int bhStartedReceivedCount = 0;
|
|
|
|
int bhEndedReceivedCount = 0;
|
|
|
|
int bhErrorReceivedCount = 0;
|
|
|
|
bool targetAccountDone = false;
|
|
|
|
QObject::connect(
|
|
|
|
StatusGo::SignalsManager::instance(),
|
|
|
|
&StatusGo::SignalsManager::wallet,
|
|
|
|
testAccount.app(),
|
|
|
|
[&targetAccountDone, &bhStartedReceivedCount, &bhEndedReceivedCount, &bhErrorReceivedCount, &newAccount](
|
|
|
|
QSharedPointer<StatusGo::EventData> data) {
|
|
|
|
Wallet::Transfer::Event event = data->eventInfo();
|
|
|
|
if(event.type == Wallet::Transfer::Events::EventBalanceHistoryUpdateStarted)
|
|
|
|
{
|
|
|
|
bhStartedReceivedCount++;
|
|
|
|
}
|
|
|
|
else if(event.type == Wallet::Transfer::Events::EventBalanceHistoryUpdateFinished)
|
|
|
|
{
|
|
|
|
bhEndedReceivedCount++;
|
|
|
|
if(event.accounts)
|
|
|
|
{
|
|
|
|
auto found = std::find_if(event.accounts.value().begin(),
|
|
|
|
event.accounts.value().end(),
|
|
|
|
[&event, &newAccount](const auto& a) { return a == newAccount.address; });
|
|
|
|
if(found != event.accounts.value().end())
|
|
|
|
{
|
|
|
|
targetAccountDone = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(event.type == Wallet::Transfer::Events::EventBalanceHistoryUpdateFinishedWithError)
|
|
|
|
{
|
|
|
|
bhErrorReceivedCount++;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
std::vector<QString> symbols{params.token};
|
|
|
|
Wallet::updateVisibleTokens(symbols);
|
|
|
|
|
|
|
|
Wallet::startWallet();
|
|
|
|
|
|
|
|
testAccount.processMessages(2400000, [&targetAccountDone, &bhEndedReceivedCount, &bhErrorReceivedCount]() {
|
|
|
|
return !targetAccountDone && bhEndedReceivedCount < 2 && bhErrorReceivedCount < 1;
|
|
|
|
});
|
|
|
|
ASSERT_GT(bhStartedReceivedCount, 0);
|
|
|
|
ASSERT_EQ(bhErrorReceivedCount, 0);
|
|
|
|
ASSERT_GT(bhEndedReceivedCount, 0);
|
|
|
|
ASSERT_TRUE(targetAccountDone);
|
|
|
|
|
2022-10-28 17:17:16 +00:00
|
|
|
for(const auto& historyInterval : testIntervals)
|
2022-10-14 10:38:41 +00:00
|
|
|
{
|
2022-11-15 21:48:59 +00:00
|
|
|
auto balanceHistory = Wallet::getBalanceHistory(chainIDs, newAccount.address, params.token, historyInterval);
|
|
|
|
ASSERT_GT(balanceHistory.size(), 0);
|
2022-10-14 10:38:41 +00:00
|
|
|
|
|
|
|
auto weiToEth = [](const StatusGo::Wallet::BigInt& wei) -> double {
|
|
|
|
StatusGo::Wallet::BigInt q; // wei / eth
|
|
|
|
StatusGo::Wallet::BigInt r; // wei % eth
|
|
|
|
auto weiD = StatusGo::Wallet::BigInt("1000000000000000000");
|
|
|
|
boost::multiprecision::divide_qr(wei, weiD, q, r);
|
|
|
|
StatusGo::Wallet::BigInt rSzabos; // r / szaboD
|
|
|
|
StatusGo::Wallet::BigInt qSzabos; // r % szaboD
|
|
|
|
auto szaboD = StatusGo::Wallet::BigInt("1000000000000");
|
|
|
|
boost::multiprecision::divide_qr(r, szaboD, qSzabos, rSzabos);
|
|
|
|
return q.convert_to<double>() + (qSzabos.convert_to<double>() / ((weiD / szaboD).convert_to<double>()));
|
|
|
|
};
|
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
auto fileInfo = QFileInfo(
|
|
|
|
QString("/tmp/StatusTests/balance/balance_history-%1.csv").arg(testIntervalsStrs[historyInterval]));
|
|
|
|
QFile file(fileInfo.absoluteFilePath());
|
|
|
|
QDir().mkpath(fileInfo.absolutePath());
|
2022-10-14 10:38:41 +00:00
|
|
|
if(file.open(QIODevice::WriteOnly | QIODevice::Text))
|
|
|
|
{
|
|
|
|
QTextStream out(&file);
|
2022-11-15 21:48:59 +00:00
|
|
|
out << "Balance, Timestamp, Block Number, Formatted Date" << Qt::endl;
|
2022-10-28 17:17:16 +00:00
|
|
|
for(int i = 0; i < balanceHistory.size(); ++i)
|
2022-10-14 10:38:41 +00:00
|
|
|
{
|
2022-11-15 21:48:59 +00:00
|
|
|
out << weiToEth(balanceHistory[i].value) << "," << balanceHistory[i].time.toSecsSinceEpoch() << ","
|
|
|
|
<< balanceHistory[i].blockNumber.str().c_str() << ","
|
|
|
|
<< balanceHistory[i].time.toString("dd.MM.yyyy hh:mm:ss") << Qt::endl;
|
2022-10-14 10:38:41 +00:00
|
|
|
}
|
2022-11-15 21:48:59 +00:00
|
|
|
file.close();
|
2022-10-14 10:38:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-26 11:49:03 +00:00
|
|
|
|
2022-11-15 21:48:59 +00:00
|
|
|
TEST(WalletApi, TestStartWallet)
|
|
|
|
{
|
|
|
|
ScopedTestAccount testAccount(test_info_->name());
|
|
|
|
|
|
|
|
auto params = getTestParams();
|
|
|
|
|
|
|
|
// Add watch account
|
|
|
|
Accounts::addAccountWatch(Accounts::EOAddress("0xF38D2CD3C6Ad02dD6f8B68E0A7b2f959819954b6"),
|
|
|
|
params.newTestAccountName,
|
|
|
|
QColor("fuchsia"),
|
|
|
|
u""_qs);
|
|
|
|
const auto updatedAccounts = Accounts::getAccounts();
|
|
|
|
ASSERT_EQ(updatedAccounts.size(), 3);
|
|
|
|
|
|
|
|
int bhStartedReceivedCount = 0;
|
|
|
|
int bhEndedReceivedCount = 0;
|
|
|
|
int bhErrorReceivedCount = 0;
|
|
|
|
QObject::connect(StatusGo::SignalsManager::instance(),
|
|
|
|
&StatusGo::SignalsManager::wallet,
|
|
|
|
testAccount.app(),
|
|
|
|
[&bhStartedReceivedCount, &bhEndedReceivedCount, &bhErrorReceivedCount](
|
|
|
|
QSharedPointer<StatusGo::EventData> data) {
|
|
|
|
Wallet::Transfer::Event event = data->eventInfo();
|
|
|
|
if(event.type == Wallet::Transfer::Events::EventBalanceHistoryUpdateStarted)
|
|
|
|
{
|
|
|
|
bhStartedReceivedCount++;
|
|
|
|
}
|
|
|
|
else if(event.type == Wallet::Transfer::Events::EventBalanceHistoryUpdateFinished)
|
|
|
|
{
|
|
|
|
bhEndedReceivedCount++;
|
|
|
|
}
|
|
|
|
else if(event.type == Wallet::Transfer::Events::EventBalanceHistoryUpdateFinishedWithError)
|
|
|
|
{
|
|
|
|
bhErrorReceivedCount++;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
std::vector<QString> symbols{params.token};
|
|
|
|
Wallet::updateVisibleTokens(symbols);
|
|
|
|
|
|
|
|
Wallet::startWallet();
|
|
|
|
|
|
|
|
testAccount.processMessages(240000, [&bhEndedReceivedCount, &bhErrorReceivedCount]() {
|
|
|
|
return bhEndedReceivedCount < 2 && bhErrorReceivedCount < 1;
|
|
|
|
});
|
|
|
|
ASSERT_EQ(bhStartedReceivedCount, 2);
|
|
|
|
ASSERT_EQ(bhErrorReceivedCount, 0);
|
|
|
|
ASSERT_EQ(bhEndedReceivedCount, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(WalletApi, TestStopBalanceHistory)
|
|
|
|
{
|
|
|
|
ScopedTestAccount testAccount(test_info_->name());
|
|
|
|
|
|
|
|
const auto updatedAccounts = Accounts::getAccounts();
|
|
|
|
ASSERT_EQ(updatedAccounts.size(), 2);
|
|
|
|
|
|
|
|
int bhStartedReceivedCount = 0;
|
|
|
|
int bhEndedReceivedCount = 0;
|
|
|
|
int bhErrorReceivedCount = 0;
|
|
|
|
QString stopMessage;
|
|
|
|
QObject::connect(StatusGo::SignalsManager::instance(),
|
|
|
|
&StatusGo::SignalsManager::wallet,
|
|
|
|
testAccount.app(),
|
|
|
|
[&stopMessage, &bhStartedReceivedCount, &bhEndedReceivedCount, &bhErrorReceivedCount](
|
|
|
|
QSharedPointer<StatusGo::EventData> data) {
|
|
|
|
Wallet::Transfer::Event event = data->eventInfo();
|
|
|
|
if(event.type == Wallet::Transfer::Events::EventBalanceHistoryUpdateStarted)
|
|
|
|
{
|
|
|
|
bhStartedReceivedCount++;
|
|
|
|
}
|
|
|
|
else if(event.type == Wallet::Transfer::Events::EventBalanceHistoryUpdateFinished)
|
|
|
|
{
|
|
|
|
stopMessage = event.message;
|
|
|
|
bhEndedReceivedCount++;
|
|
|
|
}
|
|
|
|
else if(event.type == Wallet::Transfer::Events::EventBalanceHistoryUpdateFinishedWithError)
|
|
|
|
{
|
|
|
|
bhErrorReceivedCount++;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
Wallet::updateVisibleTokens({QString("ETH")});
|
|
|
|
|
|
|
|
Wallet::startWallet();
|
|
|
|
|
|
|
|
bool stopCalled = false;
|
|
|
|
testAccount.processMessages(5000,
|
|
|
|
[&stopCalled, &bhStartedReceivedCount, &bhEndedReceivedCount, &bhErrorReceivedCount]() {
|
|
|
|
if(bhStartedReceivedCount == 1 && !stopCalled)
|
|
|
|
{
|
|
|
|
stopCalled = true;
|
|
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
|
|
Wallet::stopWallet();
|
|
|
|
}
|
|
|
|
return bhEndedReceivedCount < 1 && bhErrorReceivedCount < 1;
|
|
|
|
});
|
|
|
|
ASSERT_EQ(bhStartedReceivedCount, 1);
|
|
|
|
ASSERT_EQ(bhErrorReceivedCount, 0);
|
|
|
|
ASSERT_EQ(bhEndedReceivedCount, 1);
|
|
|
|
ASSERT_EQ("Service canceled", stopMessage);
|
|
|
|
|
|
|
|
stopMessage = "";
|
|
|
|
|
|
|
|
// Do an empty run
|
|
|
|
Wallet::updateVisibleTokens({});
|
|
|
|
|
|
|
|
Wallet::stopWallet();
|
|
|
|
|
|
|
|
stopCalled = false;
|
|
|
|
testAccount.processMessages(1000,
|
|
|
|
[&stopCalled, &bhStartedReceivedCount, &bhEndedReceivedCount, &bhErrorReceivedCount]() {
|
|
|
|
return bhEndedReceivedCount < 2 && bhErrorReceivedCount < 2;
|
|
|
|
});
|
|
|
|
|
|
|
|
ASSERT_EQ(bhStartedReceivedCount, 2);
|
|
|
|
ASSERT_EQ(bhErrorReceivedCount, 0);
|
|
|
|
ASSERT_EQ(bhEndedReceivedCount, 2);
|
|
|
|
ASSERT_EQ("", stopMessage);
|
|
|
|
}
|
|
|
|
|
2022-10-14 10:38:41 +00:00
|
|
|
} // namespace Status::Testing
|