cryptoadvance / cryptoadvance/specter-desktop

HWIBridge default chain="" breaks Jade extract_xpub and sign_tx

Open
#2,615 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
847
Forks
259
Avg merge
6d 18h
Merged PRs (30d)
2

Description

## Summary

`HWIBridge.extract_xpub`, `sign_tx`, and `display_address` all default `chain=""`. For Jade specifically, this raises `BadArgumentError: Unhandled network:` *during client construction* — before any of the affected methods get a chance to apply their post-init chain override.

## Repro

```python
from cryptoadvance.specter.hwi_rpc import HWIBridge

bridge = HWIBridge()
fp = bridge.enumerate(chain="main")[0]["fingerprint"]
bridge.extract_xpub(derivation="m/84h/0h/0h", device_type="jade", fingerprint=fp)
# -> hwilib.errors.BadArgumentError: Unhandled network:
```

Workaround:
```python
bridge.extract_xpub(derivation="m/84h/0h/0h", device_type="jade", fingerprint=fp, chain="main")
```

## Why it happens

`hwi_rpc.py:240` enters `_get_client(chain=chain)` with `chain=""`. That string is passed through `Chain.argparse("")`, which falls through `Chain[""].upper()` → `KeyError` → returns the input string unchanged. So `JadeClient(chain="")` is constructed.

`devices/hwi/jade.py:186` is `__init__` calling `self.jade.auth_user(self._network())` — and `_network()` (line 104) requires `self.chain` to be a `Chain` enum value present in `NETWORKS`. Empty string is neither, so `BadArgumentError` is raised before the constructor returns.

`extract_xpub`'s logic at `hwi_rpc.py:251-253` *would* set `client.chain` from the derivation path, but execution never reaches that block.

## Where it bites

- Any direct caller of `HWIBridge.extract_xpub` / `sign_tx` / `display_address` that doesn't pass `chain=` explicitly. Most of Specter's UI flow does pass it; this hurts mostly programmatic / test consumers.
- Surfaced while wiring up the new `tests/test_jade_hardware.py` suite (PR #2616); tests had to pass `chain="main"`/`chain="test"` explicitly as a workaround.

## Fix sketch

Two reasonable options:
1. **Derive chain from the derivation path inside `_get_client`** (same heuristic that already exists in `extract_xpub`) when the caller passes `chain=""`. Pre-init Jade gets a real chain.
2. **Default `chain="main"`** in `_get_client` and the public bridge methods. Caller can still override.

Option 2 is the smaller change and matches what most callers already pass.

Other HWWClient subclasses don't validate chain in `__init__` so they don't fail loudly — but they may also produce subtly wrong results on testnet derivations. Option 1 is the more correct fix.

## Refs

- Worked around in PR #2616 (`kn/bump-hwi-3.1`) so the new Jade hardware tests can run.

Contributor guide

Open the contributing guide

Research direction

Start in hwi_rpc.py at _get_client and the extract_xpub, sign_tx, and display_address callers, then read devices/hwi/jade.py and tests/test_jade_hardware.py. Verify the selected chain is valid before Jade construction, and run the Jade tests to confirm default calls work for mainnet and testnet without explicit chain arguments.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.