feat(wallet): migrate-to-seed, Phase 1 — isolated seed-wallet creation
First, fund-safe step of "migrate a legacy wallet to a seed wallet": mint a brand-new BIP39 mnemonic wallet in an ISOLATED throwaway datadir so the user can later sweep funds into it. No funds move and the real wallet.dat / main daemon are never touched — the isolated node runs concurrently on its own port. - EmbeddedDaemon: one-shot isolated-datadir override (setNextStartOverride) consumed on the next start(); a skip-default-port-check for an isolated instance beside the main daemon; and a tcpPortInUse() probe. The datadir's basename must be the assetchain name (DRAGONX) and the daemon reads <datadir>/DRAGONX.conf itself, so no -conf is passed (both learned from live testing against the hd-transparent-keys daemon). - SeedWalletCreator (src/daemon): picks a free port, writes a throwaway conf, starts an isolated dragonxd with -usemnemonic=1 -connect=0, waits for RPC, calls z_exportmnemonic + z_getnewaddress (the sweep target), stops it, and keeps/scrubs the temp datadir. Off-thread; the seed is wiped after use. - App: beginCreateSeedWallet (background) -> pumpSeedMigration (main-thread handoff) -> renderSeedMigrationDialog (Intro -> Working -> Show seed -> Error), reusing the seed_display grid + clipboard auto-clear. - Settings: "Migrate to seed…" button (full-node gated) + persisted pending migration state (dest address + temp datadir) for Phase 2 to adopt. Validated end-to-end against the hd-transparent-keys daemon: the isolated node comes up in ~4s and returns a 24-word mnemonic + a shielded z-address. Requires that daemon (the bundled Jun-28 build lacks z_exportmnemonic). The migration modal uses English literals for now (as renderBackupDialog does); the whole flow gets translated once Phase 2 finalizes it. Phase 2 (sweep + adopt) is next. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1304,10 +1304,11 @@ void RenderSettingsPage(App* app) {
|
||||
naturalW += ImGui::CalcTextSize(r1[i]).x + btnPadX;
|
||||
float wizW = showFullNodeLifecycleActions ? ImGui::CalcTextSize(wizLabel).x + btnPadX : 0.0f;
|
||||
float bsW = showFullNodeLifecycleActions ? ImGui::CalcTextSize(bsLabel).x + btnPadX : 0.0f;
|
||||
// Full-node-only "Seed phrase" button trails the Backup button (see below).
|
||||
// Full-node-only "Seed phrase" + "Migrate to seed" buttons trail the Backup button.
|
||||
float seedW = showFullNodeLifecycleActions ? ImGui::CalcTextSize(TR("seed_backup_button")).x + btnPadX : 0.0f;
|
||||
float migrateW = showFullNodeLifecycleActions ? ImGui::CalcTextSize(TR("seed_migrate_button")).x + btnPadX : 0.0f;
|
||||
float totalW = naturalW + sp * 5;
|
||||
if (showFullNodeLifecycleActions) totalW += wizW + bsW + seedW + sp * 3;
|
||||
if (showFullNodeLifecycleActions) totalW += wizW + bsW + seedW + migrateW + sp * 4;
|
||||
|
||||
float scale = (totalW > contentW) ? contentW / totalW : 1.0f;
|
||||
if (scale < 1.0f) ImGui::SetWindowFontScale(scale);
|
||||
@@ -1334,6 +1335,11 @@ void RenderSettingsPage(App* app) {
|
||||
if (TactileButton(TR("seed_backup_button"), ImVec2(0, 0), btnFont))
|
||||
app->showSeedBackupDialog();
|
||||
if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_seed_backup"));
|
||||
// Migrate to a new seed-phrase wallet (create in isolation, then sweep funds).
|
||||
ImGui::SameLine(0, scaledSp);
|
||||
if (TactileButton(TR("seed_migrate_button"), ImVec2(0, 0), btnFont))
|
||||
app->showSeedMigrationDialog();
|
||||
if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_seed_migrate"));
|
||||
}
|
||||
ImGui::SameLine(0, scaledSp);
|
||||
if (TactileButton(r1[4], ImVec2(0, 0), btnFont))
|
||||
|
||||
Reference in New Issue
Block a user