Skip to content

Commit 2cda401

Browse files
committed
Implement get_features for all clients.
1 parent 8affeb3 commit 2cda401

File tree

6 files changed

+218
-8
lines changed

6 files changed

+218
-8
lines changed

hwilib/devices/coldcard.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Coldcard interaction script
22

33
from binascii import b2a_hex
4-
from ..hwwclient import HardwareWalletClient
4+
from ..hwwclient import DeviceFeature, HardwareWalletClient, SupportedFeatures
55
from ..errors import ActionCanceledError, BadArgumentError, DeviceBusyError, DeviceFailureError, UnavailableActionError, common_err_msgs, handle_errors
66
from .ckcc.client import ColdcardDevice, COINKITE_VID, CKCC_PID
77
from .ckcc.protocol import CCProtocolPacker, CCBusyError, CCProtoError, CCUserRefused
@@ -36,6 +36,29 @@ def func(*args, **kwargs):
3636
# This class extends the HardwareWalletClient for ColdCard specific things
3737
class ColdcardClient(HardwareWalletClient):
3838

39+
# Setup features
40+
features = SupportedFeatures()
41+
features.getxpub = DeviceFeature.SUPPORTED
42+
features.signmessage = DeviceFeature.SUPPORTED
43+
features.setup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
44+
features.wipe = DeviceFeature.FIRMWARE_NOT_SUPPORTED
45+
features.recover = DeviceFeature.FIRMWARE_NOT_SUPPORTED
46+
features.backup = DeviceFeature.SUPPORTED
47+
features.sign_p2pkh = DeviceFeature.SUPPORTED
48+
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
49+
features.sign_p2wpkh = DeviceFeature.SUPPORTED
50+
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
51+
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
52+
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
53+
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
54+
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
55+
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
56+
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
57+
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
58+
features.sign_coinjoin = DeviceFeature.SUPPORTED
59+
features.sign_mixed_segwit = DeviceFeature.SUPPORTED
60+
features.display_address = DeviceFeature.SUPPORTED
61+
3962
def __init__(self, path, password='', expert=False):
4063
super(ColdcardClient, self).__init__(path, password, expert)
4164
# Simulator hard coded pipe socket
@@ -249,7 +272,7 @@ def toggle_passphrase(self):
249272
# Get HWI features for this device
250273
@classmethod
251274
def get_features(self):
252-
raise NotImplementedError('The Coldcard does not implement this method')
275+
return self.features.get_printable_dict()
253276

254277
def enumerate(password=''):
255278
results = []

hwilib/devices/digitalbitbox.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import sys
1515
import time
1616

17-
from ..hwwclient import HardwareWalletClient
17+
from ..hwwclient import DeviceFeature, HardwareWalletClient, SupportedFeatures
1818
from ..errors import ActionCanceledError, BadArgumentError, DeviceFailureError, DeviceAlreadyInitError, DEVICE_NOT_INITIALIZED, DeviceNotReadyError, NoPasswordError, UnavailableActionError, common_err_msgs, handle_errors
1919
from ..serializations import CTransaction, ExtendedKey, hash256, ser_sig_der, ser_sig_compact, ser_compact_size
2020
from ..base58 import get_xpub_fingerprint, xpub_main_2_test
@@ -296,6 +296,29 @@ def format_backup_filename(name):
296296
# This class extends the HardwareWalletClient for Digital Bitbox specific things
297297
class DigitalbitboxClient(HardwareWalletClient):
298298

