wizard: add bitbox02 new wallet init and checks to new wizard
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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..."))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user