Skip to content

Commit 3dc1eed

Browse files
committed
Implement get_features for all clients.
1 parent 1c8049d commit 3dc1eed

File tree

6 files changed

+219
-8
lines changed

6 files changed

+219
-8
lines changed

hwilib/devices/coldcard.py

+25-2
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=''):
4063
super(ColdcardClient, self).__init__(path, password)
4164
# Simulator hard coded pipe socket
@@ -240,7 +263,7 @@ def send_pin(self, pin):
240263
# Get HWI features for this device
241264
@classmethod
242265
def get_features(self):
243-
raise NotImplementedError('The Coldcard does not implement this method')
266+
return self.features.get_printable_dict()
244267

245268
def enumerate(password=''):
246269
results = []

hwilib/devices/digitalbitbox.py

+25-2
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, 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):
300323
super(DigitalbitboxClient, self).__init__(path, password)
301324
if not password:
@@ -581,7 +604,7 @@ def send_pin(self, pin):
581604
# Get HWI features for this device
582605
@classmethod
583606
def get_features(self):
584-
raise NotImplementedError('The Digital Bitbox does not implement this method')
607+
return self.features.get_printable_dict()
585608

586609
class Digitalbitbox01Client(DigitalbitboxClient):
587610
def __init__(self, path, password=''):

hwilib/devices/keepkey.py

+29
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=''):
1237
super(KeepkeyClient, self).__init__(path, password)
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

+25-2
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=''):
7699
super(LedgerClient, self).__init__(path, password)
77100
self.type = 'Ledger Nano S and X'
@@ -351,7 +374,7 @@ def send_pin(self, pin):
351374
# Get HWI features for this device
352375
@classmethod
353376
def get_features(self):
354-
raise NotImplementedError('The Ledger Nano S and X does not implement this method')
377+
return self.features.get_printable_dict()
355378

356379
class LedgerNanoSClient(LedgerClient):
357380
def __init__(self, path, password=''):

hwilib/devices/trezor.py

+58-2
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
@@ -432,18 +432,74 @@ def send_pin(self, pin):
432432
# Get HWI features for this device
433433
@classmethod
434434
def get_features(self):
435-
raise NotImplementedError('The {} does not implement this method'.format(self.type))
435+
raise UnavailableActionError('A specific Trezor model must be specified to get the features')
436436

437437
class Trezor1Client(TrezorClient):
438+
439+
# Setup features
440+
features = SupportedFeatures()
441+
features.getxpub = DeviceFeature.SUPPORTED
442+
features.signmessage = DeviceFeature.SUPPORTED
443+
features.setup = DeviceFeature.SUPPORTED
444+
features.wipe = DeviceFeature.SUPPORTED
445+
features.recover = DeviceFeature.SUPPORTED
446+
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
447+
features.sign_p2pkh = DeviceFeature.SUPPORTED
448+
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
449+
features.sign_p2wpkh = DeviceFeature.SUPPORTED
450+
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
451+
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
452+
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
453+
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
454+
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
455+
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
456+
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
457+
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
458+
features.sign_coinjoin = DeviceFeature.SUPPORTED
459+
features.sign_mixed_segwit = DeviceFeature.SUPPORTED
460+
features.display_address = DeviceFeature.SUPPORTED
461+
438462
def __init__(self, path, password=''):
439463
super(Trezor1Client, self).__init__(path, password)
440464
self.type = 'Trezor 1'
441465

466+
@classmethod
467+
def get_features(self):
468+
return self.features.get_printable_dict()
469+
442470
class TrezorTClient(TrezorClient):
471+
472+
# Setup features
473+
features = SupportedFeatures()
474+
features.getxpub = DeviceFeature.SUPPORTED
475+
features.signmessage = DeviceFeature.SUPPORTED
476+
features.setup = DeviceFeature.SUPPORTED
477+
features.wipe = DeviceFeature.SUPPORTED
478+
features.recover = DeviceFeature.SUPPORTED
479+
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
480+
features.sign_p2pkh = DeviceFeature.SUPPORTED
481+
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
482+
features.sign_p2wpkh = DeviceFeature.SUPPORTED
483+
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
484+
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
485+
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
486+
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
487+
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
488+
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
489+
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
490+
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
491+
features.sign_coinjoin = DeviceFeature.SUPPORTED
492+
features.sign_mixed_segwit = DeviceFeature.FIRMWARE_NOT_SUPPORTED
493+
features.display_address = DeviceFeature.SUPPORTED
494+
443495
def __init__(self, path, password=''):
444496
super(TrezorTClient, self).__init__(path, password)
445497
self.type = 'Trezor T'
446498

499+
@classmethod
500+
def get_features(self):
501+
return self.features.get_printable_dict()
502+
447503
def enumerate(password=''):
448504
results = []
449505
for dev in enumerate_devices():

hwilib/hwwclient.py

+57
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)