1
0

Merge pull request #9203 from accumulator/qml_sweep_privkeys

qml: Sweep from privkeys
This commit is contained in:
accumulator
2024-10-09 11:14:00 +02:00
committed by GitHub
6 changed files with 330 additions and 4 deletions

View File

@@ -14,6 +14,7 @@ ElDialog {
required property Amount satoshis
property string address
property string message
property bool showOptions: true
property alias amountLabelText: amountLabel.text
property alias sendButtonText: sendButton.text
@@ -142,12 +143,13 @@ ElDialog {
Layout.columnSpan: 2
labelText: qsTr('Options')
color: Material.accentColor
visible: showOptions
}
TextHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
visible: !optionstoggle.collapsed
visible: optionstoggle.visible && !optionstoggle.collapsed
height: optionslayout.height
GridLayout {

View File

@@ -0,0 +1,158 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.electrum
import "controls"
ElDialog {
id: root
title: qsTr('Sweep private keys')
iconSource: Qt.resolvedUrl('../../icons/sweep.png')
property bool valid: false
property string privateKeys
width: parent.width
height: parent.height
padding: 0
function verifyPrivateKey(key) {
valid = false
validationtext.text = ''
key = key.trim()
if (!key) {
return false
}
if (!bitcoin.isPrivateKeyList(key)) {
validationtext.text = qsTr('Error: invalid private key(s)')
return false
}
return valid = true
}
function addPrivateKey(key) {
if (sweepkeys.text.includes(key))
return
if (sweepkeys.text && !sweepkeys.text.endsWith('\n'))
sweepkeys.text = sweepkeys.text + '\n'
sweepkeys.text = sweepkeys.text + key + '\n'
}
ColumnLayout {
anchors.fill: parent
spacing: 0
ColumnLayout {
Layout.leftMargin: constants.paddingLarge
Layout.rightMargin: constants.paddingLarge
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
RowLayout {
Layout.fillWidth: true
TextHighlightPane {
Layout.fillWidth: true
Label {
text: qsTr('Enter the list of private keys to sweep into this wallet')
wrapMode: Text.Wrap
}
}
HelpButton {
heading: qsTr('Sweep private keys')
helptext: qsTr('This will create a transaction sending all funds associated with the private keys to the current wallet') +
'<br/><br/>' + qsTr('WIF keys are typed in Electrum, based on script type.') + '<br/><br/>' +
qsTr('A few examples') + ':<br/>' +
'<tt><b>p2pkh</b>:KxZcY47uGp9a... \t-> 1DckmggQM...<br/>' +
'<b>p2wpkh-p2sh</b>:KxZcY47uGp9a... \t-> 3NhNeZQXF...<br/>' +
'<b>p2wpkh</b>:KxZcY47uGp9a... \t-> bc1q3fjfk...</tt>'
}
}
RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true
ElTextArea {
id: sweepkeys
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 160
font.family: FixedFont
wrapMode: TextEdit.WrapAnywhere
onTextChanged: {
if (anyActiveFocus) {
verifyPrivateKey(text)
}
}
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
background: PaneInsetBackground {
baseColor: constants.darkerDialogBackground
}
}
ColumnLayout {
Layout.alignment: Qt.AlignTop
ToolButton {
icon.source: '../../icons/paste.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
onClicked: {
if (verifyPrivateKey(AppController.clipboardToText()))
addPrivateKey(AppController.clipboardToText())
}
}
ToolButton {
icon.source: '../../icons/qrcode.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
scale: 1.2
onClicked: {
var dialog = app.scanDialog.createObject(app, {
hint: qsTr('Scan a private key')
})
dialog.onFound.connect(function() {
if (verifyPrivateKey(dialog.scanData))
addPrivateKey(dialog.scanData)
dialog.close()
})
dialog.open()
}
}
}
}
InfoTextArea {
id: validationtext
iconStyle: InfoTextArea.IconStyle.Warn
Layout.fillWidth: true
Layout.margins: constants.paddingMedium
visible: text
}
}
}
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
enabled: valid
icon.source: '../../icons/tab_send.png'
text: qsTr('Sweep')
onClicked: {
console.log('sweeping')
root.privateKeys = sweepkeys.text
root.accept()
}
}
}
Bitcoin {
id: bitcoin
}
}

View File

@@ -131,6 +131,25 @@ Item {
Daemon.currentWallet.createRequest(qamt, _request_description, _request_expiry, lightning_only, reuse_address)
}
function startSweep() {
var dialog = sweepDialog.createObject(app)
dialog.accepted.connect(function() {
var finalizerDialog = confirmSweepDialog.createObject(mainView, {
privateKeys: dialog.privateKeys,
message: qsTr('Sweep transaction'),
showOptions: false,
amountLabelText: qsTr('Total sweep amount'),
sendButtonText: qsTr('Sweep')
})
finalizerDialog.accepted.connect(function() {
console.log("Sending sweep transaction")
finalizerDialog.finalizer.send()
})
finalizerDialog.open()
})
dialog.open()
}
property QtObject menu: Menu {
id: menu
@@ -187,6 +206,19 @@ Item {
}
}
MenuItem {
icon.color: action.enabled ? 'transparent' : Material.iconDisabledColor
icon.source: '../../icons/sweep.png'
action: Action {
text: qsTr('Sweep key')
enabled: !Daemon.currentWallet.isWatchOnly // watchonly might be acceptable
onTriggered: {
startSweep()
menu.deselect()
}
}
}
MenuSeparator { }
MenuItem {
@@ -608,6 +640,22 @@ Item {
}
}
Component {
id: confirmSweepDialog
ConfirmTxDialog {
id: _confirmSweepDialog
property string privateKeys
title: qsTr('Confirm Sweep')
satoshis: MAX
finalizer: SweepFinalizer {
wallet: Daemon.currentWallet
canRbf: true
privateKeys: _confirmSweepDialog.privateKeys
}
}
}
Component {
id: lnurlPayDialog
LnurlPayRequestDialog {
@@ -635,5 +683,12 @@ Item {
}
}
Component {
id: sweepDialog
SweepDialog {
onClosed: destroy()
}
}
}