Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion hwilib/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ def backup_device_handler(args: argparse.Namespace, client: HardwareWalletClient
return backup_device(client, label=args.label, backup_passphrase=args.backup_passphrase)

def displayaddress_handler(args: argparse.Namespace, client: HardwareWalletClient) -> Dict[str, str]:
return displayaddress(client, desc=args.desc, path=args.path, addr_type=args.addr_type)
return displayaddress(client, desc=args.desc, path=args.path, addr_type=args.addr_type,
wallet_id=args.wallet, change=args.change, index=args.idx)

def enumerate_handler(args: argparse.Namespace) -> List[Dict[str, Any]]:
return enumerate(password=args.password, expert=args.expert, chain=args.chain, allow_emulators=args.allow_emulators)
Expand Down Expand Up @@ -194,7 +195,10 @@ def get_parser() -> HWIArgumentParser:
group = displayaddr_parser.add_mutually_exclusive_group(required=True)
group.add_argument('--desc', help='Output Descriptor. E.g. wpkh([00000000/84h/0h/0h]xpub.../0/0), where 00000000 must match --fingerprint and xpub can be obtained with getxpub. See doc/descriptors.md in Bitcoin Core')
group.add_argument('--path', help='The BIP 32 derivation path of the key embedded in the address, default follows BIP43 convention, e.g. ``m/84h/0h/0h/1/*``')
group.add_argument('--wallet', help='Unique identifier of the wallet enrolled on the device')
displayaddr_parser.add_argument("--addr-type", help="The address type to display", type=AddressType.argparse, choices=list(AddressType), default=AddressType.WIT) # type: ignore
displayaddr_parser.add_argument("--change", action='store_true', help="Use internal chain") # type: ignore
displayaddr_parser.add_argument("--idx", type=int, default=0, help="The index for desired address") # type: ignore
displayaddr_parser.set_defaults(func=displayaddress_handler)

setupdev_parser = subparsers.add_parser('setup', help='Setup a device. Passphrase protection uses the password given by -p. Requires interactive mode')
Expand Down
15 changes: 14 additions & 1 deletion hwilib/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,10 @@ def displayaddress(
client: HardwareWalletClient,
path: Optional[str] = None,
desc: Optional[str] = None,
addr_type: AddressType = AddressType.WIT
addr_type: AddressType = AddressType.WIT,
wallet_id: Optional[str] = None,
change: bool = False,
index: int = 0,
) -> Dict[str, str]:
"""
Display an address on the device for client.
Expand All @@ -451,6 +454,9 @@ def displayaddress(
:param path: The path of the address to display. Mutually exclusive with ``desc``
:param desc: The descriptor to display the address for. Mutually exclusive with ``path``
:param addr_type: The address type to return. Only works with ``path``
:param wallet_id: Name of the complex wallet enrolled on the HWW device
:param change: Use internal chain. Only works with ``wallet_id``
:param index: Address index. Only works with ``wallet_id``
:return: A dictionary containing the address displayed.
Returned as ``{"address": <base58 or bech32 address string>}``.
:raises: BadArgumentError: if an argument is malformed, missing, or conflicts.
Expand Down Expand Up @@ -492,6 +498,13 @@ def displayaddress(
elif isinstance(descriptor, TRDescriptor):
addr_type = AddressType.TAP
return {"address": client.display_singlesig_address(pubkey.get_full_derivation_path(0), addr_type)}

elif wallet_id is not None:
if not getattr(client, "display_address_by_wallet_id"):
raise UnavailableActionError("No support for querying address by wallet id")

return {"address": client.display_address_by_wallet_id(wallet_id, change, index)}

raise BadArgumentError("Missing both path and descriptor")

def setup_device(client: HardwareWalletClient, label: str = "", backup_passphrase: str = "") -> Dict[str, bool]:
Expand Down
11 changes: 11 additions & 0 deletions hwilib/devices/coldcard.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,9 @@ def display_multisig_address(
addr_type: AddressType,
multisig: MultisigDescriptor,
) -> str:
if self.is_edge:
raise UnavailableActionError("Coldcard EDGE does not support this command."
" Use displayaddress with 'wallet_name' parameter")
if not multisig.is_sorted:
raise BadArgumentError("Coldcards only allow sortedmulti descriptors")

Expand Down Expand Up @@ -321,6 +324,14 @@ def display_multisig_address(
self.device.send_recv(CCProtocolPacker.sim_keypress(b'y'))
return address

@coldcard_exception
def display_address_by_wallet_id(self, name: str, change: bool, index: int) -> str:
if not self.is_edge:
raise UnavailableActionError("Coldcard does not support this command."
" Use displayaddress with 'desc' parameter")
return self.device.send_recv(CCProtocolPacker.miniscript_address(name, change, index),
timeout=None)

def setup_device(self, label: str = "", passphrase: str = "") -> bool:
"""
The Coldcard does not support setup via software.
Expand Down
17 changes: 17 additions & 0 deletions hwilib/hwwclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,23 @@ def display_multisig_address(
raise NotImplementedError("The HardwareWalletClient base class "
"does not implement this method")

def display_address_by_wallet_id(
self,
uid: str,
change: bool,
index: int
) -> str:
"""
Display and return the address of wallet enrolled on a device with specific id.

:param uid: Unique identifier of wallet enrolled on the device
:param change: Return address from internal chain.
:param index: Return address from index.
:return: The retrieved address also being shown by the device
"""
raise NotImplementedError("The HardwareWalletClient base class "
"does not implement this method")

def wipe_device(self) -> bool:
"""
Wipe the device.
Expand Down
Loading