From 44c0e583d6d4cbfcf848bdce70124b7819f471a2 Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Tue, 17 Sep 2024 13:22:05 +0200 Subject: [PATCH 1/4] qml: SweepDialog --- .../gui/qml/components/ConfirmTxDialog.qml | 4 +- electrum/gui/qml/components/SweepDialog.qml | 159 ++++++++++++++++++ .../gui/qml/components/WalletMainView.qml | 55 ++++++ electrum/gui/qml/qeapp.py | 3 +- electrum/gui/qml/qetxfinalizer.py | 105 +++++++++++- 5 files changed, 322 insertions(+), 4 deletions(-) create mode 100644 electrum/gui/qml/components/SweepDialog.qml diff --git a/electrum/gui/qml/components/ConfirmTxDialog.qml b/electrum/gui/qml/components/ConfirmTxDialog.qml index 1f2e6d67b..ea9470cdc 100644 --- a/electrum/gui/qml/components/ConfirmTxDialog.qml +++ b/electrum/gui/qml/components/ConfirmTxDialog.qml @@ -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 { diff --git a/electrum/gui/qml/components/SweepDialog.qml b/electrum/gui/qml/components/SweepDialog.qml new file mode 100644 index 000000000..0e8c48d1e --- /dev/null +++ b/electrum/gui/qml/components/SweepDialog.qml @@ -0,0 +1,159 @@ +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/add.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') + + '

' + qsTr('WIF keys are typed in Electrum, based on script type.') + '

' + + qsTr('A few examples') + ':
' + + 'p2pkh:KxZcY47uGp9a... \t-> 1DckmggQM...
' + + 'p2wpkh-p2sh:KxZcY47uGp9a... \t-> 3NhNeZQXF...
' + + 'p2wpkh:KxZcY47uGp9a... \t-> bc1q3fjfk...
' + } + } + 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 + console.log(root.privateKeys) + root.accept() + } + } + + } + + Bitcoin { + id: bitcoin + } +} diff --git a/electrum/gui/qml/components/WalletMainView.qml b/electrum/gui/qml/components/WalletMainView.qml index fb3a55d0a..a360d6c6b 100644 --- a/electrum/gui/qml/components/WalletMainView.qml +++ b/electrum/gui/qml/components/WalletMainView.qml @@ -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/add.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() + } + } + } diff --git a/electrum/gui/qml/qeapp.py b/electrum/gui/qml/qeapp.py index 692bc68cc..5b168b3a9 100644 --- a/electrum/gui/qml/qeapp.py +++ b/electrum/gui/qml/qeapp.py @@ -29,7 +29,7 @@ from .qeqr import QEQRParser, QEQRImageProvider, QEQRImageProviderHelper from .qeqrscanner import QEQRScanner from .qebitcoin import QEBitcoin from .qefx import QEFX -from .qetxfinalizer import QETxFinalizer, QETxRbfFeeBumper, QETxCpfpFeeBumper, QETxCanceller +from .qetxfinalizer import QETxFinalizer, QETxRbfFeeBumper, QETxCpfpFeeBumper, QETxCanceller, QETxSweepFinalizer from .qeinvoice import QEInvoice, QEInvoiceParser from .qerequestdetails import QERequestDetails from .qetypes import QEAmount @@ -396,6 +396,7 @@ class ElectrumQmlApplication(QGuiApplication): qmlRegisterType(QETxRbfFeeBumper, 'org.electrum', 1, 0, 'TxRbfFeeBumper') qmlRegisterType(QETxCpfpFeeBumper, 'org.electrum', 1, 0, 'TxCpfpFeeBumper') qmlRegisterType(QETxCanceller, 'org.electrum', 1, 0, 'TxCanceller') + qmlRegisterType(QETxSweepFinalizer, 'org.electrum', 1, 0, 'SweepFinalizer') qmlRegisterType(QEBip39RecoveryListModel, 'org.electrum', 1, 0, 'Bip39RecoveryListModel') # TODO QT6: these were declared as uncreatable, but that doesn't seem to work for pyqt6 diff --git a/electrum/gui/qml/qetxfinalizer.py b/electrum/gui/qml/qetxfinalizer.py index 56548bef2..f9e8b1565 100644 --- a/electrum/gui/qml/qetxfinalizer.py +++ b/electrum/gui/qml/qetxfinalizer.py @@ -1,3 +1,5 @@ +import copy +import threading from decimal import Decimal from typing import Optional, TYPE_CHECKING from functools import partial @@ -7,8 +9,9 @@ from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject from electrum.logging import get_logger from electrum.i18n import _ from electrum.transaction import PartialTxOutput, PartialTransaction, Transaction, TxOutpoint -from electrum.util import NotEnoughFunds, profiler, quantize_feerate -from electrum.wallet import CannotBumpFee, CannotDoubleSpendTx, CannotCPFP, BumpFeeStrategy +from electrum.util import NotEnoughFunds, profiler, quantize_feerate, UserFacingException +from electrum.wallet import CannotBumpFee, CannotDoubleSpendTx, CannotCPFP, BumpFeeStrategy, sweep_preparations +from electrum import keystore from electrum.plugin import run_hook from .qewallet import QEWallet @@ -868,3 +871,101 @@ class QETxCpfpFeeBumper(TxFeeSlider, TxMonMixin): @pyqtSlot(result=str) def getNewTx(self): return str(self._new_tx) + + +class QETxSweepFinalizer(QETxFinalizer): + _logger = get_logger(__name__) + + txinsRetrieved = pyqtSignal() + + def __init__(self, parent=None): + super().__init__(parent) + + self._private_keys = '' + self._txins = None + self._amount = QEAmount(is_max=True) + + self.txinsRetrieved.connect(self.update) + + privateKeysChanged = pyqtSignal() + @pyqtProperty(str, notify=privateKeysChanged) + def privateKeys(self): + return self._private_keys + + @privateKeys.setter + def privateKeys(self, private_keys): + if self._private_keys != private_keys: + self._private_keys = private_keys + self.update_privkeys() + self.privateKeysChanged.emit() + + def make_sweep_tx(self): + address = self._wallet.wallet.get_unused_address() # TODO: dont fail + + coins, keypairs = copy.deepcopy(self._txins) + outputs = [PartialTxOutput.from_address_and_value(address, value='!')] + + tx = self._wallet.wallet.make_unsigned_transaction(coins=coins, outputs=outputs, fee=None, rbf=self._rbf, is_sweep=True) + self._logger.debug('fee: %d, inputs: %d, outputs: %d' % (tx.get_fee(), len(tx.inputs()), len(tx.outputs()))) + + tx.sign(keypairs) + return tx + + def update_privkeys(self): + privkeys = keystore.get_private_keys(self._private_keys) + + def fetch_privkeys_info(): + try: + self._txins = self._wallet.wallet.network.run_from_another_thread(sweep_preparations(privkeys, self._wallet.wallet.network)) + self._logger.info(f'txins {self._txins!r}') + except UserFacingException as e: + self.warning = str(e) + return + self.txinsRetrieved.emit() + + threading.Thread(target=fetch_privkeys_info, daemon=True).start() + + def update(self): + if not self._wallet: + self._logger.debug('wallet not set, ignoring update()') + return + if not self._private_keys: + self._logger.debug('private keys not set, ignoring update()') + return + + try: + # make unsigned transaction + tx = self.make_sweep_tx() + except Exception as e: + self._logger.error(str(e)) + self.warning = repr(e) + self._valid = False + self.validChanged.emit() + return + + self._tx = tx + + amount = tx.output_value() + + self._effectiveAmount.satsInt = amount + self.effectiveAmountChanged.emit() + + self.update_from_tx(tx) + + fee_warning_tuple = self._wallet.wallet.get_tx_fee_warning( + invoice_amt=amount, tx_size=tx.estimated_size(), fee=tx.get_fee()) + if fee_warning_tuple: + allow_send, long_warning, short_warning = fee_warning_tuple + self.warning = _('Warning') + ': ' + long_warning + else: + self.warning = '' + + self._valid = True + self.validChanged.emit() + + self.on_signed_tx(False, tx) + + @pyqtSlot() + def send(self): + self._wallet.broadcast(self._tx) + self._wallet.wallet.set_label(self._tx.txid(), _('Sweep transaction')) From a8833eb650f77576011bb5971c68bf4c82cee641 Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Tue, 8 Oct 2024 12:16:19 +0200 Subject: [PATCH 2/4] qml: add sweep icon --- electrum/gui/icons/sweep.png | Bin 0 -> 5696 bytes electrum/gui/qml/components/SweepDialog.qml | 2 +- electrum/gui/qml/components/WalletMainView.qml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 electrum/gui/icons/sweep.png diff --git a/electrum/gui/icons/sweep.png b/electrum/gui/icons/sweep.png new file mode 100644 index 0000000000000000000000000000000000000000..faeb3141788c8b567bf12cf3ac64840c078a37dc GIT binary patch literal 5696 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 Date: Tue, 8 Oct 2024 12:19:21 +0200 Subject: [PATCH 3/4] qml: sweep: tone down logging --- electrum/gui/qml/components/SweepDialog.qml | 1 - electrum/gui/qml/qetxfinalizer.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/electrum/gui/qml/components/SweepDialog.qml b/electrum/gui/qml/components/SweepDialog.qml index c1d4b7655..d3f82523b 100644 --- a/electrum/gui/qml/components/SweepDialog.qml +++ b/electrum/gui/qml/components/SweepDialog.qml @@ -146,7 +146,6 @@ ElDialog { onClicked: { console.log('sweeping') root.privateKeys = sweepkeys.text - console.log(root.privateKeys) root.accept() } } diff --git a/electrum/gui/qml/qetxfinalizer.py b/electrum/gui/qml/qetxfinalizer.py index f9e8b1565..a7a4a62ef 100644 --- a/electrum/gui/qml/qetxfinalizer.py +++ b/electrum/gui/qml/qetxfinalizer.py @@ -917,7 +917,7 @@ class QETxSweepFinalizer(QETxFinalizer): def fetch_privkeys_info(): try: self._txins = self._wallet.wallet.network.run_from_another_thread(sweep_preparations(privkeys, self._wallet.wallet.network)) - self._logger.info(f'txins {self._txins!r}') + self._logger.debug(f'txins {self._txins!r}') except UserFacingException as e: self.warning = str(e) return From 3cabbf7caa551f6c21f2c2bad4e822a1dd830750 Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Wed, 9 Oct 2024 11:06:59 +0200 Subject: [PATCH 4/4] qml: sweep: obtain wallet address like desktop --- electrum/gui/qml/qetxfinalizer.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/electrum/gui/qml/qetxfinalizer.py b/electrum/gui/qml/qetxfinalizer.py index a7a4a62ef..6d86611ec 100644 --- a/electrum/gui/qml/qetxfinalizer.py +++ b/electrum/gui/qml/qetxfinalizer.py @@ -900,7 +900,16 @@ class QETxSweepFinalizer(QETxFinalizer): self.privateKeysChanged.emit() def make_sweep_tx(self): - address = self._wallet.wallet.get_unused_address() # TODO: dont fail + addresses = self._wallet.wallet.get_unused_addresses() + if not addresses: + try: + addresses = self._wallet.wallet.get_receiving_addresses() + except AttributeError: + addresses = self._wallet.wallet.get_addresses() + + assert len(addresses) > 0, 'no address in wallet to send to' + address = addresses[0] + assert self._wallet.wallet.adb.is_mine(address) coins, keypairs = copy.deepcopy(self._txins) outputs = [PartialTxOutput.from_address_and_value(address, value='!')]