feat(lite): M3 — new-address generation + sync-indicator confirmation
- LiteWalletController::newAddress(shielded) runs the backend "new" command ("zs"/"R" ->
do_new_address), parses the ["addr"] response, and returns the new address; the next
refresh lists it. Fast (local derivation), safe on the UI thread.
- fake_lite_backend returns ["zs1fakenew"]/["R1fakenew"] for "new" by args.
- testLiteWalletControllerNewAddress covers shielded/transparent + no-wallet error.
Also confirmed (no code needed): the sync-progress indicator already works for lite —
balance_tab reads state.sync.* which M2b-3 populates. Per-address balances landed in M2.
Remaining M3 is pure UI wiring (receive_tab button -> newAddress, loading/empty states),
which isn't verifiable without a GUI session.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -58,8 +58,12 @@ inline char* liteFakeInitFromPhrase(bool, const char*, const char*,
|
||||
return liteFakeDup("{\"result\":\"restored\"}");
|
||||
}
|
||||
inline char* liteFakeInitExisting(bool, const char*) { return liteFakeDup("{\"result\":\"opened\"}"); }
|
||||
inline char* liteFakeExecute(const char* command, const char*)
|
||||
inline char* liteFakeExecute(const char* command, const char* args)
|
||||
{
|
||||
// new-address generation returns a JSON array with the new address (type from args: zs/R).
|
||||
if (command && std::strcmp(command, "new") == 0) {
|
||||
return liteFakeDup(args && std::strcmp(args, "R") == 0 ? "[\"R1fakenew\"]" : "[\"zs1fakenew\"]");
|
||||
}
|
||||
// A command named "boom" yields an "Error:"-prefixed response (the bridge's
|
||||
// looksLikeError contract maps that to ok=false).
|
||||
if (command && std::strcmp(command, "boom") == 0) {
|
||||
|
||||
@@ -4718,6 +4718,30 @@ void testLitePerAddressBalances()
|
||||
EXPECT_NEAR(state.t_addresses[0].balance, 0.5, 1e-9); // 50000000
|
||||
}
|
||||
|
||||
// M3: new-address generation via the controller (backend "new" zs/R) returns the address.
|
||||
void testLiteWalletControllerNewAddress()
|
||||
{
|
||||
using namespace dragonx::wallet;
|
||||
const auto caps = makeWalletCapabilities(WalletBuildKind::Lite, /*embeddedDaemon*/ false, /*liteBackendLinked*/ true);
|
||||
const auto conn = defaultLiteConnectionSettings();
|
||||
|
||||
LiteWalletController controller(caps, conn, LiteClientBridge::fromApi(dragonx::test::makeFakeLiteApi()));
|
||||
EXPECT_TRUE(controller.createWallet(LiteWalletCreateRequest{}).walletReady);
|
||||
|
||||
const auto z = controller.newAddress(/*shielded*/ true);
|
||||
EXPECT_TRUE(z.ok);
|
||||
EXPECT_TRUE(z.address.rfind("zs1", 0) == 0);
|
||||
|
||||
const auto t = controller.newAddress(/*shielded*/ false);
|
||||
EXPECT_TRUE(t.ok);
|
||||
EXPECT_TRUE(t.address.rfind("R1", 0) == 0);
|
||||
|
||||
// No wallet open -> error, no address.
|
||||
LiteWalletController idle(caps, conn, LiteClientBridge::fromApi(dragonx::test::makeFakeLiteApi()));
|
||||
const auto none = idle.newAddress(true);
|
||||
EXPECT_FALSE(none.ok);
|
||||
}
|
||||
|
||||
// Gateway hardening: one command's parse failure must not abort the whole refresh — the
|
||||
// other commands still populate the bundle (graceful degradation against real-shape drift).
|
||||
void testLiteWalletGatewayRefreshSkipsFailedCommand()
|
||||
@@ -4841,6 +4865,7 @@ int main()
|
||||
testLiteChainNameMigration();
|
||||
testLiteRefreshModelAppliesToWalletState();
|
||||
testLitePerAddressBalances();
|
||||
testLiteWalletControllerNewAddress();
|
||||
testLiteSyncStatusParserRealShapes();
|
||||
testLiteWalletControllerRefreshPopulatesState();
|
||||
testLiteWalletGatewayRefreshSkipsFailedCommand();
|
||||
|
||||
Reference in New Issue
Block a user