299+
# Setup features
300+
features = SupportedFeatures()
301+
features.getxpub = DeviceFeature.SUPPORTED
302+
features.signmessage = DeviceFeature.SUPPORTED
303+
features.setup = DeviceFeature.SUPPORTED
304+
features.wipe = DeviceFeature.SUPPORTED
305+
features.recover = DeviceFeature.FIRMWARE_NOT_SUPPORTED
306+
features.backup = DeviceFeature.SUPPORTED
307+
features.sign_p2pkh = DeviceFeature.SUPPORTED
308+
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
309+
features.sign_p2wpkh = DeviceFeature.SUPPORTED
310+
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
311+
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
312+
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
313+
features.sign_multi_bare = DeviceFeature.SUPPORTED
314+
features.sign_arbitrary_bare = DeviceFeature.SUPPORTED
315+
features.sign_arbitrary_p2sh = DeviceFeature.SUPPORTED
316+
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.SUPPORTED
317+
features.sign_arbitrary_p2wsh = DeviceFeature.SUPPORTED
318+
features.sign_coinjoin = DeviceFeature.SUPPORTED
319+
features.sign_mixed_segwit = DeviceFeature.SUPPORTED
320+
features.display_address = DeviceFeature.FIRMWARE_NOT_SUPPORTED
321+
299322
def __init__(self, path, password, expert=False):
300323
super(DigitalbitboxClient, self).__init__(path, password, expert)
301324
if not password:
@@ -590,7 +613,7 @@ def toggle_passphrase(self):
590613
# Get HWI features for this device
591614
@classmethod
592615
def get_features(self):
593-
raise NotImplementedError('The Digital Bitbox does not implement this method')
616+
return self.features.get_printable_dict()
594617

595618
class Digitalbitbox01Client(DigitalbitboxClient):
596619
def __init__(self, path, password='', expert=False):

hwilib/devices/keepkey.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,45 @@
11
# KeepKey interaction script
22

33
from ..errors import DEVICE_NOT_INITIALIZED, DeviceNotReadyError, common_err_msgs, handle_errors
4+
from ..hwwclient import DeviceFeature, SupportedFeatures
45
from .trezorlib.transport import enumerate_devices, KEEPKEY_VENDOR_IDS
56
from .trezor import TrezorClient
67

78
py_enumerate = enumerate # Need to use the enumerate built-in but there's another function already named that
89

910
class KeepkeyClient(TrezorClient):
11+
12+
# Setup features
13+
features = SupportedFeatures()
14+
features.getxpub = DeviceFeature.SUPPORTED
15+
features.signmessage = DeviceFeature.SUPPORTED
16+
features.setup = DeviceFeature.SUPPORTED
17+
features.wipe = DeviceFeature.SUPPORTED
18+
features.recover = DeviceFeature.SUPPORTED
19+
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
20+
features.sign_p2pkh = DeviceFeature.SUPPORTED
21+
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
22+
features.sign_p2wpkh = DeviceFeature.SUPPORTED
23+
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
24+
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
25+
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
26+
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
27+
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
28+
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
29+
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
30+
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
31+
features.sign_coinjoin = DeviceFeature.SUPPORTED
32+
features.sign_mixed_segwit = DeviceFeature.SUPPORTED
33+
features.display_address = DeviceFeature.SUPPORTED
34+
1035
def __init__(self, path, password='', expert=False):
1136
super(KeepkeyClient, self).__init__(path, password, expert)
1237
self.type = 'Keepkey'
1338

39+
@classmethod
40+
def get_features(self):
41+
return self.features.get_printable_dict()
42+
1443
def enumerate(password=''):
1544
results = []
1645
for dev in enumerate_devices():

hwilib/devices/ledger.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Ledger interaction script
22

3-
from ..hwwclient import HardwareWalletClient
3+
from ..hwwclient import DeviceFeature, HardwareWalletClient, SupportedFeatures
44
from ..errors import ActionCanceledError, BadArgumentError, DeviceConnectionError, DeviceFailureError, UnavailableActionError, common_err_msgs, handle_errors
55
from .btchip.bitcoinTransaction import bitcoinTransaction
66
from .btchip.btchip import btchip
@@ -71,6 +71,29 @@ def func(*args, **kwargs):
7171
# This class extends the HardwareWalletClient for Ledger Nano S and Nano X specific things
7272
class LedgerClient(HardwareWalletClient):
7373

