feat(lite): lite wallet foundation (inherited working-tree state)

Preserve the previously-uncommitted lite wallet implementation and related dev WIP
under version control:
- src/wallet/ lite services: client bridge, bridge runtime, connection, lifecycle,
  sync, gateway, result parsers, state mapper, artifact contract/resolver, refresh
  services, UI adapters, wallet_backend/capabilities. (Includes two small M1 fixes:
  lifecycle walletReady now parses the response; default chain name -> "main".)
- src/chat/ chat protocol; tests/fixtures/ (lite + hushchat); tools/hushchat_fixture_check.cpp;
  scripts/build-lite-backend-artifact.sh.
- Pre-existing modified app_network/security/wizard, network_refresh_service, sidebar,
  mining_tab, bootstrap dialog, and version headers captured as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-04 21:15:28 -05:00
parent a78a13edf3
commit 863d015628
69 changed files with 39458 additions and 85 deletions

View File

@@ -0,0 +1,186 @@
// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#include "lite_client_bridge.h"
#include "lite_bridge_runtime.h"
#ifndef DRAGONX_ENABLE_LITE_BACKEND
#define DRAGONX_ENABLE_LITE_BACKEND 0
#endif
#if DRAGONX_ENABLE_LITE_BACKEND
extern "C" {
bool litelib_wallet_exists(const char* chain_name);
char* litelib_initialize_new(bool dangerous, const char* server);
char* litelib_initialize_new_from_phrase(bool dangerous,
const char* server,
const char* seed,
unsigned long long birthday,
unsigned long long number,
bool overwrite);
char* litelib_initialize_existing(bool dangerous, const char* server);
char* litelib_execute(const char* command, const char* args);
void litelib_rust_free_string(char* value);
bool litelib_check_server_online(const char* server);
void litelib_shutdown();
}
#endif
#include <utility>
namespace dragonx {
namespace wallet {
namespace {
bool hasRequiredApi(const LiteClientBridgeApi& api)
{
return api.walletExists &&
api.initializeNew &&
api.initializeNewFromPhrase &&
api.initializeExisting &&
api.execute &&
api.freeString &&
api.checkServerOnline &&
api.shutdown;
}
#if DRAGONX_ENABLE_LITE_BACKEND
LiteClientBridgeApi linkedSdxlApi()
{
return LiteClientBridgeApi{
&litelib_wallet_exists,
&litelib_initialize_new,
&litelib_initialize_new_from_phrase,
&litelib_initialize_existing,
&litelib_execute,
&litelib_rust_free_string,
&litelib_check_server_online,
&litelib_shutdown
};
}
#endif
} // namespace
LiteClientBridge::LiteClientBridge(LiteClientBridgeApi api, std::string unavailableReason)
: api_(api), unavailableReason_(std::move(unavailableReason))
{
}
LiteClientBridge LiteClientBridge::unavailable(std::string reason)
{
return LiteClientBridge({}, std::move(reason));
}
LiteClientBridge LiteClientBridge::fromApi(LiteClientBridgeApi api)
{
if (!hasRequiredApi(api)) {
return unavailable("lite client bridge API is incomplete");
}
return LiteClientBridge(api, {});
}
LiteClientBridge LiteClientBridge::linkedSdxl()
{
#if DRAGONX_ENABLE_LITE_BACKEND
return fromApi(linkedSdxlApi());
#else
return unavailable("lite backend is not linked");
#endif
}
LiteClientBridge::LiteClientBridge(LiteClientBridge&& other) noexcept
: api_(other.api_),
unavailableReason_(std::move(other.unavailableReason_)),
shutdownCalled_(other.shutdownCalled_)
{
other.api_ = {};
other.shutdownCalled_ = true;
}
LiteClientBridge& LiteClientBridge::operator=(LiteClientBridge&& other) noexcept
{
if (this == &other) return *this;
shutdown();
api_ = other.api_;
unavailableReason_ = std::move(other.unavailableReason_);
shutdownCalled_ = other.shutdownCalled_;
other.api_ = {};
other.shutdownCalled_ = true;
return *this;
}
LiteClientBridge::~LiteClientBridge()
{
shutdown();
}
bool LiteClientBridge::available() const
{
return hasRequiredApi(api_);
}
bool LiteClientBridge::walletExists(const std::string& chainName) const
{
if (!available()) return false;
return api_.walletExists(chainName.c_str());
}
bool LiteClientBridge::checkServerOnline(const std::string& server) const
{
if (!available()) return false;
return api_.checkServerOnline(server.c_str());
}
LiteBridgeStringResult LiteClientBridge::initializeNew(bool dangerous, const std::string& server)
{
if (!available()) return unavailableResult();
return takeOwnedString(api_.initializeNew(dangerous, server.c_str()));
}
LiteBridgeStringResult LiteClientBridge::initializeNewFromPhrase(bool dangerous,
const std::string& server,
const std::string& seed,
unsigned long long birthday,
unsigned long long account,
bool overwrite)
{
if (!available()) return unavailableResult();
return takeOwnedString(api_.initializeNewFromPhrase(
dangerous, server.c_str(), seed.c_str(), birthday, account, overwrite));
}
LiteBridgeStringResult LiteClientBridge::initializeExisting(bool dangerous, const std::string& server)
{
if (!available()) return unavailableResult();
return takeOwnedString(api_.initializeExisting(dangerous, server.c_str()));
}
LiteBridgeStringResult LiteClientBridge::execute(const std::string& command, const std::string& args)
{
if (!available()) return unavailableResult();
if (command.empty()) return {false, {}, "lite command is empty"};
return takeOwnedString(api_.execute(command.c_str(), args.c_str()));
}
void LiteClientBridge::shutdown()
{
if (shutdownCalled_) return;
shutdownCalled_ = true;
if (available()) api_.shutdown();
}
LiteBridgeStringResult LiteClientBridge::unavailableResult() const
{
return {false, {}, unavailableReason_.empty() ? "lite backend is unavailable" : unavailableReason_};
}
LiteBridgeStringResult LiteClientBridge::takeOwnedString(char* rawValue) const
{
return liteBridgeRuntimeTakeOwnedString(rawValue, api_.freeString);
}
} // namespace wallet
} // namespace dragonx