commit 9c7fd44b58b4eb18711e9206654f92c8b21d0aae
parent eb60e0d2e092e2bddce2734a0bb2efdb6fd5437e
Author: ThomasV <thomasv@electrum.org>
Date: Sun, 21 Aug 2016 22:44:42 +0200
update ledger plugin
Diffstat:
3 files changed, 69 insertions(+), 64 deletions(-)
diff --git a/plugins/ledger/__init__.py b/plugins/ledger/__init__.py
@@ -3,5 +3,5 @@ from electrum.i18n import _
fullname = 'Ledger Wallet'
description = 'Provides support for Ledger hardware wallet'
requires = [('btchip', 'github.com/ledgerhq/btchip-python')]
-registers_keystore = ('hardware', 'btchip', _("Ledger wallet"))
+registers_keystore = ('hardware', 'ledger', _("Ledger wallet"))
available_for = ['qt', 'cmdline']
diff --git a/plugins/ledger/ledger.py b/plugins/ledger/ledger.py
@@ -27,26 +27,19 @@ except ImportError:
class Ledger_KeyStore(Hardware_KeyStore):
- wallet_type = 'btchip'
device = 'Ledger'
- def __init__(self):
- Hardware_KeyStore.__init__(self)
+ def __init__(self, d):
+ Hardware_KeyStore.__init__(self, d)
# Errors and other user interaction is done through the wallet's
# handler. The handler is per-window and preserved across
# device reconnects
- self.handler = None
self.force_watching_only = False
self.device_checked = False
self.signing = False
- self.client = None
- def get_derivation(self):
- return "m/44'/0'/%d'"%self.account_id
-
- def load(self, storage, name):
- self.xpub = storage.get('master_public_keys', {}).get(name)
- self.account_id = int(storage.get('account_id'))
+ def get_client(self):
+ return self.plugin.get_client()
def init_xpub(self):
client = self.get_client()
@@ -67,42 +60,6 @@ class Ledger_KeyStore(Hardware_KeyStore):
# Strip the leading "m/"
return BIP32_HW_Wallet.address_id(self, address)[2:]
- def get_public_key(self, bip32_path):
- # bip32_path is of the form 44'/0'/1'
- # S-L-O-W - we don't handle the fingerprint directly, so compute
- # it manually from the previous node
- # This only happens once so it's bearable
- self.get_client() # prompt for the PIN before displaying the dialog if necessary
- self.handler.show_message("Computing master public key")
- try:
- splitPath = bip32_path.split('/')
- if splitPath[0] == 'm':
- splitPath = splitPath[1:]
- bip32_path = bip32_path[2:]
- fingerprint = 0
- if len(splitPath) > 1:
- prevPath = "/".join(splitPath[0:len(splitPath) - 1])
- nodeData = self.get_client().getWalletPublicKey(prevPath)
- publicKey = compress_public_key(nodeData['publicKey'])
- h = hashlib.new('ripemd160')
- h.update(hashlib.sha256(publicKey).digest())
- fingerprint = unpack(">I", h.digest()[0:4])[0]
- nodeData = self.get_client().getWalletPublicKey(bip32_path)
- publicKey = compress_public_key(nodeData['publicKey'])
- depth = len(splitPath)
- lastChild = splitPath[len(splitPath) - 1].split('\'')
- if len(lastChild) == 1:
- childnum = int(lastChild[0])
- else:
- childnum = 0x80000000 | int(lastChild[0])
- xpub = "0488B21E".decode('hex') + chr(depth) + self.i4b(fingerprint) + self.i4b(childnum) + str(nodeData['chainCode']) + str(publicKey)
- except Exception, e:
- self.give_error(e, True)
- finally:
- self.handler.clear_dialog()
-
- return EncodeBase58Check(xpub)
-
def decrypt_message(self, pubkey, message, password):
self.give_error("Not supported")
@@ -318,6 +275,21 @@ class Ledger_KeyStore(Hardware_KeyStore):
return False, None, None
return True, response, response
+
+class LedgerPlugin(HW_PluginBase):
+ libraries_available = BTCHIP
+ keystore_class = Ledger_KeyStore
+ hw_type='ledger'
+ client = None
+
+ def btchip_is_connected(self, keystore):
+ try:
+ self.get_client().getFirmwareVersion()
+ except Exception as e:
+ self.print_error("get_client", str(e))
+ return False
+ return True
+
def get_client(self, force_pair=True, noPin=False):
aborted = False
client = self.client
@@ -389,15 +361,39 @@ class Ledger_KeyStore(Hardware_KeyStore):
return self.client
+ def get_public_key(self, bip32_path):
+ # bip32_path is of the form 44'/0'/1'
+ # S-L-O-W - we don't handle the fingerprint directly, so compute
+ # it manually from the previous node
+ # This only happens once so it's bearable
+ self.get_client() # prompt for the PIN before displaying the dialog if necessary
+ self.handler.show_message("Computing master public key")
+ try:
+ splitPath = bip32_path.split('/')
+ if splitPath[0] == 'm':
+ splitPath = splitPath[1:]
+ bip32_path = bip32_path[2:]
+ fingerprint = 0
+ if len(splitPath) > 1:
+ prevPath = "/".join(splitPath[0:len(splitPath) - 1])
+ nodeData = self.get_client().getWalletPublicKey(prevPath)
+ publicKey = compress_public_key(nodeData['publicKey'])
+ h = hashlib.new('ripemd160')
+ h.update(hashlib.sha256(publicKey).digest())
+ fingerprint = unpack(">I", h.digest()[0:4])[0]
+ nodeData = self.get_client().getWalletPublicKey(bip32_path)
+ publicKey = compress_public_key(nodeData['publicKey'])
+ depth = len(splitPath)
+ lastChild = splitPath[len(splitPath) - 1].split('\'')
+ if len(lastChild) == 1:
+ childnum = int(lastChild[0])
+ else:
+ childnum = 0x80000000 | int(lastChild[0])
+ xpub = "0488B21E".decode('hex') + chr(depth) + self.i4b(fingerprint) + self.i4b(childnum) + str(nodeData['chainCode']) + str(publicKey)
+ except Exception, e:
+ self.give_error(e, True)
+ finally:
+ self.handler.clear_dialog()
-class LedgerPlugin(HW_PluginBase):
- libraries_available = BTCHIP
- keystore_class = Ledger_KeyStore
+ return EncodeBase58Check(xpub)
- def btchip_is_connected(self, keystore):
- try:
- keystore.get_client().getFirmwareVersion()
- except Exception as e:
- self.print_error("get_client", str(e))
- return False
- return True
diff --git a/plugins/ledger/qt.py b/plugins/ledger/qt.py
@@ -25,12 +25,21 @@ class Plugin(LedgerPlugin):
window.show_error(_("Ledger device not detected.\nContinuing in watching-only mode."))
wallet.force_watching_only = True
- def on_create_wallet(self, keystore, wizard):
- assert type(keystore) == self.keystore_class
- keystore.handler = BTChipQTHandler(wizard)
- keystore.init_xpub()
- print keystore.xpub
- wizard.create_wallet(keystore, None)
+ def create_keystore(self, hw_type, derivation, wizard):
+ from electrum.keystore import hardware_keystore
+ # create keystore
+ handler = BTChipQTHandler(wizard)
+ client = self.get_client()
+ xpub = self.get_public_key(derivation)
+ d = {
+ 'xpub': self.xpub,
+ 'type': 'hardware',
+ 'hw_type': hw_type,
+ 'derivation': derivation
+ }
+ k = hardware_keystore(hw_type, d)
+ return k
+
class BTChipQTHandler(QtHandlerBase):