Skip to content

HWIBridge default chain="" breaks Jade extract_xpub and sign_tx #2615

@k9ert

Description

@k9ert

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

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:

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 deps: bump hwi 2.4.0 -> 3.1.0 (drops Python 3.7/3.8) #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

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