Browse Source

qml: refactor is_last checks to mostly lambdas, add multisig flow for 1st cosigner keystore,

add initial flow and view placeholders for additional cosigners.
patch-4
Sander van Grieken 2 years ago
parent
commit
5246f3d510
  1. 19
      electrum/gui/qml/components/wizard/WCCosignerKey.qml
  2. 39
      electrum/gui/qml/components/wizard/WCCosignerKeystore.qml
  3. 19
      electrum/gui/qml/components/wizard/WCCosignerSeed.qml
  4. 2
      electrum/gui/qml/components/wizard/WCMultisig.qml
  5. 65
      electrum/gui/qml/components/wizard/WCShowMasterPubkey.qml
  6. 13
      electrum/gui/qml/qebitcoin.py
  7. 6
      electrum/gui/qml/qewizard.py
  8. 4
      electrum/plugins/trustedcoin/qml.py
  9. 50
      electrum/wizard.py

19
electrum/gui/qml/components/wizard/WCCosignerKey.qml

@ -0,0 +1,19 @@
import QtQuick 2.6
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.1
import org.electrum 1.0
import "../controls"
WizardComponent {
id: root
valid: false
ColumnLayout {
Label {
text: qsTr('TODO: Cosigner key entry')
}
}
}

39
electrum/gui/qml/components/wizard/WCCosignerKeystore.qml

@ -0,0 +1,39 @@
import QtQuick 2.6
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.1
import org.electrum 1.0
import "../controls"
WizardComponent {
id: root
valid: keystoregroup.checkedButton !== null
function apply() {
wizard_data['cosigner_keystore_type'] = keystoregroup.checkedButton.keystoretype
}
ButtonGroup {
id: keystoregroup
}
ColumnLayout {
Label {
text: qsTr('Add a cosigner to your multi-sig wallet')
}
RadioButton {
ButtonGroup.group: keystoregroup
property string keystoretype: 'key'
checked: true
text: qsTr('Cosigner key')
}
RadioButton {
ButtonGroup.group: keystoregroup
property string keystoretype: 'seed'
text: qsTr('Cosigner seed')
}
}
}

19
electrum/gui/qml/components/wizard/WCCosignerSeed.qml

@ -0,0 +1,19 @@
import QtQuick 2.6
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.1
import org.electrum 1.0
import "../controls"
WizardComponent {
id: root
valid: false
ColumnLayout {
Label {
text: qsTr('TODO: Cosigner seed entry')
}
}
}

2
electrum/gui/qml/components/wizard/WCMultisig.qml

@ -24,8 +24,10 @@ WizardComponent {
}
function apply() {
wizard_data['multisig'] = true
wizard_data['multisig_participants'] = participants
wizard_data['multisig_signatures'] = signatures
wizard_data['multisig_cosigner_data'] = {}
}
ColumnLayout {

65
electrum/gui/qml/components/wizard/WCShowMasterPubkey.qml

@ -0,0 +1,65 @@
import QtQuick 2.6
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.1
import org.electrum 1.0
import "../controls"
WizardComponent {
valid: true
property string masterPubkey: ''
ColumnLayout {
width: parent.width
Label {
text: qsTr('Here is your master public key. Please share it with your cosigners')
Layout.fillWidth: true
wrapMode: Text.Wrap
}
TextHighlightPane {
Layout.fillWidth: true
padding: 0
leftPadding: constants.paddingSmall
RowLayout {
width: parent.width
Label {
Layout.fillWidth: true
text: masterPubkey
font.pixelSize: constants.fontSizeMedium
font.family: FixedFont
wrapMode: Text.Wrap
}
ToolButton {
icon.source: '../../../icons/share.png'
icon.color: 'transparent'
onClicked: {
var dialog = app.genericShareDialog.createObject(app,
{ title: qsTr('Master public key'), text: masterPubkey }
)
dialog.open()
}
}
}
}
}
Bitcoin {
id: bitcoin
}
onReadyChanged: {
if (!ready)
return
if (wizard_data['seed_variant'] == 'electrum') {
masterPubkey = bitcoin.getMultisigMasterPubkey(wizard_data['seed_variant'], wizard_data['seed'], wizard_data['seed_extra_words'])
} else {
masterPubkey = bitcoin.getMultisigMasterPubkey(wizard_data['seed_variant'], wizard_data['seed'], wizard_data['seed_extra_words'], wizard_data['derivation_path'])
}
}
}

13
electrum/gui/qml/qebitcoin.py

@ -169,3 +169,16 @@ class QEBitcoin(QObject):
def isPrivateKeyList(self, csv: str):
return keystore.is_private_key_list(csv)
@pyqtSlot(str, str, str, result=str)
@pyqtSlot(str, str, str, str, result=str)
def getMultisigMasterPubkey(self, seed_variant, seed, seed_extra_words, derivation_path = None):
if seed_variant == 'electrum':
k = keystore.from_seed(seed, seed_extra_words, True)
elif seed_variant == 'bip39':
root_seed = keystore.bip39_to_seed(seed, seed_extra_words)
derivation = normalize_bip32_derivation(derivation_path)
k = keystore.from_bip43_rootseed(root_seed, derivation, xtype='p2wsh')
else:
raise Exception(f'Unsupported seed variant {seed_variant}')
return k.get_master_public_key()

6
electrum/gui/qml/qewizard.py

@ -60,6 +60,10 @@ class QENewWalletWizard(NewWalletWizard, QEAbstractWizard):
'bip39_refine': { 'gui': 'WCBIP39Refine' },
'have_master_key': { 'gui': 'WCHaveMasterKey' },
'multisig': { 'gui': 'WCMultisig' },
'multisig_show_masterpubkey': { 'gui': 'WCShowMasterPubkey' },
'multisig_cosigner_keystore': { 'gui': 'WCCosignerKeystore' },
'multisig_cosigner_key': { 'gui': 'WCCosignerKey' },
'multisig_cosigner_seed': { 'gui': 'WCCosignerSeed' },
'imported': { 'gui': 'WCImport' },
'wallet_password': { 'gui': 'WCWalletPassword' }
})
@ -74,7 +78,7 @@ class QENewWalletWizard(NewWalletWizard, QEAbstractWizard):
self._path = path
self.pathChanged.emit()
def last_if_single_password(self, *args):
def is_single_password(self):
return self._daemon.singlePasswordEnabled
@pyqtSlot('QJSValue', bool, str)

