Skip to content

Feature Request: UTXO Migration Tool with per-transaction control #1981

@semillabitcoin

Description

@semillabitcoin

Problem

When migrating funds between wallets (e.g., singlesig to multisig, wallet without passphrase to with passphrase, or key rotation), the privacy-preserving approach requires sending each UTXO individually to a separate fresh address in the destination wallet. Currently this means manually creating N individual transactions, which is tedious and error-prone.

For a wallet with 50 or more UTXOs, this manual process is directly impractical: you have to manually generate a fresh destination address each time, make sure you never reuse one, keep mental track of which UTXOs have already been migrated, and there's no way to pause and resume the process.

Previous proposals (#1421, #1971) were rejected because they required Sparrow to act as a server (scheduled broadcasting). This proposal is different — everything is manual and user-controlled.

Proposed solution

A new tool under Tools > Migrate UTXOs using the same spreadsheet interface as Send to Many.

Workflow

1. Select destination wallet

A dropdown at the top listing open wallets in Sparrow (including watch-only). If no other wallet is open, the dropdown shows "Open a destination wallet first".

2. Select UTXOs and configure fees

The spreadsheet displays all UTXOs from the current wallet. The user checks which ones to migrate. Each selected UTXO is automatically assigned a fresh receive address from the destination wallet.

  • Value — read-only, the UTXO's value
  • Fee — the only editable field, fee rate in s/vB
  • Each transaction is built as: input = entire UTXO, output = value - fee, no change

Three fee modes:

  • Fixed — one fee rate applied to all transactions
  • Manual per-tx — the fee column becomes editable, user sets each one individually
  • Random range — user defines min and max (e.g. 0.5 to 4.0 s/vB), Sparrow assigns a random value within that range to each transaction. A [Randomize] button re-rolls the values. Individual cells remain editable after randomization.

The random range is an anti-fingerprinting measure — identical fee rates across multiple transactions are a trivial heuristic for chain analysis to link them.

┌──────────────────────────────────────────────────────────────────────────────────┐
│  Migrate UTXOs                                                                X │
├──────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  Destination wallet: [ My Multisig ▼ ]                                           │
│                                                                                  │
│  Fee strategy: ( ) Fixed  (•) Manual per-tx  ( ) Random range                    │
│                                                                                  │
├──────────────────────────────────────────────────────────────────────────────────┤
│ ☑/☐ │ UTXO       │ Value     │ Label    │ Dest. Address      │ Fee             │
│─────┼────────────┼───────────┼──────────┼────────────────────┼─────────────────│
│ ☑   │ abc123:0   │ 0.050 BTC │ Kraken   │ bc1q...7xm (auto)  │ 2.7             │
│ ☑   │ def456:1   │ 0.120 BTC │ Bisq     │ bc1q...3kp (auto)  │ 1.1             │
│ ☐   │ ghi789:2   │ 0.008 BTC │ CJ chg   │                    │                 │
│ ☑   │ jkl012:3   │ 0.300 BTC │ cold     │ bc1q...9nt (auto)  │ 3.4             │
│     │            │           │          │                    │                 │
├──────────────────────────────────────────────────────────────────────────────────┤
│ [Select All]  [Create PSBTs]                                     [Cancel]        │
└──────────────────────────────────────────────────────────────────────────────────┘

3. Create PSBTs

A summary is shown (total value, total fees, number of transactions) and one PSBT per UTXO is created.

4. Sign — automatically adapts to the hardware wallet connection method

Sparrow already knows how the wallet is connected (USB, microSD, QR). The interface adapts automatically:

USB mode (Ledger, Trezor, Jade, ColdCard USB):

Each row gets a [Sign] button. The user clicks it, Sparrow sends the PSBT to the device via USB, the user confirms on the hardware wallet screen, the signed tx returns automatically.

┌──────────────────────────────────────────────────────────────────────────────────┐
│  Migrate UTXOs                                                                X │
├──────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  Destination wallet: My Multisig                                                 │
│                                                                                  │
├──────────────────────────────────────────────────────────────────────────────────┤
│ UTXO       │ Value     │ Label    │ Dest. Address    │ Fee  │ Action            │
│────────────┼───────────┼──────────┼──────────────────┼──────┼───────────────────│
│ abc123:0   │ 0.050 BTC │ Kraken   │ bc1q...7xm       │ 2.7  │ [Sign]            │
│ def456:1   │ 0.120 BTC │ Bisq     │ bc1q...3kp       │ 1.1  │ [Sign]            │
│ jkl012:3   │ 0.300 BTC │ cold     │ bc1q...9nt       │ 3.4  │ [Sign]            │
│            │           │          │                  │      │                   │
├──────────────────────────────────────────────────────────────────────────────────┤
│                                                                  [Close]         │
└──────────────────────────────────────────────────────────────────────────────────┘

microSD mode (ColdCard air-gapped):

The most efficient method for migrating many UTXOs. An [Export All to SD] button writes all PSBTs to the microSD at once. The user signs them one by one on the ColdCard, brings the SD back and clicks [Import from SD]. A single round trip for all transactions.

┌──────────────────────────────────────────────────────────────────────────────────┐
│  Migrate UTXOs                                                                X │
├──────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  Destination wallet: My Multisig                                                 │
│                                                                                  │
├──────────────────────────────────────────────────────────────────────────────────┤
│ UTXO       │ Value     │ Label    │ Dest. Address    │ Fee  │ Status            │
│────────────┼───────────┼──────────┼──────────────────┼──────┼───────────────────│
│ abc123:0   │ 0.050 BTC │ Kraken   │ bc1q...7xm       │ 2.7  │ ⏳ Unsigned       │
│ def456:1   │ 0.120 BTC │ Bisq     │ bc1q...3kp       │ 1.1  │ ⏳ Unsigned       │
│ jkl012:3   │ 0.300 BTC │ cold     │ bc1q...9nt       │ 3.4  │ ⏳ Unsigned       │
│            │           │          │                  │      │                   │
├──────────────────────────────────────────────────────────────────────────────────┤
│ [Export All to SD]  [Import from SD]                             [Close]         │
└──────────────────────────────────────────────────────────────────────────────────┘

QR mode (SeedSigner, Krux, Keystone, Jade air-gapped):

Each row gets a [Show QR] button that displays the animated QR of the PSBT for the HW to scan. After signing on the device, the user clicks [Scan signed QR] to scan the signed tx with the webcam.

┌──────────────────────────────────────────────────────────────────────────────────┐
│  Migrate UTXOs                                                                X │
├──────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  Destination wallet: My Multisig                                                 │
│                                                                                  │
├──────────────────────────────────────────────────────────────────────────────────┤
│ UTXO       │ Value     │ Label    │ Dest. Address    │ Fee  │ Action            │
│────────────┼───────────┼──────────┼──────────────────┼──────┼───────────────────│
│ abc123:0   │ 0.050 BTC │ Kraken   │ bc1q...7xm       │ 2.7  │ [Show QR]         │
│ def456:1   │ 0.120 BTC │ Bisq     │ bc1q...3kp       │ 1.1  │ [Show QR]         │
│ jkl012:3   │ 0.300 BTC │ cold     │ bc1q...9nt       │ 3.4  │ [Show QR]         │
│            │           │          │                  │      │                   │
├──────────────────────────────────────────────────────────────────────────────────┤
│ [Scan signed QR]                                                 [Close]         │
└──────────────────────────────────────────────────────────────────────────────────┘

5. Broadcast at the user's pace

After signing (by any method), each transaction gets a [Broadcast] button. The user decides when to broadcast each one — immediately, hours later, days later. There is no automation, no scheduler, no timer.

If a signed transaction's fee rate becomes stale, a [Re-create] option discards it and generates a new PSBT with an updated fee, requiring re-signing.

┌──────────────────────────────────────────────────────────────────────────────────┐
│  Migrate UTXOs                                                                X │
├──────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  Destination wallet: My Multisig                                                 │
│                                                                                  │
├──────────────────────────────────────────────────────────────────────────────────┤
│ UTXO       │ Value     │ Label    │ Dest. Address    │ Fee  │ Action            │
│────────────┼───────────┼──────────┼──────────────────┼──────┼───────────────────│
│ abc123:0   │ 0.050 BTC │ Kraken   │ bc1q...7xm       │ 2.7  │ 📡 Done           │
│ def456:1   │ 0.120 BTC │ Bisq     │ bc1q...3kp       │ 1.1  │ [Broadcast]       │
│ jkl012:3   │ 0.300 BTC │ cold     │ bc1q...9nt       │ 3.4  │ [Broadcast]       │
│            │           │          │                  │      │                   │
├──────────────────────────────────────────────────────────────────────────────────┤
│                                                                  [Close]         │
└──────────────────────────────────────────────────────────────────────────────────┘

Persistence

Migration state is saved to disk as part of the wallet data. If Sparrow is closed and reopened, the user can return to Tools > Migrate UTXOs and find the migration in progress exactly as they left it — with each transaction's state (unsigned, signed, broadcast) preserved.

On reload, Sparrow checks that unsigned/signed UTXOs still exist (haven't been spent by another transaction). Any UTXO spent elsewhere is marked as invalid.

Concerns and how they are addressed

"This can already be done manually with coin control"

Technically yes — select a UTXO, create tx, sign, broadcast, repeat. But for a wallet with 50 or more UTXOs this is directly impractical: you have to manually generate a fresh destination address each time, make sure you never reuse one, keep mental track of which ones have already been migrated, and there's no way to pause and resume the process. This tool doesn't add new capabilities — it automates the orchestration of capabilities Sparrow already has.

"This adds complexity to the wallet state"

Sparrow already persists partially signed PSBTs in multisig wallets. The persistence mechanism needed already exists — it would just apply to a list of individual transactions instead of a single one. The migration would be a temporary state that is automatically cleaned up when all transactions have been broadcast or when the user cancels.

"Better to wait for Broadcast Pool (bitcoin/bitcoin#30471)"

This proposal does not depend on or replace the Broadcast Pool. They are complementary: this tool manages the creation, signing, and storage of the transactions. The Broadcast Pool, if implemented in the future, could be integrated as an additional broadcast option. But the core value — automating the construction and signing of N individual transactions — is useful regardless of how they are broadcast.

Why this is different from #1421 and #1971

  • No server behavior — Sparrow doesn't need to stay open, there's no scheduler, no background broadcasting
  • No fee prediction — each transaction is signed with a fee the user chose at that moment
  • Fully manual — the user controls every action (sign, broadcast) individually
  • Reuses existing UI — spreadsheet component from Send to Many, signing flow already in Sparrow
  • Adapts to hardware wallet — USB, microSD and QR work automatically based on the wallet's configuration

Relation to existing features

This is the natural complement to Sparrow's coin control: where coin control lets users carefully select which UTXOs to spend, this tool lets them carefully move those UTXOs while preserving the separation they've worked to maintain.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions