feat(settings): sweep a private key's funds to your own wallet
Add a "Sweep to my wallet (don't keep the key)" option to the Import Private Key dialog (spending keys only). Rather than keeping the key, it imports the key, then sends ALL its funds to a destination you control — a freshly generated shielded address by default, or an existing wallet address you pick. Flow (App::sweepPrivateKey): import the key (rescan; the stock node has no address index, so its UTXOs/notes can't be enumerated otherwise) → confirm it holds spendable funds → resolve the destination → z_sendmany balance-minus-fee from the key's address to the destination, via the existing tested submitZSendMany wrapper + async-operation tracker. The imported key is left in the wallet with an empty balance (there is no remove-key RPC) — stated plainly in the UI caveat. Design notes forced by this daemon (verified against external/dragonx): - z_importkey returns null here, so the shielded source address is found by diffing z_listaddresses before/after import (aborts if the pre-snapshot fails, so a wrong address can never be picked). Transparent uses importprivkey's return. - z_sendmany, NOT z_mergetoaddress: moves a single-UTXO transparent source (the common paper-wallet case) and fails loudly instead of silently leaving a remainder. Amount computed in integer satoshis for an exact fixed-decimal string. - Clear errors for no-funds / unconfirmed / dust-below-fee / already-imported. - The mode + destination are locked during a running sweep; a sweep that finishes while the dialog is closed still shows its Done/Error+txid on reopen; sweep UI can't bleed into the watch-only viewing dialog. i18n: 8 new sweep_* keys (en + 8 langs); dynamic status strings are English, matching the beginSweepToSeedWallet precedent. Reviewed across three adversarial multi-agent rounds (fund-safety focus): round 1 caught the feature was broken for shielded keys (z_importkey null) and rejected single-UTXO transparent sources; round 2 caught reopen/double-submit/precision issues; round 3 verified the fixes. NOT yet exercised against a live daemon — needs a small-amount mainnet test before it's trusted, like migrate-to-seed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
18
src/app.h
18
src/app.h
@@ -305,7 +305,13 @@ public:
|
||||
// startHeight > 0 rescans from that block (shielded RPCs only; ignored for transparent WIF).
|
||||
void importPrivateKey(const std::string& key, int startHeight,
|
||||
std::function<void(bool, const std::string&, const std::string&)> callback);
|
||||
|
||||
|
||||
// Sweep a spending key: import it (rescan) then z_sendmany ALL its funds (balance − fee) to a
|
||||
// destination you own — a freshly generated shielded address when destMode == 0, else destExisting.
|
||||
// Drives the sweep_step_ / sweep_status_ / sweep_txid_ state; reuses the async-operation tracker.
|
||||
void sweepPrivateKey(const std::string& key, int startHeight, int destMode,
|
||||
const std::string& destExisting);
|
||||
|
||||
// Wallet backup
|
||||
void backupWallet(const std::string& destination, std::function<void(bool, const std::string&)> callback);
|
||||
// Export the wallet's BIP39 seed phrase (z_exportmnemonic). The callback receives
|
||||
@@ -812,6 +818,16 @@ private:
|
||||
std::string import_result_address_; // address imported on success (shown as a copy field)
|
||||
bool import_view_mode_ = false; // dialog mode: false = spending key, true = viewing key
|
||||
char import_key_scan_height_[16] = {0}; // optional rescan start height (shielded spend / viewing-key imports)
|
||||
// --- Sweep: import a spending key then move all its funds to one of your own addresses, instead
|
||||
// of keeping the key in the wallet (spending-key / non-view mode only). ---
|
||||
bool import_sweep_mode_ = false; // sweep instead of a plain import
|
||||
int sweep_dest_mode_ = 0; // destination: 0 = fresh shielded address, 1 = an existing one
|
||||
char sweep_dest_pick_[128] = {0}; // chosen existing destination (sweep_dest_mode_ == 1)
|
||||
enum class SweepStep { Idle, Running, Done, Error };
|
||||
SweepStep sweep_step_ = SweepStep::Idle;
|
||||
std::string sweep_status_; // progress / error text
|
||||
std::string sweep_txid_; // sweep transaction id (on success)
|
||||
std::string sweep_dest_shown_; // the destination address the funds were swept to
|
||||
std::string backup_status_;
|
||||
bool backup_success_ = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user