74+
# Setup features
75+
features = SupportedFeatures()
76+
features.getxpub = DeviceFeature.SUPPORTED
77+
features.signmessage = DeviceFeature.SUPPORTED
78+
features.setup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
79+
features.wipe = DeviceFeature.FIRMWARE_NOT_SUPPORTED
80+
features.recover = DeviceFeature.FIRMWARE_NOT_SUPPORTED
81+
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
82+
features.sign_p2pkh = DeviceFeature.SUPPORTED
83+
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
84+
features.sign_p2wpkh = DeviceFeature.SUPPORTED
85+
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
86+
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
87+
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
88+
features.sign_multi_bare = DeviceFeature.SUPPORTED
89+
features.sign_arbitrary_bare = DeviceFeature.SUPPORTED
90+
features.sign_arbitrary_p2sh = DeviceFeature.SUPPORTED
91+
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.SUPPORTED
92+
features.sign_arbitrary_p2wsh = DeviceFeature.SUPPORTED
93+
features.sign_coinjoin = DeviceFeature.SUPPORTED
94+
features.sign_mixed_segwit = DeviceFeature.FIRMWARE_NOT_SUPPORTED
95+
features.display_address = DeviceFeature.SUPPORTED
96+
7497
def __init__(self, path, password='', expert=False):
7598
super(LedgerClient, self).__init__(path, password, expert)
7699
self.type = 'Ledger Nano S and X'
@@ -361,7 +384,7 @@ def toggle_passphrase(self):
361384
# Get HWI features for this device
362385
@classmethod
363386
def get_features(self):
364-
raise NotImplementedError('The Ledger Nano S and X does not implement this method')
387+
return self.features.get_printable_dict()
365388

366389
class LedgerNanoSClient(LedgerClient):
367390
def __init__(self, path, password='', expert=False):

hwilib/devices/trezor.py

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Trezor interaction script
22

3-
from ..hwwclient import HardwareWalletClient
3+
from ..hwwclient import DeviceFeature, HardwareWalletClient, SupportedFeatures
44
from ..errors import ActionCanceledError, BadArgumentError, DeviceAlreadyInitError, DeviceAlreadyUnlockedError, DeviceConnectionError, DEVICE_NOT_INITIALIZED, DeviceNotReadyError, UnavailableActionError, common_err_msgs, handle_errors
55
from .trezorlib.client import TrezorClient as Trezor
66
from .trezorlib.debuglink import TrezorClientDebugLink
@@ -443,18 +443,74 @@ def toggle_passphrase(self):
443443
# Get HWI features for this device
444444
@classmethod
445445
def get_features(self):
446-
raise NotImplementedError('The {} does not implement this method'.format(self.type))
446+
raise UnavailableActionError('A specific Trezor model must be specified to get the features')
447447

448448
class Trezor1Client(TrezorClient):
449+
450+
# Setup features
451+
features = SupportedFeatures()
452+
features.getxpub = DeviceFeature.SUPPORTED
453+
features.signmessage = DeviceFeature.SUPPORTED
454+
features.setup = DeviceFeature.SUPPORTED
455+
features.wipe = DeviceFeature.SUPPORTED
456+
features.recover = DeviceFeature.SUPPORTED
457+
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
458+
features.sign_p2pkh = DeviceFeature.SUPPORTED
459+
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
460+
features.sign_p2wpkh = DeviceFeature.SUPPORTED
461+
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
462+
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
463+
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
464+
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
465+
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
466+
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
467+
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
468+
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
469+
features.sign_coinjoin = DeviceFeature.SUPPORTED
470+
features.sign_mixed_segwit = DeviceFeature.SUPPORTED
471+
features.display_address = DeviceFeature.SUPPORTED
472+
449473
def __init__(self, path, password='', expert=False):
450474
super(Trezor1Client, self).__init__(path, password, expert)
451475
self.type = 'Trezor 1'
452476

477+
@classmethod
478+
def get_features(self):
479+
return self.features.get_printable_dict()
480+
453481
class TrezorTClient(TrezorClient):
482+
483+
# Setup features
484+
features = SupportedFeatures()
485+
features.getxpub = DeviceFeature.SUPPORTED
486+
features.signmessage = DeviceFeature.SUPPORTED
487+
features.setup = DeviceFeature.SUPPORTED
488+
features.wipe = DeviceFeature.SUPPORTED
489+
features.recover = DeviceFeature.SUPPORTED
490+
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
491+
features.sign_p2pkh = DeviceFeature.SUPPORTED
492+
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
493+
features.sign_p2wpkh = DeviceFeature.SUPPORTED
494+
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
495+
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
496+
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
497+
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
498+
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
499+
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
500+
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
501+
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
502+
features.sign_coinjoin = DeviceFeature.SUPPORTED
503+
features.sign_mixed_segwit = DeviceFeature.FIRMWARE_NOT_SUPPORTED
504+
features.display_address = DeviceFeature.SUPPORTED
505+
454506
def __init__(self, path, password='', expert=False):
455507
super(TrezorTClient, self).__init__(path, password, expert)
456508
self.type = 'Trezor T'
457509

