Skip to content

Commit

Permalink
Implement get_features for all clients.
Browse files Browse the repository at this point in the history
  • Loading branch information
achow101 committed Mar 26, 2020
1 parent 9262808 commit 3074bc1
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 8 deletions.
27 changes: 25 additions & 2 deletions hwilib/devices/coldcard.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Coldcard interaction script

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

# Setup features
features = SupportedFeatures()
features.getxpub = DeviceFeature.SUPPORTED
features.signmessage = DeviceFeature.SUPPORTED
features.setup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.wipe = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.recover = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.backup = DeviceFeature.SUPPORTED
features.sign_p2pkh = DeviceFeature.SUPPORTED
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
features.sign_p2wpkh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_coinjoin = DeviceFeature.SUPPORTED
features.sign_mixed_segwit = DeviceFeature.SUPPORTED
features.display_address = DeviceFeature.SUPPORTED

def __init__(self, path, password='', expert=False):
super(ColdcardClient, self).__init__(path, password, expert)
# Simulator hard coded pipe socket
Expand Down Expand Up @@ -245,7 +268,7 @@ def send_pin(self, pin):
# Get HWI features for this device
@classmethod
def get_features(self):
raise NotImplementedError('The Coldcard does not implement this method')
return self.features.get_printable_dict()

def enumerate(password=''):
results = []
Expand Down
27 changes: 25 additions & 2 deletions hwilib/devices/digitalbitbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import sys
import time

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

# Setup features
features = SupportedFeatures()
features.getxpub = DeviceFeature.SUPPORTED
features.signmessage = DeviceFeature.SUPPORTED
features.setup = DeviceFeature.SUPPORTED
features.wipe = DeviceFeature.SUPPORTED
features.recover = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.backup = DeviceFeature.SUPPORTED
features.sign_p2pkh = DeviceFeature.SUPPORTED
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
features.sign_p2wpkh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_bare = DeviceFeature.SUPPORTED
features.sign_arbitrary_bare = DeviceFeature.SUPPORTED
features.sign_arbitrary_p2sh = DeviceFeature.SUPPORTED
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.SUPPORTED
features.sign_arbitrary_p2wsh = DeviceFeature.SUPPORTED
features.sign_coinjoin = DeviceFeature.SUPPORTED
features.sign_mixed_segwit = DeviceFeature.SUPPORTED
features.display_address = DeviceFeature.FIRMWARE_NOT_SUPPORTED

def __init__(self, path, password, expert=False):
super(DigitalbitboxClient, self).__init__(path, password, expert)
if not password:
Expand Down Expand Up @@ -586,7 +609,7 @@ def send_pin(self, pin):
# Get HWI features for this device
@classmethod
def get_features(self):
raise NotImplementedError('The Digital Bitbox does not implement this method')
return self.features.get_printable_dict()

class Digitalbitbox01Client(DigitalbitboxClient):
def __init__(self, path, password='', expert=False):
Expand Down
29 changes: 29 additions & 0 deletions hwilib/devices/keepkey.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,46 @@
# KeepKey interaction script

from ..errors import DEVICE_NOT_INITIALIZED, DeviceNotReadyError, common_err_msgs, handle_errors
from ..hwwclient import DeviceFeature, SupportedFeatures
from .trezorlib.transport import enumerate_devices, KEEPKEY_VENDOR_IDS
from .trezor import TrezorClient
from ..base58 import get_xpub_fingerprint_hex

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

class KeepkeyClient(TrezorClient):

# Setup features
features = SupportedFeatures()
features.getxpub = DeviceFeature.SUPPORTED
features.signmessage = DeviceFeature.SUPPORTED
features.setup = DeviceFeature.SUPPORTED
features.wipe = DeviceFeature.SUPPORTED
features.recover = DeviceFeature.SUPPORTED
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_p2pkh = DeviceFeature.SUPPORTED
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
features.sign_p2wpkh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_coinjoin = DeviceFeature.SUPPORTED
features.sign_mixed_segwit = DeviceFeature.SUPPORTED
features.display_address = DeviceFeature.SUPPORTED

def __init__(self, path, password='', expert=False):
super(KeepkeyClient, self).__init__(path, password, expert)
self.type = 'Keepkey'

@classmethod
def get_features(self):
return self.features.get_printable_dict()