4
electrum/plugins/trustedcoin/qml.py

@ -329,7 +329,7 @@ class Plugin(TrustedCoinPlugin):
'next': lambda d: 'trustedcoin_tos_email' if d['trustedcoin_keepordisable'] != 'disable'
else 'wallet_password',
'accept': self.recovery_disable,
'last': lambda v,d: wizard.last_if_single_password() and d['trustedcoin_keepordisable'] == 'disable'
'last': lambda v,d: wizard.is_single_password() and d['trustedcoin_keepordisable'] == 'disable'
},
'trustedcoin_tos_email': {
'gui': '../../../../plugins/trustedcoin/qml/Terms',
@ -339,7 +339,7 @@ class Plugin(TrustedCoinPlugin):
'gui': '../../../../plugins/trustedcoin/qml/ShowConfirmOTP',
'accept': self.on_accept_otp_secret,
'next': 'wallet_password',
'last': wizard.last_if_single_password
'last': lambda v,d: wizard.is_single_password()
}
}
wizard.navmap_merge(views)

50
electrum/wizard.py

@ -148,27 +148,39 @@ class NewWalletWizard(AbstractWizard):
'next': 'confirm_seed'
},
'confirm_seed': {
'next': 'wallet_password',
'last': self.last_if_single_password
'next': lambda d: 'wallet_password' if not self.is_multisig(d) else 'multisig_show_masterpubkey',
'last': lambda v,d: self.is_single_password()
},
'have_seed': {
'next': self.on_have_seed,
'last': self.last_if_single_password_and_not_bip39
'last': lambda v,d: self.is_single_password() and not self.is_bip39_seed(d) and not self.is_multisig(d)
},
'bip39_refine': {
'next': 'wallet_password',
'last': self.last_if_single_password
'next': lambda d: 'wallet_password' if not self.is_multisig(d) else 'multisig_show_masterpubkey',
'last': lambda v,d: self.is_single_password()
},
'have_master_key': {
'next': 'wallet_password',
'last': self.last_if_single_password
'next': lambda d: 'wallet_password' if not self.is_multisig(d) else 'multisig_show_masterpubkey',
'last': lambda v,d: self.is_single_password()
},
'multisig': {
'next': 'first_cosigner'
'next': 'keystore_type'
},
'multisig_show_masterpubkey': {
'next': 'multisig_cosigner_keystore'
},
'multisig_cosigner_keystore': {
'next': self.on_cosigner_keystore_type
},
'multisig_cosigner_key': {
'next': 'multisig_cosigner_keystore' # TODO
},
'multisig_cosigner_seed': {
'next': 'multisig_cosigner_keystore' # TODO
},
'imported': {
'next': 'wallet_password',
'last': self.last_if_single_password
'last': lambda v,d: self.is_single_password()
},
'wallet_password': {
'last': True
@ -181,11 +193,14 @@ class NewWalletWizard(AbstractWizard):
self._current = WizardViewState('wallet_name', initial_data, {})
return self._current
def last_if_single_password(self, view, wizard_data):
def is_single_password(self):
raise NotImplementedError()
def last_if_single_password_and_not_bip39(self, view, wizard_data):
return self.last_if_single_password(view, wizard_data) and not wizard_data['seed_variant'] == 'bip39'
def is_bip39_seed(self, wizard_data):
return wizard_data['seed_variant'] == 'bip39'
def is_multisig(self, wizard_data):
return 'multisig' in wizard_data and wizard_data['multisig'] == True
def on_wallet_type(self, wizard_data):
t = wizard_data['wallet_type']
@ -205,11 +220,20 @@ class NewWalletWizard(AbstractWizard):
}.get(t)
def on_have_seed(self, wizard_data):
if (wizard_data['seed_type'] == 'bip39'):
if self.is_bip39_seed(wizard_data):
return 'bip39_refine'
elif self.is_multisig(wizard_data):
return 'multisig_show_masterpubkey'
else:
return 'wallet_password'
def on_cosigner_keystore_type(self, wizard_data):
t = wizard_data['cosigner_keystore_type']
return {
'key': 'multisig_cosigner_key',
'seed': 'multisig_cosigner_seed'
}.get(t)
def finished(self, wizard_data):
self._logger.debug('finished')
# override

Loading…
Cancel
Save