tQt addresses list: show derivation path in tooltip (also addr dialog) - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit d8180c678b9f476da9807556debf1974284e3825
 (DIR) parent 09b3c8052982dc1fdcada054db0665c097743e57
 (HTM) Author: SomberNight <somber.night@protonmail.com>
       Date:   Sun,  1 Mar 2020 05:45:15 +0100
       
       Qt addresses list: show derivation path in tooltip (also addr dialog)
       
       related: #5641
       
       Diffstat:
         M electrum/address_synchronizer.py    |       2 +-
         M electrum/gui/qt/address_dialog.py   |       8 ++++++++
         M electrum/gui/qt/address_list.py     |       3 +++
         M electrum/gui/qt/util.py             |       4 ++--
         M electrum/wallet.py                  |      18 +++++++++++++++++-
       
       5 files changed, 31 insertions(+), 4 deletions(-)
       ---
 (DIR) diff --git a/electrum/address_synchronizer.py b/electrum/address_synchronizer.py
       t@@ -777,7 +777,7 @@ class AddressSynchronizer(Logger):
                return sum([v for height, v, is_cb in received.values()])
        
            @with_local_height_cached
       -    def get_addr_balance(self, address, *, excluded_coins: Set[str] = None):
       +    def get_addr_balance(self, address, *, excluded_coins: Set[str] = None) -> Tuple[int, int, int]:
                """Return the balance of a bitcoin address:
                confirmed and matured, unconfirmed, unmatured
                """
 (DIR) diff --git a/electrum/gui/qt/address_dialog.py b/electrum/gui/qt/address_dialog.py
       t@@ -98,6 +98,14 @@ class AddressDialog(WindowModalDialog):
                    witness_e.addCopyButton(self.app)
                    vbox.addWidget(witness_e)
        
       +        address_path_str = self.wallet.get_address_path_str(address)
       +        if address_path_str:
       +            vbox.addWidget(QLabel(_("Derivation path") + ':'))
       +            der_path_e = ButtonsLineEdit(address_path_str)
       +            der_path_e.addCopyButton(self.app)
       +            der_path_e.setReadOnly(True)
       +            vbox.addWidget(der_path_e)
       +
                vbox.addWidget(QLabel(_("History")))
                addr_hist_model = AddressHistoryModel(self.parent, self.address)
                self.hw = HistoryList(self.parent, addr_hist_model)
 (DIR) diff --git a/electrum/gui/qt/address_list.py b/electrum/gui/qt/address_list.py
       t@@ -187,6 +187,9 @@ class AddressList(MyTreeView):
                        address_item[self.Columns.TYPE].setText(_('receiving'))
                        address_item[self.Columns.TYPE].setBackground(ColorScheme.GREEN.as_color(True))
                    address_item[self.Columns.LABEL].setData(address, Qt.UserRole)
       +            address_path_str = self.wallet.get_address_path_str(address)
       +            if address_path_str is not None:
       +                address_item[self.Columns.TYPE].setToolTip(address_path_str)
                    # setup column 1
                    if self.wallet.is_frozen_address(address):
                        address_item[self.Columns.ADDRESS].setBackground(ColorScheme.BLUE.as_color(True))
 (DIR) diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py
       t@@ -463,7 +463,7 @@ def filename_field(parent, config, defaultname, select_msg):
            return vbox, filename_e, b1
        
        class ElectrumItemDelegate(QStyledItemDelegate):
       -    def __init__(self, tv):
       +    def __init__(self, tv: 'MyTreeView'):
                super().__init__(tv)
                self.tv = tv
                self.opened = None
       t@@ -529,7 +529,7 @@ class MyTreeView(QTreeView):
                items = self.selectionModel().selectedIndexes()
                return list(x for x in items if x.column() == column)
        
       -    def current_item_user_role(self, col) -> Optional[QStandardItem]:
       +    def current_item_user_role(self, col) -> Any:
                idx = self.selectionModel().currentIndex()
                idx = idx.sibling(idx.row(), col)
                item = self.model().itemFromIndex(idx)
 (DIR) diff --git a/electrum/wallet.py b/electrum/wallet.py
       t@@ -44,7 +44,7 @@ from abc import ABC, abstractmethod
        import itertools
        
        from .i18n import _
       -from .bip32 import BIP32Node
       +from .bip32 import BIP32Node, convert_bip32_intpath_to_strpath
        from .crypto import sha256
        from .util import (NotEnoughFunds, UserCancelled, profiler,
                           format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
       t@@ -442,6 +442,13 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
                pass
        
            @abstractmethod
       +    def get_address_path_str(self, address: str) -> Optional[str]:
       +        """Returns derivation path str such as "m/0/5" to address,
       +        or None if not applicable.
       +        """
       +        pass
       +
       +    @abstractmethod
            def get_redeem_script(self, address: str) -> Optional[str]:
                pass
        
       t@@ -2029,6 +2036,9 @@ class Imported_Wallet(Simple_Wallet):
                # returns None if address is not mine
                return self.get_public_key(address)
        
       +    def get_address_path_str(self, address):
       +        return None
       +
            def get_public_key(self, address) -> Optional[str]:
                x = self.db.get_imported_address(address)
                return x.get('pubkey') if x else None
       t@@ -2252,6 +2262,12 @@ class Deterministic_Wallet(Abstract_Wallet):
            def get_address_index(self, address) -> Optional[Sequence[int]]:
                return self.db.get_address_index(address) or self._ephemeral_addr_to_addr_index.get(address)
        
       +    def get_address_path_str(self, address):
       +        intpath = self.get_address_index(address)
       +        if intpath is None:
       +            return None
       +        return convert_bip32_intpath_to_strpath(intpath)
       +
            def _learn_derivation_path_for_address_from_txinout(self, txinout, address):
                for ks in self.get_keystores():
                    pubkey, der_suffix = ks.find_my_pubkey_in_txinout(txinout, only_der_suffix=True)