Skip to content

Commit 3231b25

Browse files
committed
Add register command for BIP388 policies
1 parent 01fd502 commit 3231b25

File tree

4 files changed

+66
-1
lines changed

4 files changed

+66
-1
lines changed

hwilib/_cli.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
getdescriptors,
1313
prompt_pin,
1414
toggle_passphrase,
15+
register,
1516
restore_device,
1617
send_pin,
1718
setup_device,
@@ -22,6 +23,7 @@
2223
)
2324
from .common import (
2425
AddressType,
26+
BIP388Policy,
2527
Chain,
2628
)
2729
from .errors import (
@@ -59,6 +61,10 @@ def backup_device_handler(args: argparse.Namespace, client: HardwareWalletClient
5961
def displayaddress_handler(args: argparse.Namespace, client: HardwareWalletClient) -> Dict[str, str]:
6062
return displayaddress(client, desc=args.desc, path=args.path, addr_type=args.addr_type)
6163

64+
def register_handler(args: argparse.Namespace, client: HardwareWalletClient) -> Dict[str, str]:
65+
policy = BIP388Policy(name=args.name, descriptor_template=args.desc, keys_info=args.key)
66+
return register(client, bip388_policy=policy)
67+
6268
def enumerate_handler(args: argparse.Namespace) -> List[Dict[str, Any]]:
6369
return enumerate(password=args.password, expert=args.expert, chain=args.chain, allow_emulators=args.allow_emulators)
6470

@@ -197,6 +203,12 @@ def get_parser() -> HWIArgumentParser:
197203
displayaddr_parser.add_argument("--addr-type", help="The address type to display", type=AddressType.argparse, choices=list(AddressType), default=AddressType.WIT) # type: ignore
198204
displayaddr_parser.set_defaults(func=displayaddress_handler)
199205

206+
register_parser = subparsers.add_parser('register', help='Register a BIP388 wallet policy')
207+
register_parser.add_argument('--name', help='Name for the policy')
208+
register_parser.add_argument('--desc', help='Descriptor template, e.g. tr(musig(@0,@1)')
209+
register_parser.add_argument('--key', help='Key information, e.g. [00000000/84h/0h/0h]xpub...', action='append')
210+
register_parser.set_defaults(func=register_handler)
211+
200212
setupdev_parser = subparsers.add_parser('setup', help='Setup a device. Passphrase protection uses the password given by -p. Requires interactive mode')
201213
setupdev_parser.add_argument('--label', '-l', help='The name to give to the device', default='')
202214
setupdev_parser.add_argument('--backup_passphrase', '-b', help='The passphrase to use for the backup, if applicable', default='')

hwilib/commands.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
from .devices import __all__ as all_devs
5353
from .common import (
5454
AddressType,
55+
BIP388Policy,
5556
Chain,
5657
)
5758
from .hwwclient import HardwareWalletClient
@@ -494,6 +495,23 @@ def displayaddress(
494495
return {"address": client.display_singlesig_address(pubkey.get_full_derivation_path(0), addr_type)}
495496
raise BadArgumentError("Missing both path and descriptor")
496497

498+
def register(
499+
client: HardwareWalletClient,
500+
bip388_policy: BIP388Policy,
501+
) -> Dict[str, str]:
502+
"""
503+
Register a BIP388 policy on the device for client.
504+
505+
:param name: Name for the policy
506+
:param desc: Descriptor template
507+
:return: A dictionary containing policy HMAC.
508+
Returned as ``{"hmac": <hex string>}``.
509+
:raises: BadArgumentError: if an argument is malformed, missing, or conflicts.
510+
"""
511+
assert bip388_policy.hmac is None
512+
513+
return {"hmac": client.register_bip388_policy(bip388_policy)}
514+
497515
def setup_device(client: HardwareWalletClient, label: str = "", backup_passphrase: str = "") -> Dict[str, bool]:
498516
"""
499517
Setup a device that has not yet been initialized.

hwilib/devices/ledger.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
)
3232
from ..common import (
3333
AddressType,
34+
BIP388Policy,
3435
Chain,
3536
)
3637
from .ledger_bitcoin.client import (
@@ -479,6 +480,24 @@ def format_key_info(pubkey: PubkeyProvider) -> str:
479480

480481
return self.client.get_wallet_address(multisig_wallet, registered_hmac, change, address_index, True)
481482

483+
@ledger_exception
484+
def register_bip388_policy(
485+
self,
486+
bip388_policy: BIP388Policy,
487+
) -> str:
488+
if isinstance(self.client, LegacyClient):
489+
raise BadArgumentError("Registering a BIP388 policy not supported by this version of the Bitcoin App")
490+
491+
wallet_policy = WalletPolicy(
492+
name=bip388_policy.name,
493+
descriptor_template=bip388_policy.descriptor_template,
494+
keys_info=bip388_policy.keys_info
495+
)
496+
497+
_, registered_hmac = self.client.register_wallet(wallet_policy)
498+
499+
return registered_hmac.hex()
500+
482501
def setup_device(self, label: str = "", passphrase: str = "") -> bool:
483502
"""
484503
Ledgers do not support setup via software.

hwilib/hwwclient.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from typing import (
99
Dict,
10+
List,
1011
Optional,
1112
Union,
1213
)
@@ -17,7 +18,11 @@
1718
get_bip44_chain,
1819
)
1920
from .psbt import PSBT
20-
from .common import AddressType, Chain
21+
from .common import (
22+
AddressType,
23+
BIP388Policy,
24+
Chain,
25+
)
2126

2227

2328
class HardwareWalletClient(object):
@@ -135,6 +140,17 @@ def display_multisig_address(
135140
raise NotImplementedError("The HardwareWalletClient base class "
136141
"does not implement this method")
137142

143+
def register_bip388_policy(
144+
self,
145+
bip388_policy: BIP388Policy,
146+
) -> str:
147+
"""
148+
Register a BIP388 policy.
149+
150+
:return: The policy HMAC
151+
"""
152+
raise NotImplementedError("This device does not support BIP388 policies or it's not yet implemented")
153+
138154
def wipe_device(self) -> bool:
139155
"""
140156
Wipe the device.

0 commit comments

Comments
 (0)