510+
@classmethod
511+
def get_features(self):
512+
return self.features.get_printable_dict()
513+
458514
def enumerate(password=''):
459515
results = []
460516
for dev in enumerate_devices():

hwilib/hwwclient.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,60 @@
1+
# General device client class and related constants and enums
2+
13
from .base58 import get_xpub_fingerprint_hex
4+
from enum import IntEnum
5+
6+
class DeviceFeature(IntEnum):
7+
SUPPORTED = 1 # The device supports the feature and so does HWI
8+
NOT_SUPPORTED = 2 # The device supports the feature but HWI has not implemented it yet
9+
FIRMWARE_NOT_SUPPORTED = 3 # The firmware does not support the feature so HWI cannot
10+
11+
class SupportedFeatures(object):
12+
13+
def __init__(self):
14+
self.getxpub = DeviceFeature.NOT_SUPPORTED
15+
self.signmessage = DeviceFeature.NOT_SUPPORTED
16+
self.setup = DeviceFeature.NOT_SUPPORTED
17+
self.wipe = DeviceFeature.NOT_SUPPORTED
18+
self.recover = DeviceFeature.NOT_SUPPORTED
19+
self.backup = DeviceFeature.NOT_SUPPORTED
20+
self.sign_p2pkh = DeviceFeature.NOT_SUPPORTED
21+
self.sign_p2sh_p2wpkh = DeviceFeature.NOT_SUPPORTED
22+
self.sign_p2wpkh = DeviceFeature.NOT_SUPPORTED
23+
self.sign_multi_p2sh = DeviceFeature.NOT_SUPPORTED
24+
self.sign_multi_p2sh_p2wsh = DeviceFeature.NOT_SUPPORTED
25+
self.sign_multi_p2wsh = DeviceFeature.NOT_SUPPORTED
26+
self.sign_multi_bare = DeviceFeature.NOT_SUPPORTED
27+
self.sign_arbitrary_bare = DeviceFeature.NOT_SUPPORTED
28+
self.sign_arbitrary_p2sh = DeviceFeature.NOT_SUPPORTED
29+
self.sign_arbitrary_p2sh_p2wsh = DeviceFeature.NOT_SUPPORTED
30+
self.sign_arbitrary_p2wsh = DeviceFeature.NOT_SUPPORTED
31+
self.sign_coinjoin = DeviceFeature.NOT_SUPPORTED
32+
self.sign_mixed_segwit = DeviceFeature.NOT_SUPPORTED
33+
self.display_address = DeviceFeature.NOT_SUPPORTED
34+
35+
def get_printable_dict(self):
36+
d = {}
37+
d['getxpub'] = self.getxpub
38+
d['signmessage'] = self.signmessage
39+
d['setup'] = self.setup
40+
d['wipe'] = self.wipe
41+
d['recover'] = self.recover
42+
d['backup'] = self.backup
43+
d['sign_p2pkh'] = self.sign_p2pkh
44+
d['sign_p2sh_p2wpkh'] = self.sign_p2sh_p2wpkh
45+
d['sign_p2wpkh'] = self.sign_p2wpkh
46+
d['sign_multi_p2sh'] = self.sign_multi_p2sh
47+
d['sign_multi_p2sh_p2wsh'] = self.sign_multi_p2sh_p2wsh
48+
d['sign_multi_p2wsh'] = self.sign_multi_p2wsh
49+
d['sign_multi_bare'] = self.sign_multi_bare
50+
d['sign_arbitrary_bare'] = self.sign_arbitrary_bare
51+
d['sign_arbitrary_p2sh'] = self.sign_arbitrary_p2sh
52+
d['sign_arbitrary_p2sh_p2wsh'] = self.sign_arbitrary_p2sh_p2wsh
53+
d['sign_arbitrary_p2wsh'] = self.sign_arbitrary_p2wsh
54+
d['sign_coinjoin'] = self.sign_coinjoin
55+
d['sign_mixed_segwit'] = self.sign_mixed_segwit
56+
d['display_address'] = self.display_address
57+
return d
258

359
# This is an abstract class that defines all of the methods that each Hardware
460
# wallet subclass must implement.

0 commit comments

Comments
 (0)