chore(CPP): integrate tokens balance in UI POC
Integrate token count in UI Use delete later for QML exposed items to avoid errors Closes #6321
This commit is contained in:
parent
f3dcdf636a
commit
7cf0170a8a
|
@ -63,7 +63,7 @@ cmake -B build -S . -DCMAKE_PREFIX_PATH="$HOME/Qt/6.3.2/gcc_64" -DCMAKE_BUILD_TY
|
||||||
|
|
||||||
# Windows: cmake -B build -S . -DCMAKE_PREFIX_PATH="$HOME/Qt/6.3.2/mingw_64" -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=build/conan/conan_toolchain.cmake
|
# Windows: cmake -B build -S . -DCMAKE_PREFIX_PATH="$HOME/Qt/6.3.2/mingw_64" -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=build/conan/conan_toolchain.cmake
|
||||||
|
|
||||||
cmake --build build --config Release
|
cmake --build build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run tests
|
### Run tests
|
||||||
|
|
|
@ -58,7 +58,9 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
|
beginResetModel();
|
||||||
m_objects.clear();
|
m_objects.clear();
|
||||||
|
endResetModel();
|
||||||
};
|
};
|
||||||
|
|
||||||
void push_back(const std::shared_ptr<T> newValue) {
|
void push_back(const std::shared_ptr<T> newValue) {
|
||||||
|
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
#include "Helpers/BuildConfiguration.h"
|
#include "Helpers/BuildConfiguration.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
namespace Status::Helpers {
|
namespace Status::Helpers {
|
||||||
|
|
||||||
|
@ -29,4 +33,24 @@ bool iequals(const T& a, const T& b, size_t len = -1)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename KeyType, typename ValT>
|
||||||
|
std::vector<KeyType> getKeys(const std::map<KeyType, ValT>& map)
|
||||||
|
{
|
||||||
|
std::vector<KeyType> keys;
|
||||||
|
keys.reserve(map.size());
|
||||||
|
for (const auto& [key, _] : map)
|
||||||
|
keys.push_back(key);
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doDeleteLater(QObject *obj) {
|
||||||
|
obj->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use https://en.cppreference.com/w/cpp/memory/shared_ptr/allocate_shared
|
||||||
|
template<typename T, typename ...Args>
|
||||||
|
std::shared_ptr<T> makeSharedQObject(Args&& ...args) {
|
||||||
|
return std::shared_ptr<T>(new T(std::forward<Args>(args)...), doDeleteLater);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ import Status.Onboarding
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// TODO: fix error "Unable to assign Status::Onboarding::NewAccountController to Status::Onboarding::NewAccountController" then enable typed properties
|
/// \c NewAccountController
|
||||||
required property var/*NewAccountController*/ newAccountController
|
required property var newAccountController
|
||||||
|
|
||||||
signal userLoggedIn()
|
signal userLoggedIn()
|
||||||
signal abortAccountCreation()
|
signal abortAccountCreation()
|
||||||
|
|
|
@ -12,6 +12,7 @@ TextInput {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
border.color: "#55555555"
|
||||||
z: parent.z - 1
|
z: parent.z - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ import "base"
|
||||||
OnboardingPageBase {
|
OnboardingPageBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property var onboardingController // OnboardingController
|
/// \c OnboardingController
|
||||||
|
/// \todo investigate "Unable to assign Status::Onboarding::OnboardingController to Status::Onboarding::OnboardingController"
|
||||||
|
required property var onboardingController
|
||||||
|
|
||||||
signal setupNewAccount()
|
signal setupNewAccount()
|
||||||
/// \param statusAccount \c UserAccount
|
/// \param statusAccount \c UserAccount
|
||||||
|
@ -51,15 +53,6 @@ OnboardingPageBase {
|
||||||
id: passwordInput
|
id: passwordInput
|
||||||
Layout.preferredWidth: 328
|
Layout.preferredWidth: 328
|
||||||
Layout.preferredHeight: 44
|
Layout.preferredHeight: 44
|
||||||
|
|
||||||
// TODO: remove dev helper
|
|
||||||
text: "1234567890"
|
|
||||||
Timer {
|
|
||||||
interval: 100
|
|
||||||
running: loginButton.enabled && accountsComboBox.count
|
|
||||||
onTriggered: loginButton.clicked()
|
|
||||||
}
|
|
||||||
// END dev
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
||||||
|
import Status.Onboarding
|
||||||
|
|
||||||
/*! Proposal on how to templetize the alignment requirement of some views
|
/*! Proposal on how to templetize the alignment requirement of some views
|
||||||
*/
|
*/
|
||||||
OnboardingPageBase {
|
OnboardingPageBase {
|
||||||
// TODO: fix error "Unable to assign Status::Onboarding::NewAccountController to Status::Onboarding::NewAccountController" then enable typed properties
|
// TODO: fix error "Unable to assign Status::Onboarding::NewAccountController to Status::Onboarding::NewAccountController" then enable typed properties
|
||||||
required property var/*NewAccountController*/ newAccountController
|
required property var newAccountController
|
||||||
|
|
||||||
/// Common reference item that doesn't change between common views/pages
|
/// Common reference item that doesn't change between common views/pages
|
||||||
readonly property Item alignmentItem: alignmentBaselineItem
|
readonly property Item alignmentItem: alignmentBaselineItem
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#include <StatusGo/SignalsManager.h>
|
#include <StatusGo/SignalsManager.h>
|
||||||
|
|
||||||
|
#include <Helpers/helpers.h>
|
||||||
|
|
||||||
namespace Status::Onboarding {
|
namespace Status::Onboarding {
|
||||||
|
|
||||||
namespace StatusGo = Status::StatusGo;
|
namespace StatusGo = Status::StatusGo;
|
||||||
|
@ -17,9 +19,9 @@ OnboardingController::OnboardingController(AccountsServiceInterfacePtr accountsS
|
||||||
{ // Init accounts
|
{ // Init accounts
|
||||||
std::vector<std::shared_ptr<UserAccount>> accounts;
|
std::vector<std::shared_ptr<UserAccount>> accounts;
|
||||||
for(auto &account : getOpenedAccounts()) {
|
for(auto &account : getOpenedAccounts()) {
|
||||||
accounts.push_back(std::make_shared<UserAccount>(std::make_unique<MultiAccount>(std::move(account))));
|
accounts.push_back(Helpers::makeSharedQObject<UserAccount>(std::make_unique<MultiAccount>(std::move(account))));
|
||||||
}
|
}
|
||||||
m_accounts = std::make_shared<UserAccountsModel>(std::move(accounts));
|
m_accounts = Helpers::makeSharedQObject<UserAccountsModel>(std::move(accounts));
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(StatusGo::SignalsManager::instance(), &StatusGo::SignalsManager::nodeLogin, this, &OnboardingController::onLogin);
|
connect(StatusGo::SignalsManager::instance(), &StatusGo::SignalsManager::nodeLogin, this, &OnboardingController::onLogin);
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
|
|
||||||
UserAccountsModel *accounts() const;
|
UserAccountsModel *accounts() const;
|
||||||
|
|
||||||
Q_INVOKABLE NewAccountController *initNewAccountController();
|
Q_INVOKABLE Status::Onboarding::NewAccountController *initNewAccountController();
|
||||||
Q_INVOKABLE void terminateNewAccountController();
|
Q_INVOKABLE void terminateNewAccountController();
|
||||||
NewAccountController *newAccountController() const;
|
NewAccountController *newAccountController() const;
|
||||||
std::shared_ptr<AccountsServiceInterface> accountsService() const;
|
std::shared_ptr<AccountsServiceInterface> accountsService() const;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <ApplicationCore/UserConfiguration.h>
|
#include <ApplicationCore/UserConfiguration.h>
|
||||||
|
|
||||||
|
#include <Helpers/helpers.h>
|
||||||
|
|
||||||
namespace AppCore = Status::ApplicationCore;
|
namespace AppCore = Status::ApplicationCore;
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ void OnboardingModule::initWithUserDataPath(const fs::path &path)
|
||||||
auto result = m_accountsService->init(path);
|
auto result = m_accountsService->init(path);
|
||||||
if(!result)
|
if(!result)
|
||||||
throw std::runtime_error(std::string("Failed to initialize OnboadingService") + path.string());
|
throw std::runtime_error(std::string("Failed to initialize OnboadingService") + path.string());
|
||||||
m_controller = std::make_shared<OnboardingController>(
|
m_controller = Helpers::makeSharedQObject<OnboardingController>(
|
||||||
m_accountsService);
|
m_accountsService);
|
||||||
emit controllerChanged();
|
emit controllerChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ project(OnboardingTestHelpers
|
||||||
|
|
||||||
set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true)
|
set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true)
|
||||||
|
|
||||||
find_package(GTest REQUIRED)
|
|
||||||
|
|
||||||
find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Quick Qml REQUIRED)
|
find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Quick Qml REQUIRED)
|
||||||
qt6_standard_project_setup()
|
qt6_standard_project_setup()
|
||||||
|
|
||||||
|
@ -47,6 +45,4 @@ target_link_libraries(OnboardingTestHelpers
|
||||||
Status::ApplicationCore
|
Status::ApplicationCore
|
||||||
Status::Onboarding
|
Status::Onboarding
|
||||||
Status::StatusGoQt
|
Status::StatusGoQt
|
||||||
|
|
||||||
GTest::gtest
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
#include <StatusGo/Accounts/Accounts.h>
|
#include <StatusGo/Accounts/Accounts.h>
|
||||||
#include <StatusGo/Accounts/AccountsAPI.h>
|
#include <StatusGo/Accounts/AccountsAPI.h>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <Helpers/helpers.h>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
namespace Testing = Status::Testing;
|
namespace Testing = Status::Testing;
|
||||||
namespace Onboarding = Status::Onboarding;
|
namespace Onboarding = Status::Onboarding;
|
||||||
|
@ -49,7 +49,7 @@ ScopedTestAccount::ScopedTestAccount(const std::string &tempTestSubfolderName,
|
||||||
//
|
//
|
||||||
|
|
||||||
// Beware, smartpointer is a requirement
|
// Beware, smartpointer is a requirement
|
||||||
m_onboarding = std::make_shared<Onboarding::OnboardingController>(accountsService);
|
m_onboarding = Helpers::makeSharedQObject<Onboarding::OnboardingController>(accountsService);
|
||||||
if(m_onboarding->getOpenedAccounts().size() != 0)
|
if(m_onboarding->getOpenedAccounts().size() != 0)
|
||||||
throw std::runtime_error("ScopedTestAccount - already have opened account");
|
throw std::runtime_error("ScopedTestAccount - already have opened account");
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <Onboarding/Accounts/AccountsService.h>
|
#include <Onboarding/Accounts/AccountsService.h>
|
||||||
#include <Onboarding/OnboardingController.h>
|
#include <Onboarding/OnboardingController.h>
|
||||||
|
|
||||||
|
#include <Helpers/helpers.h>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -49,7 +51,7 @@ std::shared_ptr<AccountsServiceMock> LoginTest::m_accountsServiceMock;
|
||||||
TEST_F(LoginTest, DISABLED_TestLoginController)
|
TEST_F(LoginTest, DISABLED_TestLoginController)
|
||||||
{
|
{
|
||||||
// Controller hides as a regular class but at runtime it must be a shared pointer; TODO: refactor
|
// Controller hides as a regular class but at runtime it must be a shared pointer; TODO: refactor
|
||||||
auto controller = std::make_shared<Onboarding::OnboardingController>(m_accountsServiceMock);
|
auto controller = Helpers::makeSharedQObject<Onboarding::OnboardingController>(m_accountsServiceMock);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -28,6 +28,7 @@ struct Token
|
||||||
ChainID chainId;
|
ChainID chainId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using TokenPtr = std::shared_ptr<Token>;
|
||||||
using Tokens = std::vector<Token>;
|
using Tokens = std::vector<Token>;
|
||||||
|
|
||||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Token, address, name,symbol,
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Token, address, name,symbol,
|
||||||
|
|
|
@ -28,12 +28,13 @@ NetworkConfigurations getEthereumChains(bool onlyEnabled);
|
||||||
|
|
||||||
/// \note status-go's GetEthereumChains@api.go which calls
|
/// \note status-go's GetEthereumChains@api.go which calls
|
||||||
/// NetworkManager@client.go -> network.Manager.get()
|
/// NetworkManager@client.go -> network.Manager.get()
|
||||||
/// \throws \c CallPrivateRpcError
|
/// \throws \c CallPrivateRpcError.errorResponse().error with \c "no tokens for this network" in case of missing tokens for the network
|
||||||
|
/// \throws \c CallPrivateRpcError for general RPC call failure
|
||||||
NetworkConfigurations getEthereumChains(bool onlyEnabled);
|
NetworkConfigurations getEthereumChains(bool onlyEnabled);
|
||||||
|
|
||||||
|
|
||||||
/// \note status-go's GetTokens@api.go -> TokenManager.getTokens@token.go
|
/// \note status-go's GetTokens@api.go -> TokenManager.getTokens@token.go
|
||||||
/// \throws \c CallPrivateRpcError
|
/// \throws \c CallPrivateRpcError with
|
||||||
Tokens getTokens(const ChainID &chainId);
|
Tokens getTokens(const ChainID &chainId);
|
||||||
|
|
||||||
using TokenBalances = std::map<Accounts::EOAddress, std::map<Accounts::EOAddress, BigInt>>;
|
using TokenBalances = std::map<Accounts::EOAddress, std::map<Accounts::EOAddress, BigInt>>;
|
||||||
|
|
|
@ -66,13 +66,17 @@ install(
|
||||||
|
|
||||||
target_sources(Wallet
|
target_sources(Wallet
|
||||||
PRIVATE
|
PRIVATE
|
||||||
|
include/Status/Wallet/AccountAssetsController.h
|
||||||
|
src/AccountAssetsController.cpp
|
||||||
include/Status/Wallet/DerivedWalletAddress.h
|
include/Status/Wallet/DerivedWalletAddress.h
|
||||||
src/DerivedWalletAddress.cpp
|
src/DerivedWalletAddress.cpp
|
||||||
include/Status/Wallet/NewWalletAccountController.h
|
include/Status/Wallet/NewWalletAccountController.h
|
||||||
src/NewWalletAccountController.cpp
|
src/NewWalletAccountController.cpp
|
||||||
include/Status/Wallet/WalletAccount.h
|
|
||||||
# Move to Accounts module
|
# Move to Accounts module
|
||||||
|
include/Status/Wallet/WalletAccount.h
|
||||||
src/WalletAccount.cpp
|
src/WalletAccount.cpp
|
||||||
|
include/Status/Wallet/WalletAsset.h
|
||||||
|
src/WalletAsset.cpp
|
||||||
include/Status/Wallet/WalletController.h
|
include/Status/Wallet/WalletController.h
|
||||||
src/WalletController.cpp
|
src/WalletController.cpp
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Status/Wallet/WalletAccount.h"
|
||||||
|
#include "Status/Wallet/WalletAsset.h"
|
||||||
|
|
||||||
|
#include <Helpers/QObjectVectorModel.h>
|
||||||
|
|
||||||
|
#include <QtQmlIntegration>
|
||||||
|
|
||||||
|
namespace Status::Wallet {
|
||||||
|
|
||||||
|
/// Controlls asset for an account using hardcoded network and token lists
|
||||||
|
///
|
||||||
|
/// \todo add static configuration component to provide networks, tokens and currency list
|
||||||
|
/// \todo impliement \c AccountsBalanceService to fetch and cache realtime balance (or better implement this in status-go)
|
||||||
|
/// \todo implement native token fetching
|
||||||
|
/// \todo double responsibility, split functionality in asset management and balance
|
||||||
|
class AccountAssetsController: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_UNCREATABLE("C++ only")
|
||||||
|
|
||||||
|
Q_PROPERTY(QAbstractItemModel* assetModel READ assetsModel CONSTANT)
|
||||||
|
Q_PROPERTY(float totalValue READ totalValue NOTIFY totalValueChanged)
|
||||||
|
Q_PROPERTY(bool assetsReady READ assetsReady NOTIFY assetsReadyChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
AccountAssetsController(WalletAccount* address, QObject* parent = nullptr);
|
||||||
|
|
||||||
|
QAbstractItemModel* assetsModel() const;
|
||||||
|
|
||||||
|
float totalValue() const;
|
||||||
|
|
||||||
|
bool assetsReady() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void totalValueChanged();
|
||||||
|
void assetsReadyChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateBalances();
|
||||||
|
bool isTokenEnabled(const StatusGo::Wallet::Token& token) const;
|
||||||
|
|
||||||
|
WalletAccount* m_address;
|
||||||
|
const std::vector<QString> m_enabledTokens;
|
||||||
|
|
||||||
|
using AssetModel = Helpers::QObjectVectorModel<WalletAsset>;
|
||||||
|
std::shared_ptr<AssetModel> m_assets;
|
||||||
|
float m_totalValue{};
|
||||||
|
bool m_assetsReady{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Status::Wallet
|
|
@ -2,30 +2,32 @@
|
||||||
|
|
||||||
#include <StatusGo/Wallet/DerivedAddress.h>
|
#include <StatusGo/Wallet/DerivedAddress.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QtQmlIntegration>
|
||||||
|
|
||||||
namespace GoWallet = Status::StatusGo::Wallet;
|
namespace WalletGo = Status::StatusGo::Wallet;
|
||||||
|
|
||||||
namespace Status::Wallet {
|
namespace Status::Wallet {
|
||||||
|
|
||||||
class DerivedWalletAddress : public QObject
|
class DerivedWalletAddress : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_UNCREATABLE("C++ only")
|
||||||
|
|
||||||
Q_PROPERTY(QString address READ address CONSTANT)
|
Q_PROPERTY(QString address READ address CONSTANT)
|
||||||
Q_PROPERTY(bool alreadyCreated READ alreadyCreated CONSTANT)
|
Q_PROPERTY(bool alreadyCreated READ alreadyCreated CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DerivedWalletAddress(GoWallet::DerivedAddress address, QObject *parent = nullptr);
|
explicit DerivedWalletAddress(WalletGo::DerivedAddress address, QObject *parent = nullptr);
|
||||||
|
|
||||||
QString address() const;
|
QString address() const;
|
||||||
|
|
||||||
const GoWallet::DerivedAddress &data() const { return m_derivedAddress; };
|
const WalletGo::DerivedAddress &data() const { return m_derivedAddress; };
|
||||||
|
|
||||||
bool alreadyCreated() const;
|
bool alreadyCreated() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const GoWallet::DerivedAddress m_derivedAddress;
|
const WalletGo::DerivedAddress m_derivedAddress;
|
||||||
};
|
};
|
||||||
|
|
||||||
using DerivedWalletAddressPtr = std::shared_ptr<DerivedWalletAddress>;
|
using DerivedWalletAddressPtr = std::shared_ptr<DerivedWalletAddress>;
|
||||||
|
|
|
@ -5,19 +5,16 @@
|
||||||
|
|
||||||
#include <Helpers/QObjectVectorModel.h>
|
#include <Helpers/QObjectVectorModel.h>
|
||||||
|
|
||||||
#include <QQmlListProperty>
|
|
||||||
#include <QtQmlIntegration>
|
#include <QtQmlIntegration>
|
||||||
|
|
||||||
class QQmlEngine;
|
|
||||||
class QJSEngine;
|
|
||||||
|
|
||||||
namespace Status::Wallet {
|
namespace Status::Wallet {
|
||||||
|
|
||||||
/// \note the folowing values are kept in sync \c selectedDerivedAddress, \c derivedAddressIndex and \c derivationPath
|
/// \note the following values are kept in sync \c selectedDerivedAddress, \c derivedAddressIndex and \c derivationPath
|
||||||
/// and \c customDerivationPath; \see connascence.io/value
|
/// and \c customDerivationPath; \see connascence.io/value
|
||||||
class NewWalletAccountController: public QObject
|
class NewWalletAccountController: public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
QML_UNCREATABLE("C++ only")
|
QML_UNCREATABLE("C++ only")
|
||||||
|
|
||||||
Q_PROPERTY(QAbstractListModel* mainAccountsModel READ mainAccountsModel CONSTANT)
|
Q_PROPERTY(QAbstractListModel* mainAccountsModel READ mainAccountsModel CONSTANT)
|
||||||
|
@ -35,10 +32,6 @@ public:
|
||||||
/// \note On account creation \c accounts are updated with the newly created wallet account
|
/// \note On account creation \c accounts are updated with the newly created wallet account
|
||||||
NewWalletAccountController(std::shared_ptr<AccountsModel> accounts);
|
NewWalletAccountController(std::shared_ptr<AccountsModel> accounts);
|
||||||
|
|
||||||
/// Called by QML engine to register the instance. QML takes ownership of the instance
|
|
||||||
static NewWalletAccountController *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine);
|
|
||||||
|
|
||||||
|
|
||||||
QAbstractListModel *mainAccountsModel();
|
QAbstractListModel *mainAccountsModel();
|
||||||
QAbstractItemModel *currentDerivedAddressModel();
|
QAbstractItemModel *currentDerivedAddressModel();
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include "Accounts/ChatOrWalletAccount.h"
|
#include "Accounts/ChatOrWalletAccount.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QtQmlIntegration>
|
||||||
|
|
||||||
namespace GoAccounts = Status::StatusGo::Accounts;
|
namespace GoAccounts = Status::StatusGo::Accounts;
|
||||||
|
|
||||||
|
@ -11,9 +11,11 @@ namespace Status::Wallet {
|
||||||
class WalletAccount: public QObject
|
class WalletAccount: public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_UNCREATABLE("C++ only, for now")
|
||||||
|
|
||||||
Q_PROPERTY(QString name READ name CONSTANT)
|
Q_PROPERTY(QString name READ name CONSTANT)
|
||||||
Q_PROPERTY(QString address READ address CONSTANT)
|
Q_PROPERTY(QString address READ strAddress CONSTANT)
|
||||||
Q_PROPERTY(QColor color READ color CONSTANT)
|
Q_PROPERTY(QColor color READ color CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -21,7 +23,7 @@ public:
|
||||||
|
|
||||||
const QString &name() const;
|
const QString &name() const;
|
||||||
|
|
||||||
const QString &address() const;
|
const QString &strAddress() const;
|
||||||
|
|
||||||
QColor color() const;
|
QColor color() const;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <StatusGo/Wallet/Token.h>
|
||||||
|
#include <StatusGo/Wallet/BigInt.h>
|
||||||
|
|
||||||
|
#include <QtQmlIntegration>
|
||||||
|
|
||||||
|
namespace WalletGo = Status::StatusGo::Wallet;
|
||||||
|
|
||||||
|
namespace Status::Wallet {
|
||||||
|
|
||||||
|
class WalletAsset : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_UNCREATABLE("C++ only, for now")
|
||||||
|
|
||||||
|
Q_PROPERTY(QString name READ name CONSTANT)
|
||||||
|
Q_PROPERTY(QString symbol READ symbol CONSTANT)
|
||||||
|
Q_PROPERTY(QColor color READ color CONSTANT)
|
||||||
|
Q_PROPERTY(quint64 count READ count CONSTANT)
|
||||||
|
Q_PROPERTY(float value READ value CONSTANT)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit WalletAsset(const WalletGo::TokenPtr token, StatusGo::Wallet::BigInt balance, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
const QString name() const;
|
||||||
|
|
||||||
|
const QString symbol() const;
|
||||||
|
|
||||||
|
const QColor color() const;
|
||||||
|
|
||||||
|
quint64 count() const;
|
||||||
|
|
||||||
|
float value() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const WalletGo::TokenPtr m_token;
|
||||||
|
// const GoWallet::NativeToken m_nativeToken;
|
||||||
|
|
||||||
|
StatusGo::Wallet::BigInt m_balance;
|
||||||
|
int m_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#include <Helpers/QObjectVectorModel.h>
|
#include <Helpers/QObjectVectorModel.h>
|
||||||
|
|
||||||
#include <QQmlListProperty>
|
|
||||||
#include <QtQmlIntegration>
|
#include <QtQmlIntegration>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -16,6 +15,7 @@ class QJSEngine;
|
||||||
namespace Status::Wallet {
|
namespace Status::Wallet {
|
||||||
|
|
||||||
class NewWalletAccountController;
|
class NewWalletAccountController;
|
||||||
|
class AccountAssetsController;
|
||||||
|
|
||||||
/// \todo move account creation to its own controller
|
/// \todo move account creation to its own controller
|
||||||
class WalletController: public QObject
|
class WalletController: public QObject
|
||||||
|
@ -44,6 +44,9 @@ public:
|
||||||
WalletAccount *currentAccount() const;
|
WalletAccount *currentAccount() const;
|
||||||
Q_INVOKABLE void setCurrentAccountIndex(int index);
|
Q_INVOKABLE void setCurrentAccountIndex(int index);
|
||||||
|
|
||||||
|
/// \note caller (QML) takes ownership of the returned instance
|
||||||
|
Q_INVOKABLE Status::Wallet::AccountAssetsController* createAccountAssetsController(Status::Wallet::WalletAccount* account);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void currentAccountChanged();
|
void currentAccountChanged();
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,51 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import Status.Wallet
|
||||||
|
import Status.Containers
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
/// WalletAccount
|
required property AccountAssetsController assetController
|
||||||
required property var asset
|
required property WalletAccount account
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: listView
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
model: root.assetController.assetModel
|
||||||
|
|
||||||
|
delegate: RowLayout {
|
||||||
|
required property WalletAsset asset
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
anchors.centerIn: parent
|
|
||||||
text: asset.name
|
text: asset.name
|
||||||
|
|
||||||
|
Layout.preferredWidth: listView.width * 0.4
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
Layout.preferredWidth: listView.width * 0.4
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: asset.count
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: asset.symbol
|
||||||
|
}
|
||||||
|
LayoutSpacer{}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
text: asset.value
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
//text: asset.currency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LayoutSpacer{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import QtQml
|
||||||
|
|
||||||
import Status.Wallet
|
import Status.Wallet
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@ Item {
|
||||||
|
|
||||||
/// WalletController
|
/// WalletController
|
||||||
required property WalletController controller
|
required property WalletController controller
|
||||||
|
readonly property AccountAssetsController currentAssetController: listView.currentItem ? listView.currentItem.assetController : null
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.left: leftLine.right
|
anchors.left: leftLine.right
|
||||||
|
@ -25,7 +27,8 @@ Item {
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
id: totalValueLabel
|
id: totalValueLabel
|
||||||
text: "" // TODO: Aggregate or API!?
|
// TODO: source it from the last total cached value of balance service,
|
||||||
|
text: "-"
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
text: qsTr("Total value")
|
text: qsTr("Total value")
|
||||||
|
@ -37,6 +40,8 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
|
id: listView
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
@ -47,10 +52,17 @@ Item {
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
delegate: ItemDelegate {
|
delegate: ItemDelegate {
|
||||||
|
required property int index
|
||||||
|
// Enabling type generates 'Writing to "account" broke the binding to the underlying model'
|
||||||
|
required property var/*WalletAccount*/ account
|
||||||
|
|
||||||
|
readonly property AccountAssetsController assetController: account && WalletController.createAccountAssetsController(account)
|
||||||
|
|
||||||
highlighted: ListView.isCurrentItem
|
highlighted: ListView.isCurrentItem
|
||||||
|
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
|
|
||||||
|
|
||||||
onClicked: ListView.view.currentIndex = index
|
onClicked: ListView.view.currentIndex = index
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
|
@ -79,17 +91,19 @@ Item {
|
||||||
elide: Label.ElideRight
|
elide: Label.ElideRight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Label {
|
|
||||||
|
RowLayout {
|
||||||
Layout.leftMargin: 10
|
Layout.leftMargin: 10
|
||||||
Layout.rightMargin: 10
|
Layout.rightMargin: 10
|
||||||
Layout.bottomMargin: 5
|
Layout.bottomMargin: 5
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: assetController.assetsReady ? assetController.totalValue : "-"
|
||||||
|
}
|
||||||
|
Label {
|
||||||
text: "$"
|
text: "$"
|
||||||
color: "grey"
|
color: "grey"
|
||||||
|
}
|
||||||
verticalAlignment: Qt.AlignVCenter
|
|
||||||
|
|
||||||
elide: Label.ElideRight
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,13 +151,13 @@ Item {
|
||||||
}
|
}
|
||||||
model: ObjectModel {
|
model: ObjectModel {
|
||||||
NewAccountEntry {
|
NewAccountEntry {
|
||||||
title: "New Account"
|
title: qsTr("New Account")
|
||||||
sourceComponent: NewWalletAccountView {
|
sourceComponent: NewWalletAccountView {
|
||||||
controller: root.controller.createNewWalletAccountController()
|
controller: root.controller.createNewWalletAccountController()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NewAccountEntry {
|
NewAccountEntry {
|
||||||
title: "Watch Only Account"
|
title: qsTr("Watch Only Account")
|
||||||
sourceComponent: AddWatchOnlyAccountView {
|
sourceComponent: AddWatchOnlyAccountView {
|
||||||
controller: root.controller.createNewWalletAccountController()
|
controller: root.controller.createNewWalletAccountController()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,7 @@ import Status.Containers
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
/// NewWalletAccountController
|
required property NewWalletAccountController controller
|
||||||
required property var controller
|
|
||||||
|
|
||||||
signal accountCreated()
|
signal accountCreated()
|
||||||
signal cancel()
|
signal cancel()
|
||||||
|
|
|
@ -9,7 +9,7 @@ import Status.Containers
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
/// NewWalletAccountController
|
// Using the type NewWalletAccountController generates "/bin/sh: line 1: 12832 Segmentation fault: 11 qmlcachegen --resource-path /Status/Wallet/qml/Status/Wallet/NewAccount/NewWalletAccountView.qml"
|
||||||
required property var controller
|
required property var controller
|
||||||
|
|
||||||
signal accountCreated()
|
signal accountCreated()
|
||||||
|
@ -135,7 +135,7 @@ Item {
|
||||||
}
|
}
|
||||||
highlighted: derivedAddressCombo.highlightedIndex === index
|
highlighted: derivedAddressCombo.highlightedIndex === index
|
||||||
|
|
||||||
required property var derivedAddress
|
required property DerivedWalletAddress derivedAddress
|
||||||
required property int index
|
required property int index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ Item {
|
||||||
}
|
}
|
||||||
highlighted: derivedFromCombo.highlightedIndex === index
|
highlighted: derivedFromCombo.highlightedIndex === index
|
||||||
|
|
||||||
required property var account
|
required property WalletAccount account
|
||||||
required property int index
|
required property int index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,17 @@ import Status.Wallet
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
/// WalletAccount
|
required property WalletAccount account
|
||||||
required property var asset
|
required property AccountAssetsController assetController
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: asset.name
|
text: account.name
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
text: asset.address
|
text: account.address
|
||||||
}
|
}
|
||||||
TabBar {
|
TabBar {
|
||||||
id: tabBar
|
id: tabBar
|
||||||
|
@ -37,6 +37,7 @@ Item {
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
Layout.margins: 10
|
||||||
|
|
||||||
currentIndex: tabBar.currentIndex
|
currentIndex: tabBar.currentIndex
|
||||||
|
|
||||||
|
@ -44,21 +45,24 @@ Item {
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: SwipeView.isCurrentItem
|
active: SwipeView.isCurrentItem && root.assetController && root.account
|
||||||
sourceComponent: AssetView {
|
sourceComponent: AssetView {
|
||||||
Layout.fillWidth: true
|
Rectangle {
|
||||||
Layout.fillHeight: true
|
anchors.fill: parent
|
||||||
|
color: "#66000066"
|
||||||
|
border.width: 1
|
||||||
|
}
|
||||||
|
width: swipeView.width
|
||||||
|
height: swipeView.height
|
||||||
|
|
||||||
asset: root.asset
|
assetController: root.assetController
|
||||||
|
account: root.account
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: SwipeView.isCurrentItem
|
active: SwipeView.isCurrentItem
|
||||||
sourceComponent: Item {
|
sourceComponent: Item {
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "TODO"
|
text: "TODO"
|
||||||
|
|
|
@ -36,7 +36,8 @@ PanelAndContentBase {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
asset: WalletController.currentAccount
|
account: WalletController.currentAccount
|
||||||
|
assetController: panel.currentAssetController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
#include "Status/Wallet/AccountAssetsController.h"
|
||||||
|
|
||||||
|
#include <StatusGo/Wallet/WalletApi.h>
|
||||||
|
#include <StatusGo/Wallet/BigInt.h>
|
||||||
|
#include <StatusGo/Metadata/api_response.h>
|
||||||
|
|
||||||
|
#include <Helpers/helpers.h>
|
||||||
|
|
||||||
|
#include <QtConcurrent>
|
||||||
|
|
||||||
|
namespace WalletGo = Status::StatusGo::Wallet;
|
||||||
|
|
||||||
|
namespace Status::Wallet {
|
||||||
|
|
||||||
|
AccountAssetsController::AccountAssetsController(WalletAccount* address, QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_address(address)
|
||||||
|
, m_enabledTokens({u"SNT"_qs, u"ETH"_qs, u"STT"_qs, u"DAI"_qs})
|
||||||
|
, m_assets(Helpers::makeSharedQObject<AssetModel>("asset"))
|
||||||
|
{
|
||||||
|
QtConcurrent::run([this, address]{ updateBalances(); })
|
||||||
|
.then([this] {
|
||||||
|
m_assetsReady = true;
|
||||||
|
emit assetsReadyChanged();
|
||||||
|
|
||||||
|
m_totalValue = 0;
|
||||||
|
for(const auto& asset : m_assets->objects())
|
||||||
|
m_totalValue += asset->value();
|
||||||
|
emit totalValueChanged();
|
||||||
|
})
|
||||||
|
.onFailed([this] {
|
||||||
|
emit assetsReadyChanged();
|
||||||
|
qWarning() << "Unexpected failure while executing updateBalances for account" << m_address->data().address.get();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountAssetsController::updateBalances()
|
||||||
|
{
|
||||||
|
const StatusGo::Accounts::EOAddress& address = m_address->data().address;
|
||||||
|
if(m_assets->size() > 0)
|
||||||
|
m_assets->clear();
|
||||||
|
// TODO: this should be moved to status-go and exposed as "get balances for account and tokens with currency"
|
||||||
|
std::map<Accounts::EOAddress, StatusGo::Wallet::Token> tokens;
|
||||||
|
std::vector<WalletGo::ChainID> chainIds;
|
||||||
|
auto allNets = WalletGo::getEthereumChains(false);
|
||||||
|
for(const auto &net : allNets) {
|
||||||
|
if(net.enabled && !net.isTest) {
|
||||||
|
try {
|
||||||
|
const auto allTokens = WalletGo::getTokens(net.chainId);
|
||||||
|
for(const auto& tokenToMove : allTokens) {
|
||||||
|
if(isTokenEnabled(tokenToMove)) {
|
||||||
|
auto address = tokenToMove.address;
|
||||||
|
tokens.emplace(std::move(address), std::move(tokenToMove));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chainIds.push_back(net.chainId);
|
||||||
|
}
|
||||||
|
catch (const StatusGo::CallPrivateRpcError& e) {
|
||||||
|
// Most probably "no tokens for this network"
|
||||||
|
if(e.errorResponse().error.message.compare("no tokens for this network") != 0)
|
||||||
|
qWarning() << "Failed retrieving tokens for network" << net.chainId.get() << "; error" << e.errorResponse().error.message.c_str();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto accountBalances = WalletGo::getTokensBalancesForChainIDs(chainIds, { address }, std::move(Helpers::getKeys(tokens)));
|
||||||
|
if(accountBalances.size() == 1) {
|
||||||
|
for(const auto& accountAndBalance : accountBalances.begin()->second) {
|
||||||
|
auto asset = Helpers::makeSharedQObject<WalletAsset>(std::make_shared<WalletGo::Token>(tokens.at(accountAndBalance.first)), accountAndBalance.second);
|
||||||
|
m_assets->push_back(asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
qWarning() << "Failed fetching balances for account" << address.get() << "; balances count" << accountBalances.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AccountAssetsController::isTokenEnabled(const StatusGo::Wallet::Token& token) const
|
||||||
|
{
|
||||||
|
return find_if(m_enabledTokens.begin(), m_enabledTokens.end(), [&token](const auto& symbol) {
|
||||||
|
return token.symbol == symbol;
|
||||||
|
}) != m_enabledTokens.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractItemModel* AccountAssetsController::assetsModel() const
|
||||||
|
{
|
||||||
|
return m_assets.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
float AccountAssetsController::totalValue() const
|
||||||
|
{
|
||||||
|
return m_totalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AccountAssetsController::assetsReady() const
|
||||||
|
{
|
||||||
|
return m_assetsReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace Status::Wallet {
|
namespace Status::Wallet {
|
||||||
|
|
||||||
DerivedWalletAddress::DerivedWalletAddress(GoWallet::DerivedAddress address, QObject *parent)
|
DerivedWalletAddress::DerivedWalletAddress(WalletGo::DerivedAddress address, QObject *parent)
|
||||||
: QObject{parent}
|
: QObject{parent}
|
||||||
, m_derivedAddress{std::move(address)}
|
, m_derivedAddress{std::move(address)}
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
namespace GoAccounts = Status::StatusGo::Accounts;
|
namespace GoAccounts = Status::StatusGo::Accounts;
|
||||||
namespace GoWallet = Status::StatusGo::Wallet;
|
namespace WalletGo = Status::StatusGo::Wallet;
|
||||||
namespace UtilsSG = Status::StatusGo::Utils;
|
namespace UtilsSG = Status::StatusGo::Utils;
|
||||||
namespace StatusGo = Status::StatusGo;
|
namespace StatusGo = Status::StatusGo;
|
||||||
|
|
||||||
|
@ -31,7 +31,6 @@ NewWalletAccountController::NewWalletAccountController(std::shared_ptr<Helpers::
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QAbstractListModel* NewWalletAccountController::mainAccountsModel()
|
QAbstractListModel* NewWalletAccountController::mainAccountsModel()
|
||||||
{
|
{
|
||||||
return &m_mainAccounts;
|
return &m_mainAccounts;
|
||||||
|
@ -107,7 +106,7 @@ bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString
|
||||||
auto maxPageCount = static_cast<int>(std::ceil(static_cast<double>(m_maxDerivedAddresses)/static_cast<double>(m_derivedAddressesPageSize)));
|
auto maxPageCount = static_cast<int>(std::ceil(static_cast<double>(m_maxDerivedAddresses)/static_cast<double>(m_derivedAddressesPageSize)));
|
||||||
std::shared_ptr<DerivedWalletAddress> foundEntry;
|
std::shared_ptr<DerivedWalletAddress> foundEntry;
|
||||||
while(currentPage <= maxPageCount && foundIndex < 0) {
|
while(currentPage <= maxPageCount && foundIndex < 0) {
|
||||||
auto all = GoWallet::getDerivedAddressesForPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)),
|
auto all = WalletGo::getDerivedAddressesForPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)),
|
||||||
derivedFrom->data().derivedFrom.value(),
|
derivedFrom->data().derivedFrom.value(),
|
||||||
Status::Constants::General::PathWalletRoot,
|
Status::Constants::General::PathWalletRoot,
|
||||||
m_derivedAddressesPageSize, currentPage);
|
m_derivedAddressesPageSize, currentPage);
|
||||||
|
@ -115,7 +114,7 @@ bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString
|
||||||
m_derivedAddress.resize(currentIndex + all.size());
|
m_derivedAddress.resize(currentIndex + all.size());
|
||||||
|
|
||||||
for(auto newDerived : all) {
|
for(auto newDerived : all) {
|
||||||
auto newEntry = std::make_shared<DerivedWalletAddress>(std::move(newDerived));
|
auto newEntry = Helpers::makeSharedQObject<DerivedWalletAddress>(std::move(newDerived));
|
||||||
m_derivedAddress.set(currentIndex, newEntry);
|
m_derivedAddress.set(currentIndex, newEntry);
|
||||||
if(foundIndex < 0 && !newEntry->data().alreadyCreated) {
|
if(foundIndex < 0 && !newEntry->data().alreadyCreated) {
|
||||||
foundIndex = currentIndex;
|
foundIndex = currentIndex;
|
||||||
|
@ -147,7 +146,7 @@ WalletAccountPtr NewWalletAccountController::findMissingAccount()
|
||||||
return std::none_of(m_accounts->objects().begin(), m_accounts->objects().end(),
|
return std::none_of(m_accounts->objects().begin(), m_accounts->objects().end(),
|
||||||
[&a](const auto &eA) { return a.address == eA->data().address; });
|
[&a](const auto &eA) { return a.address == eA->data().address; });
|
||||||
});
|
});
|
||||||
return it != accounts.end() ? std:: make_shared<WalletAccount>(*it) : nullptr;
|
return it != accounts.end() ? Helpers::makeSharedQObject<WalletAccount>(*it) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
NewWalletAccountController::AccountsModel::ObjectContainer
|
NewWalletAccountController::AccountsModel::ObjectContainer
|
||||||
|
|
|
@ -13,7 +13,7 @@ const QString &WalletAccount::name() const
|
||||||
return m_data.name;
|
return m_data.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString &WalletAccount::address() const
|
const QString &WalletAccount::strAddress() const
|
||||||
{
|
{
|
||||||
return m_data.address.get();
|
return m_data.address.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "WalletAsset.h"
|
||||||
|
|
||||||
|
#include <boost/multiprecision/number.hpp>
|
||||||
|
|
||||||
|
namespace Status::Wallet {
|
||||||
|
|
||||||
|
WalletAsset::WalletAsset(const WalletGo::TokenPtr token, StatusGo::Wallet::BigInt balance, QObject *parent)
|
||||||
|
: QObject{parent}
|
||||||
|
, m_token(token)
|
||||||
|
, m_balance(std::move(balance))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString WalletAsset::name() const
|
||||||
|
{
|
||||||
|
return m_token ? m_token->name : u""_qs;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString WalletAsset::symbol() const
|
||||||
|
{
|
||||||
|
return m_token ? m_token->symbol : u""_qs;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QColor WalletAsset::color() const
|
||||||
|
{
|
||||||
|
return m_token ? m_token->color : QColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 WalletAsset::count() const
|
||||||
|
{
|
||||||
|
return (m_token)
|
||||||
|
? static_cast<quint64>(m_balance/boost::multiprecision::pow(WalletGo::BigInt(10), m_token->decimals))
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float WalletAsset::value() const
|
||||||
|
{
|
||||||
|
if(m_token) {
|
||||||
|
const int mantissaDigits = m_token->decimals > 3 ? 3 : 0;
|
||||||
|
const auto scale = 10 * mantissaDigits;
|
||||||
|
return static_cast<float>((m_balance*scale)/boost::multiprecision::pow(WalletGo::BigInt(10), m_token->decimals))/scale;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
#include "Status/Wallet/WalletController.h"
|
#include "Status/Wallet/WalletController.h"
|
||||||
|
|
||||||
#include "NewWalletAccountController.h"
|
#include "NewWalletAccountController.h"
|
||||||
|
#include "AccountAssetsController.h"
|
||||||
|
|
||||||
#include <StatusGo/Wallet/WalletApi.h>
|
#include <StatusGo/Wallet/WalletApi.h>
|
||||||
|
|
||||||
|
@ -16,14 +18,14 @@
|
||||||
#include <QJSEngine>
|
#include <QJSEngine>
|
||||||
|
|
||||||
namespace GoAccounts = Status::StatusGo::Accounts;
|
namespace GoAccounts = Status::StatusGo::Accounts;
|
||||||
namespace GoWallet = Status::StatusGo::Wallet;
|
namespace WalletGo = Status::StatusGo::Wallet;
|
||||||
namespace UtilsSG = Status::StatusGo::Utils;
|
namespace UtilsSG = Status::StatusGo::Utils;
|
||||||
namespace StatusGo = Status::StatusGo;
|
namespace StatusGo = Status::StatusGo;
|
||||||
|
|
||||||
namespace Status::Wallet {
|
namespace Status::Wallet {
|
||||||
|
|
||||||
WalletController::WalletController()
|
WalletController::WalletController()
|
||||||
: m_accounts(std::make_shared<AccountsModel>(std::move(getWalletAccounts()), "account"))
|
: m_accounts(Helpers::makeSharedQObject<AccountsModel>(std::move(getWalletAccounts()), "account"))
|
||||||
, m_currentAccount(m_accounts->get(0))
|
, m_currentAccount(m_accounts->get(0))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -60,13 +62,18 @@ void WalletController::setCurrentAccountIndex(int index)
|
||||||
emit currentAccountChanged();
|
emit currentAccountChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AccountAssetsController *WalletController::createAccountAssetsController(WalletAccount *account)
|
||||||
|
{
|
||||||
|
return new AccountAssetsController(account);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<WalletAccountPtr> WalletController::getWalletAccounts(bool rootWalletAccountsOnly) const
|
std::vector<WalletAccountPtr> WalletController::getWalletAccounts(bool rootWalletAccountsOnly) const
|
||||||
{
|
{
|
||||||
auto all = GoAccounts::getAccounts();
|
auto all = GoAccounts::getAccounts();
|
||||||
std::vector<WalletAccountPtr> result;
|
std::vector<WalletAccountPtr> result;
|
||||||
for(auto account : all) {
|
for(auto account : all) {
|
||||||
if(!account.isChat && (!rootWalletAccountsOnly || account.isWallet))
|
if(!account.isChat && (!rootWalletAccountsOnly || account.isWallet))
|
||||||
result.push_back(std::make_shared<WalletAccount>(std::move(account)));
|
result.push_back(Helpers::makeSharedQObject<WalletAccount>(std::move(account)));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include <StatusGo/Accounts/AccountsAPI.h>
|
#include <StatusGo/Accounts/AccountsAPI.h>
|
||||||
|
|
||||||
#include <StatusGo/Wallet/WalletApi.h>
|
#include <StatusGo/Wallet/WalletApi.h>
|
||||||
|
|
||||||
#include <StatusGo/Metadata/api_response.h>
|
#include <StatusGo/Metadata/api_response.h>
|
||||||
|
|
||||||
#include <Onboarding/Accounts/AccountsServiceInterface.h>
|
#include <Onboarding/Accounts/AccountsServiceInterface.h>
|
||||||
|
@ -223,14 +225,14 @@ TEST(WalletApi, TestGetTokensBalancesForChainIDs)
|
||||||
ASSERT_GT(balances.size(), 0);
|
ASSERT_GT(balances.size(), 0);
|
||||||
|
|
||||||
ASSERT_TRUE(balances.contains(testAddress));
|
ASSERT_TRUE(balances.contains(testAddress));
|
||||||
const auto &addressBallance = balances[testAddress];
|
const auto &addressBalance = balances[testAddress];
|
||||||
ASSERT_GT(addressBallance.size(), 0);
|
ASSERT_GT(addressBalance.size(), 0);
|
||||||
|
|
||||||
ASSERT_TRUE(addressBallance.contains(sntMain.address));
|
ASSERT_TRUE(addressBalance.contains(sntMain.address));
|
||||||
ASSERT_EQ(toQString(addressBallance.at(sntMain.address)), "0");
|
ASSERT_EQ(toQString(addressBalance.at(sntMain.address)), "0");
|
||||||
|
|
||||||
ASSERT_TRUE(addressBallance.contains(sntTest.address));
|
ASSERT_TRUE(addressBalance.contains(sntTest.address));
|
||||||
ASSERT_EQ(toQString(addressBallance.at(sntTest.address)), "0");
|
ASSERT_EQ(toQString(addressBalance.at(sntTest.address)), "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(WalletApi, TestGetTokensBalancesForChainIDs_WatchOnlyAccount)
|
TEST(WalletApi, TestGetTokensBalancesForChainIDs_WatchOnlyAccount)
|
||||||
|
@ -267,11 +269,14 @@ TEST(WalletApi, TestGetTokensBalancesForChainIDs_WatchOnlyAccount)
|
||||||
ASSERT_GT(balances.size(), 0);
|
ASSERT_GT(balances.size(), 0);
|
||||||
|
|
||||||
ASSERT_TRUE(balances.contains(newAccount.address));
|
ASSERT_TRUE(balances.contains(newAccount.address));
|
||||||
const auto &addressBallance = balances[newAccount.address];
|
const auto &addressBalance = balances[newAccount.address];
|
||||||
ASSERT_GT(addressBallance.size(), 0);
|
ASSERT_GT(addressBalance.size(), 0);
|
||||||
|
|
||||||
ASSERT_TRUE(addressBallance.contains(sntMain.address));
|
ASSERT_TRUE(addressBalance.contains(sntMain.address));
|
||||||
ASSERT_GT(addressBallance.at(sntMain.address), 0);
|
ASSERT_GT(addressBalance.at(sntMain.address), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// "{"jsonrpc":"2.0","id":0,"error":{"code":-32000,"message":"no tokens for this network"}}"
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue