Browse Source

wizard: add bitbox02 new wallet init and checks to new wizard

master
Sander van Grieken 2 years ago
parent
commit
dd64b5c628
  1. 4
      electrum/gui/qt/wizard/wallet.py
  2. 2
      electrum/gui/qt/wizard/wizard.py
  3. 33
      electrum/plugins/bitbox02/bitbox02.py
  4. 75
      electrum/plugins/bitbox02/qt.py

4
electrum/gui/qt/wizard/wallet.py

@ -720,9 +720,9 @@ class WCScriptAndDerivation(WizardComponent, Logger):
self.apply()
cosigner_data = self.wizard.current_cosigner(self.wizard_data)
derivation_valid = is_bip32_derivation(cosigner_data['derivation_path'])
valid = is_bip32_derivation(cosigner_data['derivation_path'])
if derivation_valid:
if valid:
valid, error = self.wizard.check_multisig_constraints(self.wizard_data)
if not valid:
# TODO: user feedback

2
electrum/gui/qt/wizard/wizard.py

@ -167,7 +167,7 @@ class QEAbstractWizard(QDialog, MessageBoxMixin):
self.back_button.setText(_('Back') if self.can_go_back() else _('Cancel'))
self.back_button.setEnabled(not page.busy)
self.next_button.setText(_('Next') if not self.is_last(page.wizard_data) else _('Finish'))
self.next_button.setEnabled(page.valid)
self.next_button.setEnabled(not page.busy and page.valid)
self.main_widget.setVisible(not page.busy and not bool(page.error))
self.please_wait.setVisible(page.busy)
self.please_wait_l.setText(page.busy_msg if page.busy_msg else _("Please wait..."))

33
electrum/plugins/bitbox02/bitbox02.py

@ -31,13 +31,8 @@ _logger = get_logger(__name__)
try:
from bitbox02 import bitbox02
from bitbox02 import util
from bitbox02.communication import (
devices,
HARDENED,
u2fhid,
bitbox_api_protocol,
FirmwareVersionOutdatedException,
)
from bitbox02.communication import (devices, HARDENED, u2fhid, bitbox_api_protocol,
FirmwareVersionOutdatedException)
requirements_ok = True
except ImportError as e:
if not (isinstance(e, ModuleNotFoundError) and e.name == 'bitbox02'):
@ -45,6 +40,10 @@ except ImportError as e:
requirements_ok = False
class BitBox02NotInitialized(UserFacingException):
pass
class BitBox02Client(HardwareClientBase):
# handler is a BitBox02_Handler, importing it would lead to a circular dependency
def __init__(self, handler: HardwareHandlerBase, device: Device, config: SimpleConfig, *, plugin: HW_PluginBase):
@ -119,7 +118,7 @@ class BitBox02Client(HardwareClientBase):
bitbox02_config = self.config.get("bitbox02")
noise_keys = bitbox02_config.get("remote_static_noise_keys")
if noise_keys is not None:
if pubkey.hex() in [noise_key for noise_key in noise_keys]:
if pubkey.hex() in noise_keys:
return True
return False
@ -192,7 +191,7 @@ class BitBox02Client(HardwareClientBase):
def fail_if_not_initialized(self) -> None:
assert self.bitbox02_device
if not self.bitbox02_device.device_info()["initialized"]:
raise Exception(
raise BitBox02NotInitialized(
"Please initialize the BitBox02 using the BitBox app first before using the BitBox02 in electrum"
)
@ -248,12 +247,8 @@ class BitBox02Client(HardwareClientBase):
else:
raise Exception("invalid xtype:{}".format(xtype))
return self.bitbox02_device.btc_xpub(
keypath=xpub_keypath,
xpub_type=out_type,
coin=coin_network,
display=display,
)
return self.bitbox02_device.btc_xpub(keypath=xpub_keypath, xpub_type=out_type, coin=coin_network,
display=display)
@runs_in_hwd_thread
def label(self) -> str:
@ -565,6 +560,7 @@ class BitBox02Client(HardwareClientBase):
)
return signature
class BitBox02_KeyStore(Hardware_KeyStore):
hw_type = "bitbox02"
device = "BitBox02"
@ -600,7 +596,6 @@ class BitBox02_KeyStore(Hardware_KeyStore):
keypath = self.get_derivation_prefix() + "/%d/%d" % sequence
return client.sign_message(keypath, message.encode("utf-8"), script_type)
@runs_in_hwd_thread
def sign_transaction(self, tx: PartialTransaction, password: str):
if tx.is_complete():
@ -612,7 +607,6 @@ class BitBox02_KeyStore(Hardware_KeyStore):
try:
self.handler.show_message("Authorize Transaction...")
client.sign_transaction(self, tx, self.handler.get_wallet())
finally:
self.handler.finished()
@ -639,6 +633,7 @@ class BitBox02_KeyStore(Hardware_KeyStore):
self.logger.exception("")
self.handler.show_error(e)
class BitBox02Plugin(HW_PluginBase):
keystore_class = BitBox02_KeyStore
minimum_library = (6, 2, 0)
@ -700,9 +695,9 @@ class BitBox02Plugin(HW_PluginBase):
id_ = str(d['path'])
return device._replace(id_=id_)
# new wizard
def wizard_entry_for_device(self, device_info: 'DeviceInfo', *, new_wallet=True) -> str:
# Note: device_info.initialized for this hardware doesn't imply a seed is present,
# only that it has firmware installed
if new_wallet:
return 'bitbox02_start' if device_info.initialized else 'bitbox02_not_initialized'
else:

75
electrum/plugins/bitbox02/qt.py

@ -1,29 +1,20 @@
import threading
from functools import partial
from typing import TYPE_CHECKING
from PyQt5.QtWidgets import (
QPushButton,
QLabel,
QVBoxLayout,
QLineEdit,
QHBoxLayout,
)
from PyQt5.QtCore import Qt, QMetaObject, Q_RETURN_ARG, pyqtSlot
from electrum.gui.qt.util import (
WindowModalDialog,
OkButton,
ButtonsTextEdit,
)
from PyQt5.QtCore import Qt, QMetaObject, Q_RETURN_ARG, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import QLabel, QVBoxLayout, QLineEdit, QHBoxLayout
from electrum.i18n import _
from electrum.plugin import hook
from electrum.util import UserCancelled, UserFacingException
from .bitbox02 import BitBox02Plugin
from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
from ..hw_wallet.plugin import only_hook_if_libraries_available
from ..hw_wallet.plugin import only_hook_if_libraries_available, OperationCancelled
from electrum.gui.qt.wizard.wallet import WCScriptAndDerivation, WCHWUnlock, WCHWUninitialized, WCHWXPub
from electrum.gui.qt.util import WindowModalDialog, OkButton, ButtonsTextEdit
if TYPE_CHECKING:
from electrum.gui.qt.wizard.wallet import QENewWalletWizard
@ -77,7 +68,7 @@ class Plugin(BitBox02Plugin, QtPluginBase):
def extend_wizard(self, wizard: 'QENewWalletWizard'):
super().extend_wizard(wizard)
views = {
'bitbox02_start': {'gui': WCScriptAndDerivation},
'bitbox02_start': {'gui': WCBitbox02ScriptAndDerivation},
'bitbox02_xpub': {'gui': WCHWXPub},
'bitbox02_not_initialized': {'gui': WCHWUninitialized},
'bitbox02_unlock': {'gui': WCHWUnlock}
@ -92,12 +83,7 @@ class BitBox02_Handler(QtHandlerBase):
super(BitBox02_Handler, self).__init__(win, "BitBox02")
def name_multisig_account(self):
return QMetaObject.invokeMethod(
self,
"_name_multisig_account",
Qt.BlockingQueuedConnection,
Q_RETURN_ARG(str),
)
return QMetaObject.invokeMethod(self, "_name_multisig_account", Qt.BlockingQueuedConnection, Q_RETURN_ARG(str))
@pyqtSlot(result=str)
def _name_multisig_account(self):
@ -125,3 +111,46 @@ class BitBox02_Handler(QtHandlerBase):
dialog.setLayout(vbox)
dialog.exec_()
return name.text().strip()
class WCBitbox02ScriptAndDerivation(WCScriptAndDerivation):
def __init__(self, parent, wizard):
WCScriptAndDerivation.__init__(self, parent, wizard)
self._busy = True
self.title = ''
self.client = None
def on_ready(self):
super().on_ready()
_name, _info = self.wizard_data['hardware_device']
plugin = self.wizard.plugins.get_plugin(_info.plugin_name)
device_id = _info.device.id_
self.client = self.wizard.plugins.device_manager.client_by_id(device_id, scan_now=False)
if not self.client.handler:
self.client.handler = plugin.create_handler(self.wizard)
self.client.setupRunning = True
self.check_device()
def check_device(self):
self.error = None
self.valid = False
self.busy = True
def check_task():
try:
self.client.pairing_dialog()
self.title = _('Script type and Derivation path')
self.valid = True
except (UserCancelled, OperationCancelled):
self.error = _('Cancelled')
self.wizard.requestPrev.emit()
except UserFacingException as e:
self.error = str(e)
except Exception as e:
self.error = repr(e)
finally:
self.busy = False
t = threading.Thread(target=check_task, daemon=True)
t.start()

Loading…
Cancel
Save