URI: 
       tMerge pull request #1662 from LedgerHQ/ledger_plugin_redesign - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 4a7cc1c65f8e27523c95b8442e7dc0624d0535f0
   DIR parent 9930d5fd6f6fd269614a58182ac49d21b358f8f1
  HTML Author: Neil <kyuupichan@gmail.com>
       Date:   Sat, 30 Jan 2016 17:43:39 +0900
       
       Merge pull request #1662 from LedgerHQ/ledger_plugin_redesign
       
       Ledger plugin redesign
       Diffstat:
         M plugins/ledger/ledger.py            |      58 ++++++++++---------------------
         M plugins/ledger/qt.py                |      47 ++++++-------------------------
       
       2 files changed, 27 insertions(+), 78 deletions(-)
       ---
   DIR diff --git a/plugins/ledger/ledger.py b/plugins/ledger/ledger.py
       t@@ -9,7 +9,8 @@ from electrum.bitcoin import EncodeBase58Check, DecodeBase58Check, public_key_to
        from electrum.i18n import _
        from electrum.plugins import BasePlugin, hook
        from electrum.transaction import deserialize
       -from electrum.wallet import BIP44_Wallet
       +from ..hw_wallet import BIP44_HW_Wallet
       +
        
        from electrum.util import format_satoshis_plain, print_error, print_msg
        import hashlib
       t@@ -29,14 +30,14 @@ except ImportError:
            BTCHIP = False
        
        
       -class BTChipWallet(BIP44_Wallet):
       +class BTChipWallet(BIP44_HW_Wallet):
            wallet_type = 'btchip'
            device = 'Ledger'
       -    restore_wallet_class = BIP44_Wallet
       +    restore_wallet_class = BIP44_HW_Wallet
            max_change_outputs = 1
        
            def __init__(self, storage):
       -        BIP44_Wallet.__init__(self, storage)
       +        BIP44_HW_Wallet.__init__(self, storage)
                # Errors and other user interaction is done through the wallet's
                # handler.  The handler is per-window and preserved across
                # device reconnects
       t@@ -49,7 +50,7 @@ class BTChipWallet(BIP44_Wallet):
            def give_error(self, message, clear_client = False):
                print_error(message)
                if not self.signing:
       -            QMessageBox.warning(QDialog(), _('Warning'), _(message), _('OK'))
       +            self.handler.show_error(message)
                else:
                    self.signing = False
                if clear_client:
       t@@ -57,30 +58,9 @@ class BTChipWallet(BIP44_Wallet):
                    self.device_checked = False
                raise Exception(message)
        
       -    def get_action(self):
       -        pass
       -
       -    def can_create_accounts(self):
       -        return False
       -
       -    def can_change_password(self):
       -        return False
       -
       -    def is_watching_only(self):
       -        assert not self.has_seed()
       -        return self.force_watching_only
       -
            def address_id(self, address):
                # Strip the leading "m/"
       -        return BIP44_Wallet.address_id(self, address)[2:]
       -
       -    def get_client(self, noPin=False):
       -        return self.plugin.get_client(self, noPin=noPin)
       -
       -    def derive_xkeys(self, root, derivation, password):
       -        derivation = '/'.join(derivation.split('/')[1:])
       -        xpub = self.get_public_key(derivation)
       -        return xpub, None
       +        return BIP44_HW_Wallet.address_id(self, address)[2:]
        
            def get_public_key(self, bip32_path):
                # bip32_path is of the form 44'/0'/1'
       t@@ -91,6 +71,9 @@ class BTChipWallet(BIP44_Wallet):
                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])
       t@@ -111,13 +94,10 @@ class BTChipWallet(BIP44_Wallet):
                except Exception, e:
                    self.give_error(e, True)
                finally:
       -            self.handler.stop()
       +            self.handler.clear_dialog()
        
                return EncodeBase58Check(xpub)
        
       -    def i4b(self, x):
       -        return pack('>I', x)
       -
            def decrypt_message(self, pubkey, message, password):
                self.give_error("Not supported")
        
       t@@ -142,7 +122,7 @@ class BTChipWallet(BIP44_Wallet):
                        pin = pin.encode()
                        client.bad = True
                        self.device_checked = False
       -                self.get_client(True)
       +                self.plugin.get_client(self, True, True)
                    signature = self.get_client().signMessageSign(pin)
                except BTChipException, e:
                    if e.sw == 0x6a80:
       t@@ -152,7 +132,7 @@ class BTChipWallet(BIP44_Wallet):
                except Exception, e:
                    self.give_error(e, True)
                finally:
       -            self.handler.stop()
       +            self.handler.clear_dialog()
                client.bad = use2FA
                self.signing = False
        
       t@@ -239,7 +219,7 @@ class BTChipWallet(BIP44_Wallet):
                            transactionOutput = outputData['outputData']
                        if outputData['confirmationNeeded']:
                            # TODO : handle different confirmation types. For the time being only supports keyboard 2FA
       -                    self.handler.stop()
       +                    self.handler.clear_dialog()
                            if 'keycardData' in outputData:
                                pin2 = ""
                                for keycardIndex in range(len(outputData['keycardData'])):
       t@@ -269,7 +249,7 @@ class BTChipWallet(BIP44_Wallet):
                                pin = pin.encode()
                                client.bad = True
                                self.device_checked = False
       -                        self.get_client(True)
       +                        self.plugin.get_client(self, True, True)
                            self.handler.show_message("Signing ...")
                        else:
                            # Sign input with the provided PIN
       t@@ -282,7 +262,7 @@ class BTChipWallet(BIP44_Wallet):
                except Exception, e:
                    self.give_error(e, True)
                finally:
       -            self.handler.stop()
       +            self.handler.clear_dialog()
        
                # Reformat transaction
                inputIndex = 0
       t@@ -306,7 +286,7 @@ class BTChipWallet(BIP44_Wallet):
                    except Exception, e:
                        self.give_error(e, True)
                    finally:
       -                self.handler.stop()
       +                self.handler.clear_dialog()
                    pubKeyDevice = compress_public_key(nodeData['publicKey'])
                    self.device_checked = True
                    if pubKey != pubKeyDevice:
       t@@ -328,7 +308,7 @@ class BTChipWallet(BIP44_Wallet):
                            "the transaction being signed into the text-editor.\r\n\r\n" \
                            "Check that summary and then enter the second factor code here.\r\n" \
                            "Before clicking OK, re-plug the device once more (unplug it and plug it again if you read the second factor code on the same computer)")
       -        response = self.handler.prompt_auth(msg)
       +        response = self.handler.get_word(msg)
                if response is None:
                    return False, None, None
                return True, response, response
       t@@ -380,7 +360,7 @@ class LedgerPlugin(BasePlugin):
            def close_wallet(self, wallet):
                self.client = None
        
       -    def get_client(self, wallet, noPin=False):
       +    def get_client(self, wallet, force_pair=True, noPin=False):
                aborted = False
                client = self.client
                if not client or client.bad:
   DIR diff --git a/plugins/ledger/qt.py b/plugins/ledger/qt.py
       t@@ -7,6 +7,7 @@ import PyQt4.QtCore as QtCore
        from electrum.i18n import _
        from electrum.plugins import hook
        from .ledger import LedgerPlugin, BTChipWallet
       +from ..hw_wallet import QtHandlerBase
        
        class Plugin(LedgerPlugin):
        
       t@@ -29,48 +30,16 @@ class Plugin(LedgerPlugin):
        #        self.select_device(wallet)
                wallet.create_hd_account(None)
        
       -class BTChipQTHandler:
       +class BTChipQTHandler(QtHandlerBase):
        
            def __init__(self, win):
       -        self.win = win
       -        self.win.connect(win, SIGNAL('btchip_done'), self.dialog_stop)
       -        self.win.connect(win, SIGNAL('btchip_message_dialog'), self.message_dialog)
       -        self.win.connect(win, SIGNAL('btchip_auth_dialog'), self.auth_dialog)
       -        self.done = threading.Event()
       +        super(BTChipQTHandler, self).__init__(win, 'Ledger')
        
       -    def stop(self):
       -        self.win.emit(SIGNAL('btchip_done'))
        
       -    def show_message(self, msg):
       -        self.message = msg
       -        self.win.emit(SIGNAL('btchip_message_dialog'))
       -
       -    def prompt_auth(self, msg):
       -        self.done.clear()
       -        self.message = msg
       -        self.win.emit(SIGNAL('btchip_auth_dialog'))
       -        self.done.wait()
       -        return self.response
       -
       -    def auth_dialog(self):
       -        response = QInputDialog.getText(None, "Ledger Wallet Authentication", self.message, QLineEdit.Password)
       +    def word_dialog(self, msg):
       +        response = QInputDialog.getText(self.top_level_window(), "Ledger Wallet Authentication", msg, QLineEdit.Password)
                if not response[1]:
       -            self.response = None
       +            self.word = None
                else:
       -            self.response = str(response[0])
       -        self.done.set()
       -
       -    def message_dialog(self):
       -        self.d = QDialog()
       -        self.d.setModal(1)
       -        self.d.setWindowTitle('Ledger')
       -        self.d.setWindowFlags(self.d.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
       -        l = QLabel(self.message)
       -        vbox = QVBoxLayout(self.d)
       -        vbox.addWidget(l)
       -        self.d.show()
       -
       -    def dialog_stop(self):
       -        if self.d is not None:
       -            self.d.hide()
       -            self.d = None
       +            self.word = str(response[0])
       +        self.done.set()