qml: refactor is_last checks to mostly lambdas, add multisig flow for 1st cosigner keystore,
add initial flow and view placeholders for additional cosigners.
This commit is contained in:
19
electrum/gui/qml/components/wizard/WCCosignerKey.qml
Normal file
19
electrum/gui/qml/components/wizard/WCCosignerKey.qml
Normal file
@@ -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
Normal file
39
electrum/gui/qml/components/wizard/WCCosignerKeystore.qml
Normal file
@@ -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
Normal file
19
electrum/gui/qml/components/wizard/WCCosignerSeed.qml
Normal file
@@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
Normal file
65
electrum/gui/qml/components/wizard/WCShowMasterPubkey.qml
Normal file
@@ -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'])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user