def enumerate(password=''):
results = []
for dev in enumerate_devices():
Expand Down
27 changes: 25 additions & 2 deletions hwilib/devices/ledger.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Ledger interaction script

from ..hwwclient import HardwareWalletClient
from ..hwwclient import DeviceFeature, HardwareWalletClient, SupportedFeatures
from ..errors import ActionCanceledError, BadArgumentError, DeviceConnectionError, DeviceFailureError, UnavailableActionError, common_err_msgs, handle_errors
from .btchip.bitcoinTransaction import bitcoinTransaction
from .btchip.btchip import btchip
Expand Down Expand Up @@ -72,6 +72,29 @@ def func(*args, **kwargs):
# This class extends the HardwareWalletClient for Ledger Nano S and Nano X specific things
class LedgerClient(HardwareWalletClient):

# Setup features
features = SupportedFeatures()
features.getxpub = DeviceFeature.SUPPORTED
features.signmessage = DeviceFeature.SUPPORTED
features.setup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.wipe = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.recover = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_p2pkh = DeviceFeature.SUPPORTED
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
features.sign_p2wpkh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_bare = DeviceFeature.SUPPORTED
features.sign_arbitrary_bare = DeviceFeature.SUPPORTED
features.sign_arbitrary_p2sh = DeviceFeature.SUPPORTED
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.SUPPORTED
features.sign_arbitrary_p2wsh = DeviceFeature.SUPPORTED
features.sign_coinjoin = DeviceFeature.SUPPORTED
features.sign_mixed_segwit = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.display_address = DeviceFeature.SUPPORTED

def __init__(self, path, password='', expert=False):
super(LedgerClient, self).__init__(path, password, expert)
self.type = 'Ledger Nano S and X'
Expand Down Expand Up @@ -358,7 +381,7 @@ def send_pin(self, pin):
# Get HWI features for this device
@classmethod
def get_features(self):
raise NotImplementedError('The Ledger Nano S and X does not implement this method')
return self.features.get_printable_dict()

class LedgerNanoSClient(LedgerClient):
def __init__(self, path, password='', expert=False):
Expand Down
60 changes: 58 additions & 2 deletions hwilib/devices/trezor.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Trezor interaction script

from ..hwwclient import HardwareWalletClient
from ..hwwclient import DeviceFeature, HardwareWalletClient, SupportedFeatures
from ..errors import ActionCanceledError, BadArgumentError, DeviceAlreadyInitError, DeviceAlreadyUnlockedError, DeviceConnectionError, DEVICE_NOT_INITIALIZED, DeviceNotReadyError, UnavailableActionError, common_err_msgs, handle_errors
from .trezorlib.client import TrezorClient as Trezor
from .trezorlib.debuglink import TrezorClientDebugLink
Expand Down Expand Up @@ -437,18 +437,74 @@ def send_pin(self, pin):
# Get HWI features for this device
@classmethod
def get_features(self):
raise NotImplementedError('The {} does not implement this method'.format(self.type))
raise UnavailableActionError('A specific Trezor model must be specified to get the features')

class Trezor1Client(TrezorClient):

# Setup features
features = SupportedFeatures()
features.getxpub = DeviceFeature.SUPPORTED
features.signmessage = DeviceFeature.SUPPORTED
features.setup = DeviceFeature.SUPPORTED
features.wipe = DeviceFeature.SUPPORTED
features.recover = DeviceFeature.SUPPORTED
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_p2pkh = DeviceFeature.SUPPORTED
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
features.sign_p2wpkh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_coinjoin = DeviceFeature.SUPPORTED
features.sign_mixed_segwit = DeviceFeature.SUPPORTED
features.display_address = DeviceFeature.SUPPORTED

def __init__(self, path, password='', expert=False):
super(Trezor1Client, self).__init__(path, password, expert)
self.type = 'Trezor 1'

@classmethod
def get_features(self):
return self.features.get_printable_dict()

class TrezorTClient(TrezorClient):

# Setup features
features = SupportedFeatures()
features.getxpub = DeviceFeature.SUPPORTED
features.signmessage = DeviceFeature.SUPPORTED
features.setup = DeviceFeature.SUPPORTED
features.wipe = DeviceFeature.SUPPORTED
features.recover = DeviceFeature.SUPPORTED
features.backup = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_p2pkh = DeviceFeature.SUPPORTED
features.sign_p2sh_p2wpkh = DeviceFeature.SUPPORTED
features.sign_p2wpkh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh = DeviceFeature.SUPPORTED
features.sign_multi_p2sh_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_p2wsh = DeviceFeature.SUPPORTED
features.sign_multi_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_bare = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2sh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2sh_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_arbitrary_p2wsh = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.sign_coinjoin = DeviceFeature.SUPPORTED
features.sign_mixed_segwit = DeviceFeature.FIRMWARE_NOT_SUPPORTED
features.display_address = DeviceFeature.SUPPORTED

