Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Feb 5, 2026

Wallet exports (PDF, JSON, QR codes) were only including the receive descriptor /0/*, omitting change addresses. Hardware wallets importing these backups could not derive change addresses.

Changes

Export with combined descriptor (wallet.py)

  • Changed account_map property to use descriptor.to_string() which returns BIP 389 multipath syntax <0;1>/* instead of just recv_descriptor (/0/*)
  • Affects all export paths: PDF backup, JSON export, and QR codes

Backward compatible import (wallet_importer.py)

  • Added regex conversion <0;1>/*0/* during import to satisfy existing validation logic
  • Wallet is created with both branches regardless (internal invariant)

Test coverage (test_wallet.py)

  • New test verifies account_map exports combined descriptor with 2 branches

Example

Before:

{"descriptor": "wpkh([fp/84h/0h/0h]xpub.../0/*)#checksum"}

After:

{"descriptor": "wpkh([fp/84h/0h/0h]xpub.../<0;1>/*)#checksum"}

The combined descriptor expands to both receive (/0/*) and change (/1/*) branches when parsed by BIP 389-compliant wallets.

Original prompt

This section details on the original issue you should resolve

<issue_title>Export JSON/PDF for single/multi signature omit change address branch</issue_title>
<issue_description>Describe the bug
When creating a single/multi signature with ambiguous XPUB (i.e. without branch/output address info), Specter export the wallet with branch/output address for receive only (branch /0/*).

To Reproduce
Example steps to reproduce the behavior:

"Add wallet > Single Signature > Add new device > SeedSigner > Scan QR Code [e0c595c5/84'/0'/0']zpub6qV6TyVkDQsoP6XnSgLJxoH7YunCwUKzPZq3FhccdoQT7uS9w5hDo45tLpRQxr6P3FJnwWaCnYJcZSQiXif5WnPQ5rN2yMRHAE5ZyTzQvre and give device a name > Continue > Create single key wallet > give wallet a name and Create wallet > Save Backup PDF"

The first page of the PDF has the QR Code with descriptor as /0/* without change address info:

{"label": "a name", "blockheight": 481824, "descriptor": "wpkh([669dce62/84h/0h/0h]xpub6Cygb51hbAxuxKQ4hwVV5z6YvhauXbhDexEuA7EoAq9DkejbuF2najEM3YdY2BvC39XYa9nHE3R9QWr2yYgTU58LTNQ7ipFQoj4TszqYVeS/0/*)#w0rtkcqe", "devices": [{"type": "other", "label": "gg"}]}

The second page of the PDF has the text with descriptor as /0/* without change address info:

{"label": "a name", "blockheight": 481824, "descriptor": "wp
kh([669dce62/84h/0h/0h]xpub6Cygb51hbAxuxKQ4hwVV5z6YvhauXbhDe
xEuA7EoAq9DkejbuF2najEM3YdY2BvC39XYa9nHE3R9QWr2yYgTU58LTNQ7i
pFQoj4TszqYVeS/0/*)#w0rtkcqe", "devices": [{"type": "other",
"label": "gg"}]}

The same thing happen if you go to "Settings > Export > Go to export details, descriptor as /0/* in the QR Code and the JSON Data:

{"label": "a name", "blockheight": 481824, "descriptor": "wpkh([669dce62/84h/0h/0h]xpub6Cygb51hbAxuxKQ4hwVV5z6YvhauXbhDexEuA7EoAq9DkejbuF2najEM3YdY2BvC39XYa9nHE3R9QWr2yYgTU58LTNQ7ipFQoj4TszqYVeS/0/*)#w0rtkcqe", "devices": [{"type": "other", "label": "gg"}]}

Expected behavior
It would be fine to return ONLY the [fingerprint/deriv/path]xpub... which would be an XPUB with origin-info rather than a complete descriptor... or since Specter Desktop is returning a descriptor that made some assumptions (script wrapper and checksum) to also assume the change path /<0;1>/* rather than assuming receive path only /0/*.

Screenshots

Image

Desktop (please complete the following information):

  • Where is your node running: public
  • Where is your specter running: Binaries downloaded from Specter site
  • If you're running a binary, which OS: Linux
  • Browser N/A
  • Specter v2.0.5 - May 30, 2024

Additional context
SeedSigner and Krux exports the ZPUB/XPUB without branch/output address info. Specter-DIY "Master public keys Single key/Multisig" also give values without branch/output address info. But Specter-DIY "Wallets > Default > Settings > Export wallet descriptor" gives values with /0/* with branch/output for receive address only.
</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@netlify
Copy link

netlify bot commented Feb 5, 2026

Deploy Preview for specter-desktop-docs canceled.

Name Link
🔨 Latest commit 0a969d1
🔍 Latest deploy log https://app.netlify.com/projects/specter-desktop-docs/deploys/69844561bf70c50008251569

Copilot AI changed the title [WIP] Fix export JSON/PDF for single/multi signature change address Export wallets with BIP 389 multipath descriptors for both receive and change branches Feb 5, 2026
Copilot AI requested a review from k9ert February 5, 2026 07:26
Copy link
Contributor

@al-munazzim al-munazzim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good fix for including both receive and change branches in exports. A few considerations:

  1. BIP 389 compatibility: Verify that target wallets (SeedSigner, Krux, etc.) actually support the <0;1>/* multipath syntax. Some older firmware versions might not parse it correctly.

  2. Import regex concern: The conversion <0;1>/*0/* in wallet_importer.py:

# What if there are multiple multipath parts in a complex descriptor?
# e.g., multi(2, ../<0;1>/*, .../<0;1>/*)

The current regex might not handle all cases. Worth adding a test for multisig descriptors with multipath.

  1. Backward compatibility: Good that imports still work - old exports with /0/* will continue to import fine.

  2. Checksum: Does changing from /0/* to /<0;1>/* affect the descriptor checksum? The checksum should be recalculated.

Overall: 👍 Good improvement. Might want to verify hardware wallet compatibility before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export JSON/PDF for single/multi signature omit change address branch

3 participants