Skip to content

Commit 2422cf1

Browse files
committed
Implement get_features for all clients.
1 parent fd41626 commit 2422cf1

File tree

6 files changed

+219
-8
lines changed

6 files changed

+219
-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
@@ -245,7 +268,7 @@ def send_pin(self, pin):
245268
# Get HWI features for this device
246269
@classmethod
247270
def get_features(self):
248-
raise NotImplementedError('The Coldcard does not implement this method')
271+
return self.features.get_printable_dict()
249272

250273
def enumerate(password=''):
251274
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, get_xpub_fingerprint_hex
@@ -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:
@@ -586,7 +609,7 @@ def send_pin(self, pin):
586609
# Get HWI features for this device
587610
@classmethod
588611
def get_features(self):
589-
raise NotImplementedError('The Digital Bitbox does not implement this method')
612+
return self.features.get_printable_dict()
590613

591614
class Digitalbitbox01Client(DigitalbitboxClient):
592615
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,17 +1,46 @@
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
from ..base58 import get_xpub_fingerprint_hex
78

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

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

40+
@classmethod
41+
def get_features(self):
42+
return self.features.get_printable_dict()
43+
1544
def enumerate(password=''):
1645
results = []
1746
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
@@ -72,6 +72,29 @@ def func(*args, **kwargs):
7272
# This class extends the HardwareWalletClient for Ledger Nano S and Nano X specific things
7373
class LedgerClient(HardwareWalletClient):
7474

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

363386
class LedgerNanoSClient(LedgerClient):
364387
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
@@ -437,18 +437,74 @@ def send_pin(self, pin):
437437
# Get HWI features for this device
438438
@classmethod
439439
def get_features(self):
440-
raise NotImplementedError('The {} does not implement this method'.format(self.type))
440+
raise UnavailableActionError('A specific Trezor model must be specified to get the features')
441441

442442
class Trezor1Client(TrezorClient):
443+
444+
# Setup features
445+
features = SupportedFeatures()
446+
features.getxpub = DeviceFeature.SUPPORTED
447+
features.signmessage = DeviceFeature.SUPPORTED
448+
features.setup = DeviceFeature.SUPPORTED
449+
features.wipe = DeviceFeature.SUPPORTED
450+
features.recover = DeviceFeature.SUPPORTED
451+
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
452+
features.sign_p2pkh = DeviceFeature.SUPPORTED
453+
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
454+
features.sign_p2wpkh = DeviceFeature.SUPPORTED
455+
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
456+
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
457+
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
458+
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
459+
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
460+
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
461+
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
462+
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
463+
features.sign_coinjoin = DeviceFeature.SUPPORTED
464+
features.sign_mixed_segwit = DeviceFeature.SUPPORTED
465+
features.display_address = DeviceFeature.SUPPORTED
466+
443467
def __init__(self, path, password='', expert=False):
444468
super(Trezor1Client, self).__init__(path, password, expert)
445469
self.type = 'Trezor 1'
446470

471+
@classmethod
472+
def get_features(self):
473+
return self.features.get_printable_dict()
474+
447475
class TrezorTClient(TrezorClient):
476+
477+
# Setup features
478+
features = SupportedFeatures()
479+
features.getxpub = DeviceFeature.SUPPORTED
480+
features.signmessage = DeviceFeature.SUPPORTED
481+
features.setup = DeviceFeature.SUPPORTED
482+
features.wipe = DeviceFeature.SUPPORTED
483+
features.recover = DeviceFeature.SUPPORTED
484+
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
485+
features.sign_p2pkh = DeviceFeature.SUPPORTED
486+
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
487+
features.sign_p2wpkh = DeviceFeature.SUPPORTED
488+
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
489+
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
490+
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
491+
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
492+
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
493+
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
494+
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
495+
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
496+
features.sign_coinjoin = DeviceFeature.SUPPORTED
497+
features.sign_mixed_segwit = DeviceFeature.FIRMWARE_NOT_SUPPORTED
498+
features.display_address = DeviceFeature.SUPPORTED
499+
448500
def __init__(self, path, password='', expert=False):
449501
super(TrezorTClient, self).__init__(path, password, expert)
450502
self.type = 'Trezor T'
451503

504+
@classmethod
505+
def get_features(self):
506+
return self.features.get_printable_dict()
507+
452508
def enumerate(password=''):
453509
results = []
454510
for dev in enumerate_devices():

hwilib/hwwclient.py

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

0 commit comments

Comments
 (0)