def __init__(self, path, password='', expert=False):
super(TrezorTClient, self).__init__(path, password, expert)
self.type = 'Trezor T'

@classmethod
def get_features(self):
return self.features.get_printable_dict()

def enumerate(password=''):
results = []
for dev in enumerate_devices():
Expand Down
57 changes: 57 additions & 0 deletions hwilib/hwwclient.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,60 @@
# General device client class and related constants and enums

from enum import IntEnum

class DeviceFeature(IntEnum):
SUPPORTED = 1 # The device supports the feature and so does HWI
NOT_SUPPORTED = 2 # The device supports the feature but HWI has not implemented it yet
FIRMWARE_NOT_SUPPORTED = 3 # The firmware does not support the feature so HWI cannot

class SupportedFeatures(object):

def __init__(self):
self.getxpub = DeviceFeature.NOT_SUPPORTED
self.signmessage = DeviceFeature.NOT_SUPPORTED
self.setup = DeviceFeature.NOT_SUPPORTED
self.wipe = DeviceFeature.NOT_SUPPORTED
self.recover = DeviceFeature.NOT_SUPPORTED
self.backup = DeviceFeature.NOT_SUPPORTED
self.sign_p2pkh = DeviceFeature.NOT_SUPPORTED
self.sign_p2sh_p2wpkh = DeviceFeature.NOT_SUPPORTED
self.sign_p2wpkh = DeviceFeature.NOT_SUPPORTED
self.sign_multi_p2sh = DeviceFeature.NOT_SUPPORTED
self.sign_multi_p2sh_p2wsh = DeviceFeature.NOT_SUPPORTED
self.sign_multi_p2wsh = DeviceFeature.NOT_SUPPORTED
self.sign_multi_bare = DeviceFeature.NOT_SUPPORTED
self.sign_arbitrary_bare = DeviceFeature.NOT_SUPPORTED
self.sign_arbitrary_p2sh = DeviceFeature.NOT_SUPPORTED
self.sign_arbitrary_p2sh_p2wsh = DeviceFeature.NOT_SUPPORTED
self.sign_arbitrary_p2wsh = DeviceFeature.NOT_SUPPORTED
self.sign_coinjoin = DeviceFeature.NOT_SUPPORTED
self.sign_mixed_segwit = DeviceFeature.NOT_SUPPORTED
self.display_address = DeviceFeature.NOT_SUPPORTED

def get_printable_dict(self):
d = {}
d['getxpub'] = self.getxpub
d['signmessage'] = self.signmessage
d['setup'] = self.setup
d['wipe'] = self.wipe
d['recover'] = self.recover
d['backup'] = self.backup
d['sign_p2pkh'] = self.sign_p2pkh
d['sign_p2sh_p2wpkh'] = self.sign_p2sh_p2wpkh
d['sign_p2wpkh'] = self.sign_p2wpkh
d['sign_multi_p2sh'] = self.sign_multi_p2sh
d['sign_multi_p2sh_p2wsh'] = self.sign_multi_p2sh_p2wsh
d['sign_multi_p2wsh'] = self.sign_multi_p2wsh
d['sign_multi_bare'] = self.sign_multi_bare
d['sign_arbitrary_bare'] = self.sign_arbitrary_bare
d['sign_arbitrary_p2sh'] = self.sign_arbitrary_p2sh
d['sign_arbitrary_p2sh_p2wsh'] = self.sign_arbitrary_p2sh_p2wsh
d['sign_arbitrary_p2wsh'] = self.sign_arbitrary_p2wsh
d['sign_coinjoin'] = self.sign_coinjoin
d['sign_mixed_segwit'] = self.sign_mixed_segwit
d['display_address'] = self.display_address
return d

# This is an abstract class that defines all of the methods that each Hardware
# wallet subclass must implement.
class HardwareWalletClient(object):
Expand Down

0 comments on commit 3074bc1

Please sign in to comment.