diff --git a/apps/amm/src/AmmUiBackend.cpp b/apps/amm/src/AmmUiBackend.cpp index c2e75a6..fbe6a92 100644 --- a/apps/amm/src/AmmUiBackend.cpp +++ b/apps/amm/src/AmmUiBackend.cpp @@ -1,248 +1,86 @@ #include "AmmUiBackend.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "LogosWalletProvider.h" +#include "WalletController.h" #include "logos_api.h" -namespace { -const char SETTINGS_ORG[] = "Logos"; -const char SETTINGS_APP[] = "AmmUI"; -const char DISCONNECTED_KEY[] = "disconnected"; -const char WALLET_HOME_ENV[] = "LEE_WALLET_HOME_DIR"; - -QString toLocalPath(const QString& path) -{ - if (path.startsWith(QStringLiteral("file://")) || path.contains(QLatin1Char('/'))) - return QUrl::fromUserInput(path).toLocalFile(); - return path; -} -} - -QString AmmUiBackend::defaultWalletHome() -{ - const QByteArray override = qgetenv(WALLET_HOME_ENV); - if (!override.isEmpty()) - return QString::fromLocal8Bit(override); - return QDir::homePath() + QStringLiteral("/.lee/wallet"); -} - -QString AmmUiBackend::defaultConfigPath() const -{ - return defaultWalletHome() + QStringLiteral("/wallet_config.json"); -} - -QString AmmUiBackend::defaultStoragePath() const -{ - return defaultWalletHome() + QStringLiteral("/storage.json"); -} - AmmUiBackend::AmmUiBackend(LogosAPI* logosAPI, QObject* parent) : AmmUiBackendSimpleSource(parent), - m_accountModel(new WalletAccountModel(this)), m_logosAPI(logosAPI ? logosAPI : new LogosAPI("amm_ui", this)), m_wallet(std::make_unique(m_logosAPI)), - m_net(new QNetworkAccessManager(this)), - m_reachabilityTimer(new QTimer(this)) + m_walletController(std::make_unique( + *m_wallet, QStringLiteral("AmmUI"))) { - setIsWalletOpen(false); - setLastSyncedBlock(0); - setCurrentBlockHeight(0); - setWalletHome(defaultWalletHome()); - setSequencerReachable(true); - setWalletExists(QFileInfo::exists(defaultStoragePath())); - - m_reachabilityTimer->setInterval(10000); - connect(m_reachabilityTimer, &QTimer::timeout, - this, &AmmUiBackend::checkReachability); - m_reachabilityTimer->start(); - - QTimer::singleShot(0, this, &AmmUiBackend::openOrAdoptWallet); + connect(m_walletController.get(), &WalletController::stateChanged, + this, &AmmUiBackend::syncWalletState); + syncWalletState(); + m_walletController->start(); } AmmUiBackend::~AmmUiBackend() = default; -void AmmUiBackend::openOrAdoptWallet() +WalletAccountModel* AmmUiBackend::accountModel() const { - if (QSettings(SETTINGS_ORG, SETTINGS_APP).value(DISCONNECTED_KEY, false).toBool()) - return; + return m_walletController->accountModel(); +} - const QString config = defaultConfigPath(); - const QString storage = defaultStoragePath(); - const WalletSession session = m_wallet->connect({ config, storage }); - if (session.failure == WalletFailure::WalletMissing) - return; - if (!session.ok()) { - qWarning() << "AmmUiBackend: wallet connection failed" - << walletFailureCode(session.failure); - return; - } +QString AmmUiBackend::createAccountPublic() +{ + return m_walletController->createAccount(true); +} - persistConfigPath(config); - persistStoragePath(storage); - setWalletExists(QFileInfo::exists(storage) || session.adopted); - setIsWalletOpen(true); - applySnapshot(session.snapshot); +QString AmmUiBackend::createAccountPrivate() +{ + return m_walletController->createAccount(false); +} + +void AmmUiBackend::refreshAccounts() +{ + m_walletController->refresh(); +} + +void AmmUiBackend::refreshBalances() +{ + m_walletController->refresh(); +} + +QString AmmUiBackend::getBalance(QString accountIdHex, bool isPublic) +{ + return m_walletController->balance(accountIdHex, isPublic); } QString AmmUiBackend::createNewDefault(QString password) { - return createNew(defaultConfigPath(), defaultStoragePath(), password); + return m_walletController->createDefaultWallet(password); } QString AmmUiBackend::createNew(QString configPath, QString storagePath, QString password) { - const QString config = toLocalPath(configPath); - const QString storage = toLocalPath(storagePath); - const WalletCreation creation = m_wallet->createWallet( - { config, storage }, password); - if (creation.mnemonic.isEmpty()) { - qWarning() << "AmmUiBackend: wallet creation failed" - << walletFailureCode(creation.failure); - return {}; - } - - persistConfigPath(config); - persistStoragePath(storage); - setWalletExists(true); - QSettings(SETTINGS_ORG, SETTINGS_APP).setValue(DISCONNECTED_KEY, false); - if (!creation.ok()) { - qWarning() << "AmmUiBackend: wallet creation failed" - << walletFailureCode(creation.failure); - return creation.mnemonic; - } - - setIsWalletOpen(true); - applySnapshot(creation.snapshot); - return creation.mnemonic; + return m_walletController->createWallet(configPath, storagePath, password); } bool AmmUiBackend::openExisting() { - const QString config = configPath().isEmpty() ? defaultConfigPath() : configPath(); - const QString storage = storagePath().isEmpty() ? defaultStoragePath() : storagePath(); - const WalletSession session = m_wallet->connect({ config, storage }); - if (!session.ok()) { - qWarning() << "AmmUiBackend: wallet open failed" - << walletFailureCode(session.failure); - return false; - } - - persistConfigPath(config); - persistStoragePath(storage); - setWalletExists(true); - setIsWalletOpen(true); - QSettings(SETTINGS_ORG, SETTINGS_APP).setValue(DISCONNECTED_KEY, false); - applySnapshot(session.snapshot); - return true; + return m_walletController->open(); } void AmmUiBackend::disconnectWallet() { - m_wallet->disconnect(); - setIsWalletOpen(false); - m_accountModel->replaceAccounts({}); - QSettings(SETTINGS_ORG, SETTINGS_APP).setValue(DISCONNECTED_KEY, true); + m_walletController->disconnect(); } -QString AmmUiBackend::createAccountPublic() +void AmmUiBackend::syncWalletState() { - const WalletAccountCreation creation = m_wallet->createAccount(true); - if (!creation.ok()) { - qWarning() << "AmmUiBackend: public account creation failed" - << walletFailureCode(creation.failure); - return {}; - } - if (creation.snapshot.ok()) - applySnapshot(creation.snapshot); - else - qWarning() << "AmmUiBackend: account refresh failed" - << walletFailureCode(creation.snapshot.failure); - return creation.accountId; -} - -QString AmmUiBackend::createAccountPrivate() -{ - const WalletAccountCreation creation = m_wallet->createAccount(false); - if (!creation.ok()) { - qWarning() << "AmmUiBackend: private account creation failed" - << walletFailureCode(creation.failure); - return {}; - } - if (creation.snapshot.ok()) - applySnapshot(creation.snapshot); - else - qWarning() << "AmmUiBackend: account refresh failed" - << walletFailureCode(creation.snapshot.failure); - return creation.accountId; -} - -void AmmUiBackend::refreshAccounts() -{ - const WalletSnapshot next = m_wallet->snapshot(true); - if (next.ok()) - applySnapshot(next); - else - qWarning() << "AmmUiBackend: wallet refresh failed" - << walletFailureCode(next.failure); -} - -void AmmUiBackend::refreshBalances() -{ - refreshAccounts(); -} - -QString AmmUiBackend::getBalance(QString accountIdHex, bool isPublic) -{ - const WalletSnapshot current = m_wallet->snapshot(); - for (const WalletAccount& account : current.accounts) { - if (account.address == accountIdHex && account.isPublic == isPublic) - return account.balance; - } - return {}; -} - -void AmmUiBackend::applySnapshot(const WalletSnapshot& snapshot) -{ - m_accountModel->replaceAccounts(snapshot.accounts); - setLastSyncedBlock(static_cast(snapshot.lastSyncedBlock)); - setCurrentBlockHeight(static_cast(snapshot.currentBlockHeight)); - setSequencerAddr(snapshot.sequencerAddress); - checkReachability(); -} - -void AmmUiBackend::checkReachability() -{ - if (sequencerAddr().isEmpty()) - return; - - QNetworkRequest request{QUrl(sequencerAddr())}; - request.setTransferTimeout(4000); - QNetworkReply* reply = m_net->get(request); - connect(reply, &QNetworkReply::finished, this, [this, reply]() { - const bool receivedHttp = - reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isValid(); - setSequencerReachable(receivedHttp || reply->error() == QNetworkReply::NoError); - reply->deleteLater(); - }); -} - -void AmmUiBackend::persistConfigPath(const QString& path) -{ - setConfigPath(toLocalPath(path)); -} - -void AmmUiBackend::persistStoragePath(const QString& path) -{ - setStoragePath(toLocalPath(path)); + const WalletUiState& state = m_walletController->state(); + setIsWalletOpen(state.isWalletOpen); + setWalletExists(state.walletExists); + setConfigPath(state.configPath); + setStoragePath(state.storagePath); + setWalletHome(state.walletHome); + setLastSyncedBlock(state.lastSyncedBlock); + setCurrentBlockHeight(state.currentBlockHeight); + setSequencerAddr(state.sequencerAddress); + setSequencerReachable(state.sequencerReachable); } diff --git a/apps/amm/src/AmmUiBackend.h b/apps/amm/src/AmmUiBackend.h index 48f370a..99fa7e0 100644 --- a/apps/amm/src/AmmUiBackend.h +++ b/apps/amm/src/AmmUiBackend.h @@ -11,8 +11,7 @@ class LogosAPI; class LogosWalletProvider; -class QNetworkAccessManager; -class QTimer; +class WalletController; class AmmUiBackend : public AmmUiBackendSimpleSource { Q_OBJECT @@ -22,7 +21,7 @@ public: explicit AmmUiBackend(LogosAPI* logosAPI = nullptr, QObject* parent = nullptr); ~AmmUiBackend() override; - WalletAccountModel* accountModel() const { return m_accountModel; } + WalletAccountModel* accountModel() const; public slots: QString createAccountPublic() override; @@ -36,21 +35,11 @@ public slots: void disconnectWallet() override; private: - static QString defaultWalletHome(); - QString defaultConfigPath() const; - QString defaultStoragePath() const; + void syncWalletState(); - void persistConfigPath(const QString& path); - void persistStoragePath(const QString& path); - void openOrAdoptWallet(); - void applySnapshot(const WalletSnapshot& snapshot); - void checkReachability(); - - WalletAccountModel* m_accountModel; LogosAPI* m_logosAPI; std::unique_ptr m_wallet; - QNetworkAccessManager* m_net; - QTimer* m_reachabilityTimer; + std::unique_ptr m_walletController; }; #endif // AMM_UI_BACKEND_H diff --git a/apps/shared/wallet/CMakeLists.txt b/apps/shared/wallet/CMakeLists.txt index 5c5403f..37f1663 100644 --- a/apps/shared/wallet/CMakeLists.txt +++ b/apps/shared/wallet/CMakeLists.txt @@ -18,6 +18,9 @@ if(LOGOS_WALLET_BUILD_ACCESS endif() find_package(Qt6 6.8 REQUIRED COMPONENTS Core) +if(LOGOS_WALLET_BUILD_ACCESS OR BUILD_TESTING) + find_package(Qt6 6.8 REQUIRED COMPONENTS Network) +endif() set(CMAKE_AUTOMOC ON) if(LOGOS_WALLET_BUILD_ACCESS) @@ -28,6 +31,8 @@ if(LOGOS_WALLET_BUILD_ACCESS) src/LogosWalletProvider.cpp src/WalletAccountModel.h src/WalletAccountModel.cpp + src/WalletController.h + src/WalletController.cpp ) set_target_properties(logos_wallet_access PROPERTIES AUTOMOC ON @@ -41,7 +46,10 @@ if(LOGOS_WALLET_BUILD_ACCESS) "${LOGOS_WALLET_GENERATED_DIR}" "${LOGOS_WALLET_GENERATED_DIR}/include" ) - target_link_libraries(logos_wallet_access PUBLIC Qt6::Core) + target_link_libraries(logos_wallet_access + PUBLIC Qt6::Core + PRIVATE Qt6::Network + ) endif() if(LOGOS_WALLET_BUILD_QML) @@ -127,6 +135,8 @@ if(BUILD_TESTING) src/LogosWalletProvider.cpp src/WalletAccountModel.cpp src/WalletAccountModel.h + src/WalletController.cpp + src/WalletController.h ) set_target_properties(logos_wallet_access_test PROPERTIES AUTOMOC ON) target_compile_features(logos_wallet_access_test PRIVATE cxx_std_17) @@ -135,7 +145,11 @@ if(BUILD_TESTING) tests/support src ) - target_link_libraries(logos_wallet_access_test PRIVATE Qt6::Core Qt6::Test) + target_link_libraries(logos_wallet_access_test PRIVATE + Qt6::Core + Qt6::Network + Qt6::Test + ) add_test(NAME logos_wallet_access COMMAND logos_wallet_access_test) if(LOGOS_WALLET_BUILD_QML) diff --git a/apps/shared/wallet/src/WalletController.cpp b/apps/shared/wallet/src/WalletController.cpp new file mode 100644 index 0000000..487daa8 --- /dev/null +++ b/apps/shared/wallet/src/WalletController.cpp @@ -0,0 +1,234 @@ +#include "WalletController.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "WalletAccountModel.h" + +namespace { +const char SETTINGS_ORG[] = "Logos"; +const char DISCONNECTED_KEY[] = "disconnected"; +const char WALLET_HOME_ENV[] = "LEE_WALLET_HOME_DIR"; + +QString toLocalPath(const QString& path) +{ + if (path.startsWith(QStringLiteral("file://")) || path.contains(QLatin1Char('/'))) + return QUrl::fromUserInput(path).toLocalFile(); + return path; +} +} + +WalletController::WalletController(WalletProvider& wallet, + QString settingsApplication, + QObject* parent) + : QObject(parent), + m_wallet(wallet), + m_settingsApplication(std::move(settingsApplication)), + m_accountModel(new WalletAccountModel(this)), + m_network(new QNetworkAccessManager(this)), + m_reachabilityTimer(new QTimer(this)) +{ + m_state.walletHome = defaultWalletHome(); + m_state.walletExists = QFileInfo::exists(defaultStoragePath()); + + m_reachabilityTimer->setInterval(10000); + connect(m_reachabilityTimer, &QTimer::timeout, + this, &WalletController::checkReachability); +} + +WalletController::~WalletController() = default; + +QString WalletController::defaultWalletHome() +{ + const QByteArray override = qgetenv(WALLET_HOME_ENV); + if (!override.isEmpty()) + return QString::fromLocal8Bit(override); + return QDir::homePath() + QStringLiteral("/.lee/wallet"); +} + +QString WalletController::defaultConfigPath() const +{ + return m_state.walletHome + QStringLiteral("/wallet_config.json"); +} + +QString WalletController::defaultStoragePath() const +{ + return m_state.walletHome + QStringLiteral("/storage.json"); +} + +void WalletController::start() +{ + if (m_started) + return; + m_started = true; + m_reachabilityTimer->start(); + QTimer::singleShot(0, this, &WalletController::openOnStartup); +} + +void WalletController::openOnStartup() +{ + if (QSettings(SETTINGS_ORG, m_settingsApplication) + .value(DISCONNECTED_KEY, false).toBool()) { + return; + } + + const QString config = defaultConfigPath(); + const QString storage = defaultStoragePath(); + const WalletSession session = m_wallet.connect({ config, storage }); + if (session.failure == WalletFailure::WalletMissing) + return; + if (!session.ok()) { + qWarning() << "WalletController: wallet connection failed" + << walletFailureCode(session.failure); + return; + } + + m_state.configPath = config; + m_state.storagePath = storage; + m_state.walletExists = QFileInfo::exists(storage) || session.adopted; + m_state.isWalletOpen = true; + applySnapshot(session.snapshot); +} + +QString WalletController::createDefaultWallet(const QString& password) +{ + return createWallet(defaultConfigPath(), defaultStoragePath(), password); +} + +QString WalletController::createWallet(const QString& configPath, + const QString& storagePath, + const QString& password) +{ + const QString config = toLocalPath(configPath); + const QString storage = toLocalPath(storagePath); + const WalletCreation creation = m_wallet.createWallet( + { config, storage }, password); + if (creation.mnemonic.isEmpty()) { + qWarning() << "WalletController: wallet creation failed" + << walletFailureCode(creation.failure); + return {}; + } + + m_state.configPath = config; + m_state.storagePath = storage; + m_state.walletExists = true; + QSettings(SETTINGS_ORG, m_settingsApplication).setValue(DISCONNECTED_KEY, false); + if (!creation.ok()) { + qWarning() << "WalletController: wallet creation failed" + << walletFailureCode(creation.failure); + emit stateChanged(); + return creation.mnemonic; + } + + m_state.isWalletOpen = true; + applySnapshot(creation.snapshot); + return creation.mnemonic; +} + +bool WalletController::open() +{ + const QString config = m_state.configPath.isEmpty() + ? defaultConfigPath() : m_state.configPath; + const QString storage = m_state.storagePath.isEmpty() + ? defaultStoragePath() : m_state.storagePath; + const WalletSession session = m_wallet.connect({ config, storage }); + if (!session.ok()) { + qWarning() << "WalletController: wallet open failed" + << walletFailureCode(session.failure); + return false; + } + + m_state.configPath = config; + m_state.storagePath = storage; + m_state.walletExists = true; + m_state.isWalletOpen = true; + QSettings(SETTINGS_ORG, m_settingsApplication).setValue(DISCONNECTED_KEY, false); + applySnapshot(session.snapshot); + return true; +} + +void WalletController::disconnect() +{ + m_wallet.disconnect(); + m_state.isWalletOpen = false; + m_accountModel->replaceAccounts({}); + QSettings(SETTINGS_ORG, m_settingsApplication).setValue(DISCONNECTED_KEY, true); + emit stateChanged(); +} + +QString WalletController::createAccount(bool isPublic) +{ + const WalletAccountCreation creation = m_wallet.createAccount(isPublic); + if (!creation.ok()) { + qWarning() << "WalletController: account creation failed" + << walletFailureCode(creation.failure); + return {}; + } + if (creation.snapshot.ok()) { + applySnapshot(creation.snapshot); + } else { + qWarning() << "WalletController: account refresh failed" + << walletFailureCode(creation.snapshot.failure); + } + return creation.accountId; +} + +void WalletController::refresh() +{ + const WalletSnapshot next = m_wallet.snapshot(true); + if (next.ok()) { + applySnapshot(next); + } else { + qWarning() << "WalletController: wallet refresh failed" + << walletFailureCode(next.failure); + } +} + +QString WalletController::balance(const QString& accountId, bool isPublic) +{ + const WalletSnapshot current = m_wallet.snapshot(); + for (const WalletAccount& account : current.accounts) { + if (account.address == accountId && account.isPublic == isPublic) + return account.balance; + } + return {}; +} + +void WalletController::applySnapshot(const WalletSnapshot& snapshot) +{ + m_accountModel->replaceAccounts(snapshot.accounts); + m_state.lastSyncedBlock = static_cast(snapshot.lastSyncedBlock); + m_state.currentBlockHeight = static_cast(snapshot.currentBlockHeight); + m_state.sequencerAddress = snapshot.sequencerAddress; + emit stateChanged(); + checkReachability(); +} + +void WalletController::checkReachability() +{ + if (m_state.sequencerAddress.isEmpty()) + return; + + QNetworkRequest request{QUrl(m_state.sequencerAddress)}; + request.setTransferTimeout(4000); + QNetworkReply* reply = m_network->get(request); + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + const bool receivedHttp = + reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isValid(); + const bool reachable = receivedHttp || reply->error() == QNetworkReply::NoError; + if (m_state.sequencerReachable != reachable) { + m_state.sequencerReachable = reachable; + emit stateChanged(); + } + reply->deleteLater(); + }); +} diff --git a/apps/shared/wallet/src/WalletController.h b/apps/shared/wallet/src/WalletController.h new file mode 100644 index 0000000..c27f9ce --- /dev/null +++ b/apps/shared/wallet/src/WalletController.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include + +#include "WalletProvider.h" + +class QNetworkAccessManager; +class QTimer; +class WalletAccountModel; + +struct WalletUiState { + bool isWalletOpen = false; + bool walletExists = false; + QString configPath; + QString storagePath; + QString walletHome; + int lastSyncedBlock = 0; + int currentBlockHeight = 0; + QString sequencerAddress; + bool sequencerReachable = true; +}; + +class WalletController final : public QObject { + Q_OBJECT + +public: + // The provider must outlive the controller. + explicit WalletController(WalletProvider& wallet, + QString settingsApplication, + QObject* parent = nullptr); + ~WalletController() override; + + WalletAccountModel* accountModel() const { return m_accountModel; } + const WalletUiState& state() const { return m_state; } + + void start(); + QString createAccount(bool isPublic); + void refresh(); + QString balance(const QString& accountId, bool isPublic); + QString createDefaultWallet(const QString& password); + QString createWallet(const QString& configPath, + const QString& storagePath, + const QString& password); + bool open(); + void disconnect(); + +signals: + void stateChanged(); + +private: + static QString defaultWalletHome(); + QString defaultConfigPath() const; + QString defaultStoragePath() const; + + void openOnStartup(); + void applySnapshot(const WalletSnapshot& snapshot); + void checkReachability(); + + WalletProvider& m_wallet; + QString m_settingsApplication; + WalletUiState m_state; + WalletAccountModel* m_accountModel; + QNetworkAccessManager* m_network; + QTimer* m_reachabilityTimer; + bool m_started = false; +}; diff --git a/apps/shared/wallet/tests/cpp/LogosWalletProviderTest.cpp b/apps/shared/wallet/tests/cpp/LogosWalletProviderTest.cpp index 33672d9..f1cb44a 100644 --- a/apps/shared/wallet/tests/cpp/LogosWalletProviderTest.cpp +++ b/apps/shared/wallet/tests/cpp/LogosWalletProviderTest.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -8,6 +9,7 @@ #include "FakeWalletProvider.h" #include "LogosWalletProvider.h" #include "WalletAccountModel.h" +#include "WalletController.h" #include "logos_sdk.h" namespace { @@ -53,6 +55,7 @@ private slots: void rejectsInvalidSubmissionResponses(); void exposesStableAccountModelRoles(); void fakeProviderImplementsConsumerContract(); + void controllerOwnsUiWalletFlow(); }; void LogosWalletProviderTest::adoptsOpenWalletAndCachesSnapshots() @@ -362,6 +365,55 @@ void LogosWalletProviderTest::fakeProviderImplementsConsumerContract() QCOMPARE(provider.disconnectCalls, 1); } +void LogosWalletProviderTest::controllerOwnsUiWalletFlow() +{ + const QString settingsApplication = QStringLiteral("WalletControllerTest"); + QSettings settings(QStringLiteral("Logos"), settingsApplication); + settings.clear(); + + FakeWalletProvider provider; + provider.connectResult.snapshot.accounts = { + { ACCOUNT_A, QStringLiteral("5"), true }, + }; + provider.connectResult.snapshot.lastSyncedBlock = 7; + provider.connectResult.snapshot.currentBlockHeight = 8; + + WalletController controller(provider, settingsApplication); + QSignalSpy stateChanged(&controller, &WalletController::stateChanged); + + QVERIFY(controller.open()); + QCOMPARE(provider.connectCalls, 1); + QVERIFY(controller.state().isWalletOpen); + QVERIFY(controller.state().walletExists); + QCOMPARE(controller.state().lastSyncedBlock, 7); + QCOMPARE(controller.state().currentBlockHeight, 8); + QCOMPARE(controller.accountModel()->count(), 1); + + provider.snapshotResult.accounts = { + { ACCOUNT_A, QStringLiteral("9"), true }, + }; + controller.refresh(); + QVERIFY(provider.lastForceRefresh); + QCOMPARE(controller.balance(ACCOUNT_A, true), QStringLiteral("9")); + + provider.createAccountResult.accountId = ACCOUNT_B; + provider.createAccountResult.snapshot.accounts = { + { ACCOUNT_A, QStringLiteral("9"), true }, + { ACCOUNT_B, QStringLiteral("3"), false }, + }; + QCOMPARE(controller.createAccount(false), ACCOUNT_B); + QVERIFY(!provider.lastAccountWasPublic); + QCOMPARE(controller.accountModel()->count(), 2); + + controller.disconnect(); + QCOMPARE(provider.disconnectCalls, 1); + QVERIFY(!controller.state().isWalletOpen); + QCOMPARE(controller.accountModel()->count(), 0); + QVERIFY(stateChanged.count() >= 4); + + settings.clear(); +} + QTEST_GUILESS_MAIN(LogosWalletProviderTest) #include "LogosWalletProviderTest.moc"