Browse Source

qt: refactor SeedLayout/KeysLayout to SeedWidget/KeysWidget, remove the hacks left over from old to new wizard and

update validation in all cases (e.g. validate electrum seed when switching from bip39 to electrum in options dialog)
master
Sander van Grieken 1 year ago
parent
commit
97a7136b5f
No known key found for this signature in database
GPG Key ID: 9BCF8209EA402EBA
  1. 214
      electrum/gui/qt/seed_dialog.py
  2. 144
      electrum/gui/qt/wizard/wallet.py

214
electrum/gui/qt/seed_dialog.py

@ -69,66 +69,10 @@ def seed_warning_msg(seed):
]).format(len(seed.split())) ]).format(len(seed.split()))
class SeedLayout(QVBoxLayout): class SeedWidget(QWidget):
updated = pyqtSignal() updated = pyqtSignal()
validChanged = pyqtSignal([bool], arguments=['valid'])
def seed_options(self):
dialog = QDialog()
dialog.setWindowTitle(_("Seed Options"))
vbox = QVBoxLayout(dialog)
seed_types = [
(value, title) for value, title in (
('electrum', _('Electrum')),
('bip39', _('BIP39 seed')),
('slip39', _('SLIP39 seed')),
)
if value in self.options or value == 'electrum'
]
if 'ext' in self.options:
cb_ext = QCheckBox(_('Extend this seed with custom words'))
cb_ext.setChecked(self.is_ext)
vbox.addWidget(cb_ext)
if len(seed_types) >= 2:
def on_selected(idx):
self.seed_type = seed_type_choice.selected_key
self.is_seed = (lambda x: bool(x)) if self.seed_type != 'electrum' else self.saved_is_seed
self.slip39_current_mnemonic_invalid = None
self.seed_status.setText('')
self.on_edit()
if self.seed_type == 'bip39':
msg = ' '.join([
'<b>' + _('Warning') + ':</b> ',
_('BIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'),
_('However, we do not generate BIP39 seeds, because they do not meet our safety standard.'),
_('BIP39 seeds do not include a version number, which compromises compatibility with future software.'),
_('We do not guarantee that BIP39 imports will always be supported in Electrum.'),
])
elif self.seed_type == 'slip39':
msg = ' '.join([
'<b>' + _('Warning') + ':</b> ',
_('SLIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'),
_('However, we do not generate SLIP39 seeds.'),
])
else:
msg = ''
self.update_share_buttons()
self.initialize_completer()
self.seed_warning.setText(msg)
seed_type_choice = ChoiceWidget(message=_('Seed type'), choices=seed_types, selected=self.seed_type)
seed_type_choice.itemSelected.connect(on_selected)
vbox.addWidget(seed_type_choice)
vbox.addLayout(Buttons(OkButton(dialog)))
if not dialog.exec():
return None
self.is_ext = cb_ext.isChecked() if 'ext' in self.options else False
self.seed_type = seed_type_choice.selected_key if len(seed_types) >= 2 else 'electrum'
self.updated.emit()
def __init__( def __init__(
self, self,
@ -137,20 +81,38 @@ class SeedLayout(QVBoxLayout):
icon=True, icon=True,
msg=None, msg=None,
options=None, options=None,
is_seed=None, is_seed=None, # only used for electrum seeds
passphrase=None, passphrase=None,
parent=None, parent=None,
for_seed_words=True, for_seed_words=True,
*, *,
config: 'SimpleConfig', config: 'SimpleConfig',
): ):
QVBoxLayout.__init__(self) QWidget.__init__(self, parent)
self.parent = parent vbox = QVBoxLayout()
self.setLayout(vbox)
self.options = options self.options = options
self.config = config self.config = config
self.seed_type = 'electrum'
if options:
self.seed_types = [
(value, title) for value, title in (
('electrum', _('Electrum')),
('bip39', _('BIP39 seed')),
('slip39', _('SLIP39 seed')),
)
if value in self.options
]
assert len(self.seed_types)
self.seed_type = self.seed_types[0][0]
else:
self.seed_type = 'electrum'
self.is_seed = is_seed
if title: if title:
self.addWidget(WWLabel(title)) vbox.addWidget(WWLabel(title))
if seed: # "read only", we already have the text if seed: # "read only", we already have the text
if for_seed_words: if for_seed_words:
self.seed_e = ButtonsTextEdit() self.seed_e = ButtonsTextEdit()
@ -162,8 +124,6 @@ class SeedLayout(QVBoxLayout):
assert for_seed_words assert for_seed_words
self.seed_e = CompletionTextEdit() self.seed_e = CompletionTextEdit()
self.seed_e.setTabChangesFocus(False) # so that tab auto-completes self.seed_e.setTabChangesFocus(False) # so that tab auto-completes
self.is_seed = is_seed
self.saved_is_seed = self.is_seed
self.seed_e.textChanged.connect(self.on_edit) self.seed_e.textChanged.connect(self.on_edit)
self.initialize_completer() self.initialize_completer()
@ -176,7 +136,7 @@ class SeedLayout(QVBoxLayout):
logo.setMaximumWidth(60) logo.setMaximumWidth(60)
hbox.addWidget(logo) hbox.addWidget(logo)
hbox.addWidget(self.seed_e) hbox.addWidget(self.seed_e)
self.addLayout(hbox) vbox.addLayout(hbox)
hbox = QHBoxLayout() hbox = QHBoxLayout()
hbox.addStretch(1) hbox.addStretch(1)
self.seed_type_label = QLabel('') self.seed_type_label = QLabel('')
@ -187,7 +147,7 @@ class SeedLayout(QVBoxLayout):
if options: if options:
opt_button = EnterButton(_('Options'), self.seed_options) opt_button = EnterButton(_('Options'), self.seed_options)
hbox.addWidget(opt_button) hbox.addWidget(opt_button)
self.addLayout(hbox) vbox.addLayout(hbox)
if passphrase: if passphrase:
hbox = QHBoxLayout() hbox = QHBoxLayout()
passphrase_e = QLineEdit() passphrase_e = QLineEdit()
@ -195,7 +155,7 @@ class SeedLayout(QVBoxLayout):
passphrase_e.setReadOnly(True) passphrase_e.setReadOnly(True)
hbox.addWidget(QLabel(_("Your seed extension is") + ':')) hbox.addWidget(QLabel(_("Your seed extension is") + ':'))
hbox.addWidget(passphrase_e) hbox.addWidget(passphrase_e)
self.addLayout(hbox) vbox.addLayout(hbox)
# slip39 shares # slip39 shares
self.slip39_mnemonic_index = 0 self.slip39_mnemonic_index = 0
@ -211,15 +171,75 @@ class SeedLayout(QVBoxLayout):
self.next_share_btn.clicked.connect(self.on_next_share) self.next_share_btn.clicked.connect(self.on_next_share)
hbox.addWidget(self.next_share_btn) hbox.addWidget(self.next_share_btn)
self.update_share_buttons() self.update_share_buttons()
self.addLayout(hbox) vbox.addLayout(hbox)
self.addStretch(1) vbox.addStretch(1)
self.seed_status = WWLabel('') self.seed_status = WWLabel('')
self.addWidget(self.seed_status) vbox.addWidget(self.seed_status)
self.seed_warning = WWLabel('') self.seed_warning = WWLabel('')
if msg: if msg:
self.seed_warning.setText(seed_warning_msg(seed)) self.seed_warning.setText(seed_warning_msg(seed))
self.addWidget(self.seed_warning) else:
self.update_seed_warning()
vbox.addWidget(self.seed_warning)
def seed_options(self):
dialog = QDialog()
dialog.setWindowTitle(_("Seed Options"))
vbox = QVBoxLayout(dialog)
if 'ext' in self.options:
cb_ext = QCheckBox(_('Extend this seed with custom words'))
cb_ext.setChecked(self.is_ext)
vbox.addWidget(cb_ext)
def on_selected(idx):
self.seed_type = seed_type_choice.selected_key
self.slip39_current_mnemonic_invalid = None
self.seed_status.setText('')
self.update_seed_warning()
self.on_edit()
self.update_share_buttons()
self.initialize_completer()
if len(self.seed_types) > 1:
seed_type_choice = ChoiceWidget(message=_('Seed type'), choices=self.seed_types, selected=self.seed_type)
seed_type_choice.itemSelected.connect(on_selected)
vbox.addWidget(seed_type_choice)
vbox.addLayout(Buttons(OkButton(dialog)))
if not dialog.exec():
return None
if 'ext' in self.options:
self.is_ext = cb_ext.isChecked()
if len(self.seed_types) > 1:
self.seed_type = seed_type_choice.selected_key
self.update_seed_warning()
self.updated.emit()
def update_seed_warning(self):
if self.seed_type == 'bip39':
msg = ' '.join([
'<b>' + _('Warning') + ':</b> ',
_('BIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'),
_('However, we do not generate BIP39 seeds, because they do not meet our safety standard.'),
_('BIP39 seeds do not include a version number, which compromises compatibility with future software.'),
_('We do not guarantee that BIP39 imports will always be supported in Electrum.'),
])
elif self.seed_type == 'slip39':
msg = ' '.join([
'<b>' + _('Warning') + ':</b> ',
_('SLIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'),
_('However, we do not generate SLIP39 seeds.'),
])
else:
msg = ''
self.seed_warning.setText(msg)
def initialize_completer(self): def initialize_completer(self):
if self.seed_type != 'slip39': if self.seed_type != 'slip39':
@ -261,12 +281,12 @@ class SeedLayout(QVBoxLayout):
def on_edit(self): def on_edit(self):
s = ' '.join(self.get_seed_words()) s = ' '.join(self.get_seed_words())
b = self.is_seed(s)
if self.seed_type == 'bip39': if self.seed_type == 'bip39':
from electrum.keystore import bip39_is_checksum_valid from electrum.keystore import bip39_is_checksum_valid
is_checksum, is_wordlist = bip39_is_checksum_valid(s) is_checksum, is_wordlist = bip39_is_checksum_valid(s)
label = '' label = ''
if bool(s): valid = bool(s)
if valid:
label = ('' if is_checksum else _('BIP39 checksum failed')) if is_wordlist else _('Unknown BIP39 wordlist') label = ('' if is_checksum else _('BIP39 checksum failed')) if is_wordlist else _('Unknown BIP39 wordlist')
elif self.seed_type == 'slip39': elif self.seed_type == 'slip39':
self.slip39_mnemonics[self.slip39_mnemonic_index] = s self.slip39_mnemonics[self.slip39_mnemonic_index] = s
@ -287,15 +307,13 @@ class SeedLayout(QVBoxLayout):
self.seed_status.setText(seed_status) self.seed_status.setText(seed_status)
self.slip39_current_mnemonic_invalid = current_mnemonic_invalid self.slip39_current_mnemonic_invalid = current_mnemonic_invalid
b = self.slip39_seed is not None valid = self.slip39_seed is not None
self.update_share_buttons() self.update_share_buttons()
else: else:
valid = self.is_seed(s)
t = calc_seed_type(s) t = calc_seed_type(s)
label = _('Seed Type') + ': ' + t if t else '' label = _('Seed Type') + ': ' + t if t else ''
if t and not b: # electrum seed, but does not conform to dialog rules if t and not valid: # electrum seed, but does not conform to dialog rules
# FIXME we should just accept any electrum seed and "redirect" the wizard automatically.
# i.e. if user selected wallet_type=="standard" but entered a 2fa seed, accept and redirect
# if user selected wallet_type=="2fa" but entered a std electrum seed, accept and redirect
wiztype_fullname = _('Wallet with two-factor authentication') if is_any_2fa_seed_type(t) else _("Standard wallet") wiztype_fullname = _('Wallet with two-factor authentication') if is_any_2fa_seed_type(t) else _("Standard wallet")
msg = ' '.join([ msg = ' '.join([
'<b>' + _('Warning') + ':</b> ', '<b>' + _('Warning') + ':</b> ',
@ -307,7 +325,7 @@ class SeedLayout(QVBoxLayout):
self.seed_warning.setText("") self.seed_warning.setText("")
self.seed_type_label.setText(label) self.seed_type_label.setText(label)
self.parent.next_button.setEnabled(b) self.validChanged.emit(valid)
# disable suggestions if user already typed an unknown word # disable suggestions if user already typed an unknown word
for word in self.get_seed_words()[:-1]: for word in self.get_seed_words()[:-1]:
@ -354,7 +372,10 @@ class SeedLayout(QVBoxLayout):
self.slip39_current_mnemonic_invalid = None self.slip39_current_mnemonic_invalid = None
class KeysLayout(QVBoxLayout): class KeysWidget(QWidget):
validChanged = pyqtSignal([bool], arguments=['valid'])
def __init__( def __init__(
self, self,
parent=None, parent=None,
@ -364,29 +385,28 @@ class KeysLayout(QVBoxLayout):
*, *,
config: 'SimpleConfig', config: 'SimpleConfig',
): ):
QVBoxLayout.__init__(self) QWidget.__init__(self, parent)
self.parent = parent vbox = QVBoxLayout()
self.setLayout(vbox)
self.is_valid = is_valid self.is_valid = is_valid
self.text_e = ScanQRTextEdit(allow_multi=allow_multi, config=config) self.text_e = ScanQRTextEdit(allow_multi=allow_multi, config=config)
self.text_e.textChanged.connect(self.on_edit) self.text_e.textChanged.connect(self.on_edit)
if isinstance(header_layout, str): if isinstance(header_layout, str):
self.addWidget(WWLabel(header_layout)) vbox.addWidget(WWLabel(header_layout))
else: else:
self.addLayout(header_layout) vbox.addLayout(header_layout)
self.addWidget(self.text_e) vbox.addWidget(self.text_e)
def get_text(self): def get_text(self):
return self.text_e.text() return self.text_e.text()
def on_edit(self): def on_edit(self):
valid = False
try: try:
valid = self.is_valid(self.get_text()) valid = self.is_valid(self.get_text())
except Exception as e: except Exception as e:
self.parent.next_button.setToolTip(f'{_("Error")}: {str(e)}') valid = False
else: self.validChanged.emit(valid)
self.parent.next_button.setToolTip('')
self.parent.next_button.setEnabled(valid)
class SeedDialog(WindowModalDialog): class SeedDialog(WindowModalDialog):
@ -395,13 +415,7 @@ class SeedDialog(WindowModalDialog):
WindowModalDialog.__init__(self, parent, ('Electrum - ' + _('Seed'))) WindowModalDialog.__init__(self, parent, ('Electrum - ' + _('Seed')))
self.setMinimumWidth(400) self.setMinimumWidth(400)
vbox = QVBoxLayout(self) vbox = QVBoxLayout(self)
title = _("Your wallet generation seed is:") title = _("Your wallet generation seed is:")
slayout = SeedLayout( seed_widget = SeedWidget(title=title, seed=seed, msg=True, passphrase=passphrase, config=config)
title=title, vbox.addWidget(seed_widget)
seed=seed,
msg=True,
passphrase=passphrase,
config=config,
)
vbox.addLayout(slayout)
vbox.addLayout(Buttons(CloseButton(self))) vbox.addLayout(Buttons(CloseButton(self)))

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

@ -27,10 +27,9 @@ from electrum.wizard import NewWalletWizard
from electrum.gui.qt.bip39_recovery_dialog import Bip39RecoveryDialog from electrum.gui.qt.bip39_recovery_dialog import Bip39RecoveryDialog
from electrum.gui.qt.password_dialog import PasswordLayout, PW_NEW, MSG_ENTER_PASSWORD, PasswordLayoutForHW from electrum.gui.qt.password_dialog import PasswordLayout, PW_NEW, MSG_ENTER_PASSWORD, PasswordLayoutForHW
from electrum.gui.qt.seed_dialog import SeedLayout, MSG_PASSPHRASE_WARN_ISSUE4566, KeysLayout from electrum.gui.qt.seed_dialog import SeedWidget, MSG_PASSPHRASE_WARN_ISSUE4566, KeysWidget
from electrum.gui.qt.util import (PasswordLineEdit, char_width_in_lineedit, WWLabel, InfoButton, font_height, from electrum.gui.qt.util import (PasswordLineEdit, char_width_in_lineedit, WWLabel, InfoButton, font_height,
ChoiceWidget, MessageBoxMixin, WindowModalDialog, CancelButton, ChoiceWidget, MessageBoxMixin, icon_path)
Buttons, OkButton, icon_path)
if TYPE_CHECKING: if TYPE_CHECKING:
from electrum.simple_config import SimpleConfig from electrum.simple_config import SimpleConfig
@ -437,7 +436,7 @@ class WCCreateSeed(WalletWizardComponent):
WalletWizardComponent.__init__(self, parent, wizard, title=_('Wallet Seed')) WalletWizardComponent.__init__(self, parent, wizard, title=_('Wallet Seed'))
self._busy = True self._busy = True
self.seed_type = 'standard' if self.wizard.config.WIZARD_DONT_CREATE_SEGWIT else 'segwit' self.seed_type = 'standard' if self.wizard.config.WIZARD_DONT_CREATE_SEGWIT else 'segwit'
self.slayout = None self.seed_widget = None
self.seed = None self.seed = None
def on_ready(self): def on_ready(self):
@ -446,10 +445,10 @@ class WCCreateSeed(WalletWizardComponent):
QTimer.singleShot(1, self.create_seed) QTimer.singleShot(1, self.create_seed)
def apply(self): def apply(self):
if self.slayout: if self.seed_widget:
self.wizard_data['seed'] = self.seed self.wizard_data['seed'] = self.seed
self.wizard_data['seed_type'] = self.seed_type self.wizard_data['seed_type'] = self.seed_type
self.wizard_data['seed_extend'] = self.slayout.is_ext self.wizard_data['seed_extend'] = self.seed_widget.is_ext
self.wizard_data['seed_variant'] = 'electrum' self.wizard_data['seed_variant'] = 'electrum'
self.wizard_data['seed_extra_words'] = '' # empty default self.wizard_data['seed_extra_words'] = '' # empty default
@ -457,15 +456,15 @@ class WCCreateSeed(WalletWizardComponent):
self.busy = True self.busy = True
self.seed = mnemonic.Mnemonic('en').make_seed(seed_type=self.seed_type) self.seed = mnemonic.Mnemonic('en').make_seed(seed_type=self.seed_type)
self.slayout = SeedLayout( self.seed_widget = SeedWidget(
title=_('Your wallet generation seed is:'), title=_('Your wallet generation seed is:'),
seed=self.seed, seed=self.seed,
options=['ext'], options=['ext', 'electrum'],
msg=True, msg=True,
parent=self, parent=self,
config=self.wizard.config, config=self.wizard.config,
) )
self.layout().addLayout(self.slayout) self.layout().addWidget(self.seed_widget)
self.layout().addStretch(1) self.layout().addStretch(1)
self.busy = False self.busy = False
self.valid = True self.valid = True
@ -482,19 +481,16 @@ class WCConfirmSeed(WalletWizardComponent):
self.layout().addWidget(WWLabel(message)) self.layout().addWidget(WWLabel(message))
# TODO: SeedLayout assumes too much in parent, refactor SeedLayout self.seed_widget = SeedWidget(
# for now, fake parent.next_button.setEnabled
class Hack:
def setEnabled(self2, b):
self.valid = b
self.next_button = Hack()
self.slayout = SeedLayout(
is_seed=lambda x: x == self.wizard_data['seed'], is_seed=lambda x: x == self.wizard_data['seed'],
parent=self,
config=self.wizard.config, config=self.wizard.config,
) )
self.layout().addLayout(self.slayout)
def seed_valid_changed(valid):
self.valid = valid
self.seed_widget.validChanged.connect(seed_valid_changed)
self.layout().addWidget(self.seed_widget)
wizard.app.clipboard().clear() wizard.app.clipboard().clear()
@ -583,37 +579,39 @@ class WCHaveSeed(WalletWizardComponent, Logger):
WalletWizardComponent.__init__(self, parent, wizard, title=_('Enter Seed')) WalletWizardComponent.__init__(self, parent, wizard, title=_('Enter Seed'))
Logger.__init__(self) Logger.__init__(self)
self.slayout = None
self.layout().addWidget(WWLabel(_('Please enter your seed phrase in order to restore your wallet.'))) self.layout().addWidget(WWLabel(_('Please enter your seed phrase in order to restore your wallet.')))
# TODO: SeedLayout assumes too much in parent, refactor SeedLayout self.seed_widget = None
# for now, fake parent.next_button.setEnabled
class Hack:
def setEnabled(self2, b):
if not b:
self.valid = b
else:
self.validate()
self.next_button = Hack()
self.can_passphrase = True self.can_passphrase = True
def on_ready(self): def on_ready(self):
options = ['ext'] if self.wizard_data['wallet_type'] == '2fa' else ['ext', 'bip39', 'slip39'] options = ['ext', 'electrum', 'bip39', 'slip39']
self.slayout = SeedLayout( if self.wizard_data['wallet_type'] == '2fa':
options = ['ext', 'electrum']
else:
if self.params and 'seed_options' in self.params:
options = self.params['seed_options']
self.seed_widget = SeedWidget(
is_seed=self.is_seed, is_seed=self.is_seed,
options=options, options=options,
parent=self,
config=self.wizard.config, config=self.wizard.config,
) )
self.slayout.updated.connect(self.validate)
self.layout().addLayout(self.slayout) def seed_valid_changed(valid):
if not valid:
self.valid = valid
else:
self.validate()
self.seed_widget.validChanged.connect(seed_valid_changed)
self.seed_widget.updated.connect(self.validate)
self.layout().addWidget(self.seed_widget)
self.layout().addStretch(1) self.layout().addStretch(1)
def is_seed(self, x): def is_seed(self, x):
# really only used for electrum seeds. bip39 and slip39 are validated in SeedWidget
t = mnemonic.calc_seed_type(x) t = mnemonic.calc_seed_type(x)
if self.wizard_data['wallet_type'] == 'standard': if self.wizard_data['wallet_type'] == 'standard':
return mnemonic.is_seed(x) and not mnemonic.is_any_2fa_seed_type(t) return mnemonic.is_seed(x) and not mnemonic.is_any_2fa_seed_type(t)
@ -624,9 +622,9 @@ class WCHaveSeed(WalletWizardComponent, Logger):
return t in ['standard', 'segwit'] return t in ['standard', 'segwit']
def validate(self): def validate(self):
# precond: only call when SeedLayout deems seed a valid seed # precond: only call when SeedWidget deems seed a valid seed
seed = self.slayout.get_seed() seed = self.seed_widget.get_seed()
seed_variant = self.slayout.seed_type seed_variant = self.seed_widget.seed_type
wallet_type = self.wizard_data['wallet_type'] wallet_type = self.wizard_data['wallet_type']
seed_valid, seed_type, validation_message, self.can_passphrase = self.wizard.validate_seed(seed, seed_variant, wallet_type) seed_valid, seed_type, validation_message, self.can_passphrase = self.wizard.validate_seed(seed, seed_variant, wallet_type)
@ -646,13 +644,13 @@ class WCHaveSeed(WalletWizardComponent, Logger):
def apply(self): def apply(self):
cosigner_data = self.wizard.current_cosigner(self.wizard_data) cosigner_data = self.wizard.current_cosigner(self.wizard_data)
cosigner_data['seed'] = self.slayout.get_seed() cosigner_data['seed'] = self.seed_widget.get_seed()
cosigner_data['seed_variant'] = self.slayout.seed_type cosigner_data['seed_variant'] = self.seed_widget.seed_type
if self.slayout.seed_type == 'electrum': if self.seed_widget.seed_type == 'electrum':
cosigner_data['seed_type'] = mnemonic.calc_seed_type(self.slayout.get_seed()) cosigner_data['seed_type'] = mnemonic.calc_seed_type(self.seed_widget.get_seed())
else: else:
cosigner_data['seed_type'] = self.slayout.seed_type cosigner_data['seed_type'] = self.seed_widget.seed_type
cosigner_data['seed_extend'] = self.slayout.is_ext if self.can_passphrase else False cosigner_data['seed_extend'] = self.seed_widget.is_ext if self.can_passphrase else False
cosigner_data['seed_extra_words'] = '' # empty default cosigner_data['seed_extra_words'] = '' # empty default
@ -790,13 +788,13 @@ class WCCosignerKeystore(WalletWizardComponent):
# different from old wizard: master public key for sharing is now shown on this page # different from old wizard: master public key for sharing is now shown on this page
self.layout().addSpacing(20) self.layout().addSpacing(20)
self.layout().addWidget(WWLabel(_('Below is your master public key. Please share it with your cosigners'))) self.layout().addWidget(WWLabel(_('Below is your master public key. Please share it with your cosigners')))
slayout = SeedLayout( seed_widget = SeedWidget(
self.wizard_data['multisig_master_pubkey'], self.wizard_data['multisig_master_pubkey'],
icon=False, icon=False,
for_seed_words=False, for_seed_words=False,
config=self.wizard.config, config=self.wizard.config,
) )
self.layout().addLayout(slayout) self.layout().addWidget(seed_widget)
self.layout().addStretch(1) self.layout().addStretch(1)
def apply(self): def apply(self):
@ -811,7 +809,7 @@ class WCHaveMasterKey(WalletWizardComponent):
def __init__(self, parent, wizard): def __init__(self, parent, wizard):
WalletWizardComponent.__init__(self, parent, wizard, title=_('Create keystore from a master key')) WalletWizardComponent.__init__(self, parent, wizard, title=_('Create keystore from a master key'))
self.slayout = None self.keys_widget = None
self.message_create = ' '.join([ self.message_create = ' '.join([
_("To create a watching-only wallet, please enter your master public key (xpub/ypub/zpub)."), _("To create a watching-only wallet, please enter your master public key (xpub/ypub/zpub)."),
@ -827,16 +825,6 @@ class WCHaveMasterKey(WalletWizardComponent):
self.label.setMinimumWidth(400) self.label.setMinimumWidth(400)
self.header_layout.addWidget(self.label) self.header_layout.addWidget(self.label)
# TODO: KeysLayout assumes too much in parent, refactor KeysLayout
# for now, fake parent.next_button.setEnabled
class Hack:
def setEnabled(self2, b):
self.valid = b
def setToolTip(self2, b):
pass
self.next_button = Hack()
def on_ready(self): def on_ready(self):
if self.wizard_data['wallet_type'] == 'standard': if self.wizard_data['wallet_type'] == 'standard':
self.label.setText(self.message_create) self.label.setText(self.message_create)
@ -860,12 +848,19 @@ class WCHaveMasterKey(WalletWizardComponent):
return True return True
else: else:
raise Exception(f"unexpected wallet type: {self.wizard_data['wallet_type']}") raise Exception(f"unexpected wallet type: {self.wizard_data['wallet_type']}")
self.slayout = KeysLayout(parent=self, header_layout=self.header_layout, is_valid=is_valid,
allow_multi=False, config=self.wizard.config) self.keys_widget = KeysWidget(parent=self, header_layout=self.header_layout, is_valid=is_valid,
self.layout().addLayout(self.slayout) allow_multi=False, config=self.wizard.config)
def key_valid_changed(valid):
self.valid = valid
self.keys_widget.validChanged.connect(key_valid_changed)
self.layout().addWidget(self.keys_widget)
def apply(self): def apply(self):
text = self.slayout.get_text() text = self.keys_widget.get_text()
cosigner_data = self.wizard.current_cosigner(self.wizard_data) cosigner_data = self.wizard.current_cosigner(self.wizard_data)
cosigner_data['master_key'] = text cosigner_data['master_key'] = text
@ -942,25 +937,20 @@ class WCImport(WalletWizardComponent):
header_layout.addWidget(label) header_layout.addWidget(label)
header_layout.addWidget(InfoButton(WIF_HELP_TEXT), alignment=Qt.AlignmentFlag.AlignRight) header_layout.addWidget(InfoButton(WIF_HELP_TEXT), alignment=Qt.AlignmentFlag.AlignRight)
# TODO: KeysLayout assumes too much in parent, refactor KeysLayout
# for now, fake parent.next_button.setEnabled
class Hack:
def setEnabled(self2, b):
self.valid = b
def setToolTip(self2, b):
pass
self.next_button = Hack()
def is_valid(x) -> bool: def is_valid(x) -> bool:
return keystore.is_address_list(x) or keystore.is_private_key_list(x, raise_on_error=True) return keystore.is_address_list(x) or keystore.is_private_key_list(x, raise_on_error=True)
self.slayout = KeysLayout(parent=self, header_layout=header_layout, is_valid=is_valid, self.keys_widget = KeysWidget(header_layout=header_layout, is_valid=is_valid,
allow_multi=True, config=self.wizard.config) allow_multi=True, config=self.wizard.config)
self.layout().addLayout(self.slayout)
def key_valid_changed(valid):
self.valid = valid
self.keys_widget.validChanged.connect(key_valid_changed)
self.layout().addWidget(self.keys_widget)
def apply(self): def apply(self):
text = self.slayout.get_text() text = self.keys_widget.get_text()
if keystore.is_address_list(text): if keystore.is_address_list(text):
self.wizard_data['address_list'] = text self.wizard_data['address_list'] = text
elif keystore.is_private_key_list(text): elif keystore.is_private_key_list(text):

Loading…
Cancel
Save