add wallet type imported addresses/private keys to wizard
This commit is contained in:
@@ -153,9 +153,14 @@ Pane {
|
|||||||
Label { text: 'has Seed'; color: Material.accentColor }
|
Label { text: 'has Seed'; color: Material.accentColor }
|
||||||
Label { text: Daemon.currentWallet.hasSeed }
|
Label { text: Daemon.currentWallet.hasSeed }
|
||||||
|
|
||||||
Label { Layout.columnSpan:4; text: qsTr('Master Public Key'); color: Material.accentColor }
|
Label {
|
||||||
|
visible: Daemon.currentWallet.masterPubkey
|
||||||
|
Layout.columnSpan:4; text: qsTr('Master Public Key'); color: Material.accentColor
|
||||||
|
}
|
||||||
|
|
||||||
TextHighlightPane {
|
TextHighlightPane {
|
||||||
|
visible: Daemon.currentWallet.masterPubkey
|
||||||
|
|
||||||
Layout.columnSpan: 4
|
Layout.columnSpan: 4
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|||||||
102
electrum/gui/qml/components/wizard/WCImport.qml
Normal file
102
electrum/gui/qml/components/wizard/WCImport.qml
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
onAccept: {
|
||||||
|
if (bitcoin.isAddressList(import_ta.text)) {
|
||||||
|
wizard_data['address_list'] = import_ta.text
|
||||||
|
} else if (bitcoin.isPrivateKeyList(import_ta.text)) {
|
||||||
|
wizard_data['private_key_list'] = import_ta.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function verify(text) {
|
||||||
|
return bitcoin.isAddressList(text) || bitcoin.isPrivateKeyList(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Label { text: qsTr('Import Bitcoin Addresses') }
|
||||||
|
|
||||||
|
InfoTextArea {
|
||||||
|
text: qsTr('Enter a list of Bitcoin addresses (this will create a watching-only wallet), or a list of private keys.')
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
TextArea {
|
||||||
|
id: import_ta
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumHeight: 80
|
||||||
|
focus: true
|
||||||
|
wrapMode: TextEdit.WrapAnywhere
|
||||||
|
onTextChanged: valid = verify(text)
|
||||||
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
ToolButton {
|
||||||
|
icon.source: '../../../icons/paste.png'
|
||||||
|
icon.height: constants.iconSizeMedium
|
||||||
|
icon.width: constants.iconSizeMedium
|
||||||
|
onClicked: {
|
||||||
|
if (verify(AppController.clipboardToText())) {
|
||||||
|
if (import_ta.text != '')
|
||||||
|
import_ta.text = import_ta.text + '\n'
|
||||||
|
import_ta.text = import_ta.text + AppController.clipboardToText()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ToolButton {
|
||||||
|
icon.source: '../../../icons/qrcode.png'
|
||||||
|
icon.height: constants.iconSizeMedium
|
||||||
|
icon.width: constants.iconSizeMedium
|
||||||
|
scale: 1.2
|
||||||
|
onClicked: {
|
||||||
|
var scan = qrscan.createObject(root)
|
||||||
|
scan.onFound.connect(function() {
|
||||||
|
if (verify(scan.scanData)) {
|
||||||
|
if (import_ta.text != '')
|
||||||
|
import_ta.text = import_ta.text + ',\n'
|
||||||
|
import_ta.text = import_ta.text + scan.scanData
|
||||||
|
}
|
||||||
|
scan.destroy()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: qrscan
|
||||||
|
QRScan {
|
||||||
|
width: root.width
|
||||||
|
height: root.height
|
||||||
|
|
||||||
|
ToolButton {
|
||||||
|
icon.source: '../../../icons/closebutton.png'
|
||||||
|
icon.height: constants.iconSizeMedium
|
||||||
|
icon.width: constants.iconSizeMedium
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
onClicked: {
|
||||||
|
parent.destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitcoin {
|
||||||
|
id: bitcoin
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -38,9 +38,8 @@ WizardComponent {
|
|||||||
text: qsTr('Multi-signature wallet')
|
text: qsTr('Multi-signature wallet')
|
||||||
}
|
}
|
||||||
RadioButton {
|
RadioButton {
|
||||||
enabled: false
|
|
||||||
ButtonGroup.group: wallettypegroup
|
ButtonGroup.group: wallettypegroup
|
||||||
property string wallettype: 'import'
|
property string wallettype: 'imported'
|
||||||
text: qsTr('Import Bitcoin addresses or private keys')
|
text: qsTr('Import Bitcoin addresses or private keys')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class QEAddressListModel(QAbstractListModel):
|
|||||||
def init_model(self):
|
def init_model(self):
|
||||||
r_addresses = self.wallet.get_receiving_addresses()
|
r_addresses = self.wallet.get_receiving_addresses()
|
||||||
c_addresses = self.wallet.get_change_addresses()
|
c_addresses = self.wallet.get_change_addresses()
|
||||||
n_addresses = len(r_addresses) + len(c_addresses)
|
n_addresses = len(r_addresses) + len(c_addresses) if self.wallet.use_change else 0
|
||||||
|
|
||||||
def insert_row(atype, alist, address, iaddr):
|
def insert_row(atype, alist, address, iaddr):
|
||||||
item = self.addr_to_model(address)
|
item = self.addr_to_model(address)
|
||||||
@@ -80,7 +80,7 @@ class QEAddressListModel(QAbstractListModel):
|
|||||||
insert_row('receive', self.receive_addresses, address, i)
|
insert_row('receive', self.receive_addresses, address, i)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
i = 0
|
i = 0
|
||||||
for address in c_addresses:
|
for address in c_addresses if self.wallet.use_change else []:
|
||||||
insert_row('change', self.change_addresses, address, i)
|
insert_row('change', self.change_addresses, address, i)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
self.endInsertRows()
|
self.endInsertRows()
|
||||||
|
|||||||
@@ -164,3 +164,12 @@ class QEBitcoin(QObject):
|
|||||||
return True
|
return True
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@pyqtSlot(str, result=bool)
|
||||||
|
def isAddressList(self, csv: str):
|
||||||
|
return keystore.is_address_list(csv)
|
||||||
|
|
||||||
|
@pyqtSlot(str, result=bool)
|
||||||
|
def isPrivateKeyList(self, csv: str):
|
||||||
|
return keystore.is_private_key_list(csv)
|
||||||
|
|
||||||
|
|||||||
@@ -319,6 +319,8 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
|||||||
|
|
||||||
@pyqtProperty(str, notify=dataChanged)
|
@pyqtProperty(str, notify=dataChanged)
|
||||||
def txinType(self):
|
def txinType(self):
|
||||||
|
if self.wallet.wallet_type == 'imported':
|
||||||
|
return self.wallet.txin_type
|
||||||
return self.wallet.get_txin_type(self.wallet.dummy_address())
|
return self.wallet.get_txin_type(self.wallet.dummy_address())
|
||||||
|
|
||||||
@pyqtProperty(bool, notify=dataChanged)
|
@pyqtProperty(bool, notify=dataChanged)
|
||||||
@@ -342,6 +344,9 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
|||||||
keystores = self.wallet.get_keystores()
|
keystores = self.wallet.get_keystores()
|
||||||
if len(keystores) > 1:
|
if len(keystores) > 1:
|
||||||
self._logger.debug('multiple keystores not supported yet')
|
self._logger.debug('multiple keystores not supported yet')
|
||||||
|
if len(keystores) == 0:
|
||||||
|
self._logger.debug('no keystore')
|
||||||
|
return ''
|
||||||
return keystores[0].get_derivation_prefix()
|
return keystores[0].get_derivation_prefix()
|
||||||
|
|
||||||
@pyqtProperty(str, notify=dataChanged)
|
@pyqtProperty(str, notify=dataChanged)
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ class QENewWalletWizard(NewWalletWizard, QEAbstractWizard):
|
|||||||
'have_seed': { 'gui': 'WCHaveSeed' },
|
'have_seed': { 'gui': 'WCHaveSeed' },
|
||||||
'bip39_refine': { 'gui': 'WCBIP39Refine' },
|
'bip39_refine': { 'gui': 'WCBIP39Refine' },
|
||||||
'have_master_key': { 'gui': 'WCHaveMasterKey' },
|
'have_master_key': { 'gui': 'WCHaveMasterKey' },
|
||||||
|
'imported': { 'gui': 'WCImport' },
|
||||||
'wallet_password': { 'gui': 'WCWalletPassword' }
|
'wallet_password': { 'gui': 'WCWalletPassword' }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from electrum.storage import WalletStorage, StorageEncryptionVersion
|
|||||||
from electrum.wallet_db import WalletDB
|
from electrum.wallet_db import WalletDB
|
||||||
from electrum.bip32 import normalize_bip32_derivation, xpub_type
|
from electrum.bip32 import normalize_bip32_derivation, xpub_type
|
||||||
from electrum import keystore
|
from electrum import keystore
|
||||||
|
from electrum import bitcoin
|
||||||
|
|
||||||
class WizardViewState(NamedTuple):
|
class WizardViewState(NamedTuple):
|
||||||
view: str
|
view: str
|
||||||
@@ -162,6 +163,10 @@ class NewWalletWizard(AbstractWizard):
|
|||||||
'next': 'wallet_password',
|
'next': 'wallet_password',
|
||||||
'last': self.last_if_single_password
|
'last': self.last_if_single_password
|
||||||
},
|
},
|
||||||
|
'imported': {
|
||||||
|
'next': 'wallet_password',
|
||||||
|
'last': self.last_if_single_password
|
||||||
|
},
|
||||||
'wallet_password': {
|
'wallet_password': {
|
||||||
'last': True
|
'last': True
|
||||||
}
|
}
|
||||||
@@ -180,10 +185,12 @@ class NewWalletWizard(AbstractWizard):
|
|||||||
return self.last_if_single_password(view, wizard_data) and not wizard_data['seed_type'] == 'bip39'
|
return self.last_if_single_password(view, wizard_data) and not wizard_data['seed_type'] == 'bip39'
|
||||||
|
|
||||||
def on_wallet_type(self, wizard_data):
|
def on_wallet_type(self, wizard_data):
|
||||||
if wizard_data['wallet_type'] == '2fa':
|
t = wizard_data['wallet_type']
|
||||||
return 'trustedcoin_start'
|
return {
|
||||||
|
'standard': 'keystore_type',
|
||||||
return 'keystore_type'
|
'2fa': 'trustedcoin_start',
|
||||||
|
'imported': 'imported'
|
||||||
|
}.get(t)
|
||||||
|
|
||||||
def on_keystore_type(self, wizard_data):
|
def on_keystore_type(self, wizard_data):
|
||||||
t = wizard_data['keystore_type']
|
t = wizard_data['keystore_type']
|
||||||
@@ -205,13 +212,28 @@ class NewWalletWizard(AbstractWizard):
|
|||||||
|
|
||||||
def create_storage(self, path, data):
|
def create_storage(self, path, data):
|
||||||
# only standard and 2fa wallets for now
|
# only standard and 2fa wallets for now
|
||||||
assert data['wallet_type'] in ['standard', '2fa']
|
assert data['wallet_type'] in ['standard', '2fa', 'imported']
|
||||||
|
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
raise Exception('file already exists at path')
|
raise Exception('file already exists at path')
|
||||||
storage = WalletStorage(path)
|
storage = WalletStorage(path)
|
||||||
|
|
||||||
if data['keystore_type'] in ['createseed', 'haveseed']:
|
k = None
|
||||||
|
if not 'keystore_type' in data:
|
||||||
|
assert data['wallet_type'] == 'imported'
|
||||||
|
addresses = {}
|
||||||
|
if 'private_key_list' in data:
|
||||||
|
k = keystore.Imported_KeyStore({})
|
||||||
|
keys = keystore.get_private_keys(data['private_key_list'])
|
||||||
|
for pk in keys:
|
||||||
|
assert bitcoin.is_private_key(pk)
|
||||||
|
txin_type, pubkey = k.import_privkey(pk, None)
|
||||||
|
addr = bitcoin.pubkey_to_address(txin_type, pubkey)
|
||||||
|
addresses[addr] = {'type': txin_type, 'pubkey': pubkey}
|
||||||
|
elif 'address_list' in data:
|
||||||
|
for addr in data['address_list'].split():
|
||||||
|
addresses[addr] = {}
|
||||||
|
elif data['keystore_type'] in ['createseed', 'haveseed']:
|
||||||
if data['seed_type'] in ['old', 'standard', 'segwit']: #2fa, 2fa-segwit
|
if data['seed_type'] in ['old', 'standard', 'segwit']: #2fa, 2fa-segwit
|
||||||
self._logger.debug('creating keystore from electrum seed')
|
self._logger.debug('creating keystore from electrum seed')
|
||||||
k = keystore.from_seed(data['seed'], data['seed_extra_words'], data['wallet_type'] == 'multisig')
|
k = keystore.from_seed(data['seed'], data['seed_extra_words'], data['wallet_type'] == 'multisig')
|
||||||
@@ -237,7 +259,7 @@ class NewWalletWizard(AbstractWizard):
|
|||||||
raise Exception('unsupported/unknown keystore_type %s' % data['keystore_type'])
|
raise Exception('unsupported/unknown keystore_type %s' % data['keystore_type'])
|
||||||
|
|
||||||
if data['encrypt']:
|
if data['encrypt']:
|
||||||
if k.may_have_password():
|
if k and k.may_have_password():
|
||||||
k.update_password(None, data['password'])
|
k.update_password(None, data['password'])
|
||||||
storage.set_password(data['password'], enc_version=StorageEncryptionVersion.USER_PASSWORD)
|
storage.set_password(data['password'], enc_version=StorageEncryptionVersion.USER_PASSWORD)
|
||||||
|
|
||||||
@@ -255,8 +277,12 @@ class NewWalletWizard(AbstractWizard):
|
|||||||
db.put('x2/', data['x2/'])
|
db.put('x2/', data['x2/'])
|
||||||
db.put('x3/', data['x3/'])
|
db.put('x3/', data['x3/'])
|
||||||
db.put('use_trustedcoin', True)
|
db.put('use_trustedcoin', True)
|
||||||
|
elif data['wallet_type'] == 'imported':
|
||||||
|
if k:
|
||||||
|
db.put('keystore', k.dump())
|
||||||
|
db.put('addresses', addresses)
|
||||||
|
|
||||||
if k.can_have_deterministic_lightning_xprv():
|
if k and k.can_have_deterministic_lightning_xprv():
|
||||||
db.put('lightning_xprv', k.get_lightning_xprv(data['password'] if data['encrypt'] else None))
|
db.put('lightning_xprv', k.get_lightning_xprv(data['password'] if data['encrypt'] else None))
|
||||||
|
|
||||||
db.load_plugins()
|
db.load_plugins()
|
||||||
|
|||||||
Reference in New Issue
Block a user