Browse Source

update ledger plugin

283
ThomasV 9 years ago
parent
commit
9c7fd44b58
  1. 2
      plugins/ledger/__init__.py
  2. 110
      plugins/ledger/ledger.py
  3. 21
      plugins/ledger/qt.py

2
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']

110
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

21
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):

Loading…
Cancel
Save