qml: add workarounds for issue assigning custom types to QObject properties
What changed, and why it matters
This commit changes how the Electrum mobile/desktop QML GUI passes custom data objects between Python and the user interface. It switches many typed properties to the generic QVariant/'var' type and adds runtime type checks (asserts) in Python setters. The stated goal is to work around a Qt/PyQt bug where assigning custom Python types to QML properties fails. The changes are defensive and reduce strict compile-time type safety in favor of runtime checks. There is no direct evidence in the commit that this fixes an exploitable security vulnerability; it appears to be a compatibility/stability fix.
Treat as a routine UI compatibility fix. Review that the added assert-based type checks are not disabled in production builds (Python -O removes asserts), and consider replacing asserts with explicit exception handling if type safety is security-critical. No urgent security action is indicated by the commit itself.
Security signals we found
Type system relaxation: custom typed QML/Python properties changed to generic QVariant/var
Runtime type enforcement added via assert statements in Python setters
No explicit security framing in commit message or diff
Changes are localized to QML GUI layer, not core wallet logic
No CVE, advisory, or researcher attribution present in commit materials
Evidence from the diff
The patch modifies QML property declarations and Python pyqtProperty definitions to use QVariant/’var’ instead of custom types (QEWallet, QEAmount, Invoice, etc.). It also adds assert isinstance(...) checks in Python setters to enforce expected types at runtime. A function rename (reset to resetDialog) and a new dialogColor constant are included. The commit message frames this as a workaround for a Qt/QML issue with custom type assignment to QObject properties. No memory-unsafe operations, cryptographic changes, or obvious injection points are introduced.
Changed components
electrum/gui/qml/components/*.qmlelectrum/gui/qml/qeaddressdetails.pyelectrum/gui/qml/qechanneldetails.pyelectrum/gui/qml/qechannelopener.pyelectrum/gui/qml/qeinvoice.pyelectrum/gui/qml/qelnpaymentdetails.pyelectrum/gui/qml/qepiresolver.pyelectrum/gui/qml/qerequestdetails.pyelectrum/gui/qml/qeswaphelper.pyelectrum/gui/qml/qetxdetails.pyelectrum/gui/qml/qetxfinalizer.pyInspect captured patch +86 / −59
diff --git a/electrum/gui/qml/components/ChannelOpenProgressDialog.qml b/electrum/gui/qml/components/ChannelOpenProgressDialog.qml
index 6179dd4..3cea2e1 100644
--- a/electrum/gui/qml/components/ChannelOpenProgressDialog.qml
+++ b/electrum/gui/qml/components/ChannelOpenProgressDialog.qml
@@ -23,7 +23,7 @@ ElDialog {
property string channelBackup
- function reset() {
+ function resetDialog() {
state = ''
errorText.text = ''
peerText.text = ''
diff --git a/electrum/gui/qml/components/ConfirmTxDialog.qml b/electrum/gui/qml/components/ConfirmTxDialog.qml
index f51a7f3..94617d3 100644
--- a/electrum/gui/qml/components/ConfirmTxDialog.qml
+++ b/electrum/gui/qml/components/ConfirmTxDialog.qml
@@ -11,7 +11,7 @@ ElDialog {
id: dialog
required property QtObject finalizer
- required property Amount satoshis
+ required property var satoshis // type: Amount
property string address
property string message
property bool showOptions: true
diff --git a/electrum/gui/qml/components/Constants.qml b/electrum/gui/qml/components/Constants.qml
index 95d79a4..7935a8c 100644
--- a/electrum/gui/qml/components/Constants.qml
+++ b/electrum/gui/qml/components/Constants.qml
@@ -31,6 +31,7 @@ Item {
property color darkerBackground: Qt.darker(Material.background, 1.20)
property color lighterBackground: Qt.lighter(Material.background, 1.10)
property color darkerDialogBackground: Qt.darker(Material.dialogColor, 1.20)
+ property color dialogColor: Material.dialogColor
property color notificationBackground: Qt.lighter(Material.background, 1.5)
property color colorCredit: "#ff80ff80"
diff --git a/electrum/gui/qml/components/InvoiceDialog.qml b/electrum/gui/qml/components/InvoiceDialog.qml
index 51f41de..882c97b 100644
--- a/electrum/gui/qml/components/InvoiceDialog.qml
+++ b/electrum/gui/qml/components/InvoiceDialog.qml
@@ -10,7 +10,7 @@ import "controls"
ElDialog {
id: dialog
- property Invoice invoice
+ property var invoice // type Invoice
property bool payImmediately: false
property string broadcastTxid
@@ -24,7 +24,7 @@ ElDialog {
property bool _canMax: invoice.invoiceType == Invoice.OnchainInvoice
- property Amount _invoice_amount: invoice.amount
+ property var _invoice_amount: invoice.amount // type: Amount
ColumnLayout {
anchors.fill: parent
diff --git a/electrum/gui/qml/components/LnurlPayRequestDialog.qml b/electrum/gui/qml/components/LnurlPayRequestDialog.qml
index 338dc08..64f4545 100644
--- a/electrum/gui/qml/components/LnurlPayRequestDialog.qml
+++ b/electrum/gui/qml/components/LnurlPayRequestDialog.qml
@@ -13,7 +13,7 @@ ElDialog {
title: qsTr('LNURL Payment request')
iconSource: '../../../icons/link.png'
- property InvoiceParser invoiceParser
+ property var invoiceParser // type: InvoiceParser
padding: 0
needsSystemBarPadding: false
diff --git a/electrum/gui/qml/components/LnurlWithdrawRequestDialog.qml b/electrum/gui/qml/components/LnurlWithdrawRequestDialog.qml
index d5a84c6..02a9be4 100644
--- a/electrum/gui/qml/components/LnurlWithdrawRequestDialog.qml
+++ b/electrum/gui/qml/components/LnurlWithdrawRequestDialog.qml
@@ -13,8 +13,8 @@ ElDialog {
title: qsTr('LNURL Withdraw request')
iconSource: '../../../icons/link.png'
- property Wallet wallet: Daemon.currentWallet
- property RequestDetails requestDetails
+ property var wallet: Daemon.currentWallet // type: Wallet
+ property var requestDetails // type: RequestDetails
padding: 0
needsSystemBarPadding: false
diff --git a/electrum/gui/qml/components/OpenChannelDialog.qml b/electrum/gui/qml/components/OpenChannelDialog.qml
index 97d709b..99aa6cd 100644
--- a/electrum/gui/qml/components/OpenChannelDialog.qml
+++ b/electrum/gui/qml/components/OpenChannelDialog.qml
@@ -298,7 +298,7 @@ ElDialog {
}
onChannelOpening: (peer) => {
console.log('Channel is opening')
- app.channelOpenProgressDialog.reset()
+ app.channelOpenProgressDialog.resetDialog()
app.channelOpenProgressDialog.peer = peer
app.channelOpenProgressDialog.open()
}
diff --git a/electrum/gui/qml/components/SendDialog.qml b/electrum/gui/qml/components/SendDialog.qml
index e17c45c..256012f 100644
--- a/electrum/gui/qml/components/SendDialog.qml
+++ b/electrum/gui/qml/components/SendDialog.qml
@@ -11,8 +11,8 @@ import "controls"
ElDialog {
id: dialog
- property InvoiceParser invoiceParser
- property PIResolver piResolver
+ property var invoiceParser // type: InvoiceParser
+ property var piResolver // type: PIResolver
signal txFound(data: string)
signal channelBackupFound(data: string)
diff --git a/electrum/gui/qml/components/WalletMainView.qml b/electrum/gui/qml/components/WalletMainView.qml
index c39cda5..593e49f 100644
--- a/electrum/gui/qml/components/WalletMainView.qml
+++ b/electrum/gui/qml/components/WalletMainView.qml
@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
import QtQml
import org.electrum 1.0
diff --git a/electrum/gui/qml/components/controls/BtcField.qml b/electrum/gui/qml/components/controls/BtcField.qml
index a426243..ce11cfe 100644
--- a/electrum/gui/qml/components/controls/BtcField.qml
+++ b/electrum/gui/qml/components/controls/BtcField.qml
@@ -16,7 +16,7 @@ TextField {
regularExpression: msatPrecision ? Config.btcAmountRegexMsat : Config.btcAmountRegex
}
- property Amount textAsSats
+ property var textAsSats
onTextChanged: {
textAsSats = Config.unitsToSats(amount.text)
if (fiatfield.activeFocus)
diff --git a/electrum/gui/qml/components/controls/ChannelBar.qml b/electrum/gui/qml/components/controls/ChannelBar.qml
index 8635356..4f67dd7 100644
--- a/electrum/gui/qml/components/controls/ChannelBar.qml
+++ b/electrum/gui/qml/components/controls/ChannelBar.qml
@@ -6,11 +6,11 @@ import QtQuick.Controls.Material
import org.electrum 1.0
Item {
- property Amount capacity
- property Amount localCapacity
- property Amount remoteCapacity
- property Amount canSend
- property Amount canReceive
+ property var capacity // type: Amount
+ property var localCapacity // type: Amount
+ property var remoteCapacity // type: Amount
+ property var canSend // type: Amount
+ property var canReceive // type: Amount
property bool frozenForSending: false
property bool frozenForReceiving: false
diff --git a/electrum/gui/qml/components/controls/FormattedAmount.qml b/electrum/gui/qml/components/controls/FormattedAmount.qml
index 80d6d77..43c57e6 100644
--- a/electrum/gui/qml/components/controls/FormattedAmount.qml
+++ b/electrum/gui/qml/components/controls/FormattedAmount.qml
@@ -6,7 +6,7 @@ import QtQuick.Controls.Material
import org.electrum 1.0
GridLayout {
- required property Amount amount
+ required property var amount // type: Amount
property bool showAlt: true
property bool singleLine: true
property bool valid: true
diff --git a/electrum/gui/qml/components/main.qml b/electrum/gui/qml/components/main.qml
index 4202130..7de57ff 100644
--- a/electrum/gui/qml/components/main.qml
+++ b/electrum/gui/qml/components/main.qml
@@ -128,7 +128,7 @@ ApplicationWindow
background: Rectangle {
implicitHeight: 48
- color: Material.dialogColor
+ color: constants.dialogColor
layer.enabled: true
layer.effect: ElevationEffect {
diff --git a/electrum/gui/qml/qeaddressdetails.py b/electrum/gui/qml/qeaddressdetails.py
index 8ff78cf..c17f50d 100644
--- a/electrum/gui/qml/qeaddressdetails.py
+++ b/electrum/gui/qml/qeaddressdetails.py
@@ -1,4 +1,4 @@
-from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
+from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QVariant
from electrum.logging import get_logger
from electrum.util import UserFacingException
@@ -35,12 +35,13 @@ class QEAddressDetails(AuthMixin, QObject):
self._historyModel = None
walletChanged = pyqtSignal()
- @pyqtProperty(QEWallet, notify=walletChanged)
+ @pyqtProperty(QVariant, notify=walletChanged)
def wallet(self):
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
+ assert isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
diff --git a/electrum/gui/qml/qechanneldetails.py b/electrum/gui/qml/qechanneldetails.py
index 1f74c6f..be9c2d5 100644
--- a/electrum/gui/qml/qechanneldetails.py
+++ b/electrum/gui/qml/qechanneldetails.py
@@ -2,7 +2,7 @@ import threading
from enum import IntEnum
from typing import Optional, TYPE_CHECKING
-from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum
+from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum, QVariant
from electrum.i18n import _
from electrum.gui import messages
@@ -61,12 +61,13 @@ class QEChannelDetails(AuthMixin, QObject, QtEventListener):
self.unregister_callbacks()
walletChanged = pyqtSignal()
- @pyqtProperty(QEWallet, notify=walletChanged)
+ @pyqtProperty(QVariant, notify=walletChanged)
def wallet(self) -> QEWallet:
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
+ assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
diff --git a/electrum/gui/qml/qechannellistmodel.py b/electrum/gui/qml/qechannellistmodel.py
index 3e68bce..0079cdc 100644
--- a/electrum/gui/qml/qechannellistmodel.py
+++ b/electrum/gui/qml/qechannellistmodel.py
@@ -1,5 +1,6 @@
-from PyQt6.QtCore import Qt, QAbstractListModel, QModelIndex
-from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot
+from typing import TYPE_CHECKING
+
+from PyQt6.QtCore import Qt, QAbstractListModel, QModelIndex, pyqtProperty, pyqtSignal, pyqtSlot
from electrum.lnchannel import ChannelState
from electrum.lnutil import LOCAL, REMOTE
@@ -12,6 +13,9 @@ from electrum.gui.common_qt.util import qt_event_listener, QtEventListener
from .qetypes import QEAmount
from .qemodelfilter import QEFilterProxyModel
+if TYPE_CHECKING:
+ from electrum.wallet import Abstract_Wallet
+
class QEChannelListModel(QAbstractListModel, QtEventListener):
_logger = get_logger(__name__)
@@ -27,7 +31,7 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
_network_signal = pyqtSignal(str, object)
- def __init__(self, wallet, parent=None):
+ def __init__(self, wallet: 'Abstract_Wallet', parent=None):
super().__init__(parent)
self.wallet = wallet
self._channels = []
diff --git a/electrum/gui/qml/qechannelopener.py b/electrum/gui/qml/qechannelopener.py
index 927f7a8..f01fd77 100644
--- a/electrum/gui/qml/qechannelopener.py
+++ b/electrum/gui/qml/qechannelopener.py
@@ -4,7 +4,7 @@ from asyncio.exceptions import TimeoutError
from typing import Optional
import electrum_ecc as ecc
-from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
+from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QVariant
from electrum.i18n import _
from electrum.gui import messages
@@ -14,7 +14,6 @@ from electrum.lntransport import extract_nodeid, ConnStringFormatError
from electrum.bitcoin import DummyAddress
from electrum.lnworker import hardcoded_trampoline_nodes
from electrum.logging import get_logger
-from electrum.fee_policy import FeePolicy
from electrum.transaction import PartialTransaction
from .auth import AuthMixin, auth_protect
@@ -55,12 +54,13 @@ class QEChannelOpener(QObject, AuthMixin):
self._updating_max = False
walletChanged = pyqtSignal()
- @pyqtProperty(QEWallet, notify=walletChanged)
+ @pyqtProperty(QVariant, notify=walletChanged)
def wallet(self):
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
+ assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
@@ -79,12 +79,13 @@ class QEChannelOpener(QObject, AuthMixin):
self.validate()
amountChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=amountChanged)
+ @pyqtProperty(QVariant, notify=amountChanged)
def amount(self):
return self._amount
@amount.setter
def amount(self, amount: QEAmount):
+ assert amount is None or isinstance(amount, QEAmount)
if self._amount != amount:
self._amount.copyFrom(amount)
self.amountChanged.emit()
diff --git a/electrum/gui/qml/qeinvoice.py b/electrum/gui/qml/qeinvoice.py
index 395f4c7..e9d30fc 100644
--- a/electrum/gui/qml/qeinvoice.py
+++ b/electrum/gui/qml/qeinvoice.py
@@ -4,7 +4,7 @@ from enum import IntEnum
from typing import Optional, Dict, Any, Tuple
from urllib.parse import urlparse
-from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum, QTimer
+from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum, QTimer, QVariant
from electrum.i18n import _
from electrum.logging import get_logger
@@ -111,12 +111,13 @@ class QEInvoice(QObject, QtEventListener):
self.determine_can_pay()
walletChanged = pyqtSignal()
- @pyqtProperty(QEWallet, notify=walletChanged)
+ @pyqtProperty(QVariant, notify=walletChanged)
def wallet(self):
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
+ assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
@@ -153,12 +154,13 @@ class QEInvoice(QObject, QtEventListener):
self._amount.copyFrom(QEAmount(from_invoice=self._effectiveInvoice))
return self._amount
- @pyqtProperty(QEAmount, notify=amountOverrideChanged)
+ @pyqtProperty(QVariant, notify=amountOverrideChanged)
def amountOverride(self):
return self._amountOverride
@amountOverride.setter
def amountOverride(self, new_amount: QEAmount):
+ assert new_amount is None or isinstance(new_amount, QEAmount)
self._logger.debug(f'set new override amount {repr(new_amount)}')
self._amountOverride.copyFrom(new_amount)
self.amountOverrideChanged.emit()
diff --git a/electrum/gui/qml/qelnpaymentdetails.py b/electrum/gui/qml/qelnpaymentdetails.py
index 574fb1b..2857c18 100644
--- a/electrum/gui/qml/qelnpaymentdetails.py
+++ b/electrum/gui/qml/qelnpaymentdetails.py
@@ -1,4 +1,4 @@
-from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
+from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QVariant
from electrum.logging import get_logger
from electrum.util import bfh, format_time
@@ -27,12 +27,13 @@ class QELnPaymentDetails(QObject):
self._preimage = ''
walletChanged = pyqtSignal()
- @pyqtProperty(QEWallet, notify=walletChanged)
+ @pyqtProperty(QVariant, notify=walletChanged)
def wallet(self):
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
+ assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
diff --git a/electrum/gui/qml/qepiresolver.py b/electrum/gui/qml/qepiresolver.py
index e171f80..f2c5b91 100644
--- a/electrum/gui/qml/qepiresolver.py
+++ b/electrum/gui/qml/qepiresolver.py
@@ -1,7 +1,7 @@
from enum import IntEnum
from typing import Optional
-from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer
+from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, QVariant
from electrum.logging import get_logger
from electrum.i18n import _
@@ -51,12 +51,13 @@ class QEPIResolver(QObject):
self.invoiceResolved.emit(self._pi)
walletChanged = pyqtSignal()
- @pyqtProperty(QEWallet, notify=walletChanged)
+ @pyqtProperty(QVariant, notify=walletChanged)
def wallet(self) -> Optional[QEWallet]:
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet) -> None:
+ assert wallet is None or isinstance(wallet, QEWallet)
self._wallet = wallet
@pyqtProperty(bool, notify=busyChanged)
diff --git a/electrum/gui/qml/qerequestdetails.py b/electrum/gui/qml/qerequestdetails.py
index ababb00..37fd70b 100644
--- a/electrum/gui/qml/qerequestdetails.py
+++ b/electrum/gui/qml/qerequestdetails.py
@@ -2,7 +2,7 @@ from enum import IntEnum
from typing import Optional
from urllib.parse import urlparse
-from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, pyqtEnum
+from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, pyqtEnum, QVariant
from electrum.logging import get_logger
from electrum.invoices import (
@@ -74,12 +74,13 @@ class QERequestDetails(QObject, QtEventListener):
self.statusChanged.emit()
walletChanged = pyqtSignal()
- @pyqtProperty(QEWallet, notify=walletChanged)
+ @pyqtProperty(QVariant, notify=walletChanged)
def wallet(self):
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
+ assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
diff --git a/electrum/gui/qml/qeswaphelper.py b/electrum/gui/qml/qeswaphelper.py
index 7475216..c112acf 100644
--- a/electrum/gui/qml/qeswaphelper.py
+++ b/electrum/gui/qml/qeswaphelper.py
@@ -4,7 +4,7 @@ from enum import IntEnum
from typing import Union, Optional, TYPE_CHECKING, Sequence
from PyQt6.QtCore import (pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, pyqtEnum, QAbstractListModel, Qt,
- QModelIndex)
+ QModelIndex, QVariant)
from PyQt6.QtGui import QColor
from electrum.i18n import _
@@ -205,12 +205,13 @@ class QESwapHelper(AuthMixin, QObject, QtEventListener):
self.unregister_callbacks()
walletChanged = pyqtSignal()
- @pyqtProperty(QEWallet, notify=walletChanged)
+ @pyqtProperty(QVariant, notify=walletChanged)
def wallet(self):
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
+ assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.run_swap_manager()
@@ -294,34 +295,37 @@ class QESwapHelper(AuthMixin, QObject, QtEventListener):
self.userinfoChanged.emit()
tosendChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=tosendChanged)
+ @pyqtProperty(QVariant, notify=tosendChanged)
def tosend(self):
return self._tosend
@tosend.setter
def tosend(self, tosend):
+ assert tosend is None or isinstance(tosend, QEAmount)
if self._tosend != tosend:
self._tosend = tosend
self.tosendChanged.emit()
toreceiveChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=toreceiveChanged)
+ @pyqtProperty(QVariant, notify=toreceiveChanged)
def toreceive(self):
return self._toreceive
@toreceive.setter
def toreceive(self, toreceive):
+ assert toreceive is None or isinstance(toreceive, QEAmount)
if self._toreceive != toreceive:
self._toreceive = toreceive
self.toreceiveChanged.emit()
serverMiningfeeChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=serverMiningfeeChanged)
+ @pyqtProperty(QVariant, notify=serverMiningfeeChanged)
def serverMiningfee(self):
return self._server_miningfee
@serverMiningfee.setter
def serverMiningfee(self, server_miningfee):
+ assert server_miningfee is None or isinstance(server_miningfee, QEAmount)
if self._server_miningfee != server_miningfee:
self._server_miningfee = server_miningfee
self.serverMiningfeeChanged.emit()
@@ -338,12 +342,13 @@ class QESwapHelper(AuthMixin, QObject, QtEventListener):
self.serverfeepercChanged.emit()
miningfeeChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=miningfeeChanged)
+ @pyqtProperty(QVariant, notify=miningfeeChanged)
def miningfee(self):
return self._miningfee
@miningfee.setter
def miningfee(self, miningfee):
+ assert miningfee is None or isinstance(miningfee, QEAmount)
if self._miningfee != miningfee:
self._miningfee = miningfee
self.miningfeeChanged.emit()
diff --git a/electrum/gui/qml/qetxdetails.py b/electrum/gui/qml/qetxdetails.py
index 50e885e..cfbf2f6 100644
--- a/electrum/gui/qml/qetxdetails.py
+++ b/electrum/gui/qml/qetxdetails.py
@@ -1,6 +1,6 @@
from typing import Optional
-from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
+from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QVariant
from electrum.i18n import _
from electrum.logging import get_logger
@@ -103,12 +103,13 @@ class QETxDetails(QObject, QtEventListener):
self.update()
walletChanged = pyqtSignal()
- @pyqtProperty(QEWallet, notify=walletChanged)
+ @pyqtProperty(QVariant, notify=walletChanged)
def wallet(self):
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
+ assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
diff --git a/electrum/gui/qml/qetxfinalizer.py b/electrum/gui/qml/qetxfinalizer.py
index e4114a8..2e46eb0 100644
--- a/electrum/gui/qml/qetxfinalizer.py
+++ b/electrum/gui/qml/qetxfinalizer.py
@@ -5,7 +5,7 @@ from decimal import Decimal
from typing import Optional, TYPE_CHECKING, Callable
from functools import partial
-from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum
+from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum, QVariant
from electrum.logging import get_logger
from electrum.i18n import _
@@ -68,12 +68,13 @@ class FeeSlider(QObject):
self._config = None # type: Optional[SimpleConfig]
walletChanged = pyqtSignal()
- @pyqtProperty(QEWallet, notify=walletChanged)
+ @pyqtProperty(QVariant, notify=walletChanged)
def wallet(self):
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
+ assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self._config = self._wallet.wallet.config
@@ -170,12 +171,13 @@ class TxFeeSlider(FeeSlider):
self._warning = ''
feeChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=feeChanged)
+ @pyqtProperty(QVariant, notify=feeChanged)
def fee(self):
return self._fee
@fee.setter
def fee(self, fee):
+ assert fee is None or isinstance(fee, QEAmount)
if self._fee != fee:
self._fee.copyFrom(fee)
self.feeChanged.emit()
@@ -419,12 +421,13 @@ class QETxFinalizer(TxFeeSlider):
self.addressChanged.emit()
amountChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=amountChanged)
+ @pyqtProperty(QVariant, notify=amountChanged)
def amount(self):
return self._amount
@amount.setter
- def amount(self, amount):
+ def amount(self, amount: QEAmount):
+ assert amount is None or isinstance(amount, QEAmount)
if self._amount != amount:
self._logger.debug(str(amount))
self._amount.copyFrom(amount)
@@ -436,12 +439,13 @@ class QETxFinalizer(TxFeeSlider):
return self._effectiveAmount
extraFeeChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=extraFeeChanged)
+ @pyqtProperty(QVariant, notify=extraFeeChanged)
def extraFee(self):
return self._extraFee
@extraFee.setter
- def extraFee(self, extrafee):
+ def extraFee(self, extrafee: QEAmount):
+ assert extrafee is None or isinstance(extrafee, QEAmount)
if self._extraFee != extrafee:
self._extraFee.copyFrom(extrafee)
self.extraFeeChanged.emit()
@@ -666,12 +670,13 @@ class QETxRbfFeeBumper(TxFeeSlider, TxMonMixin):
self._bump_methods_available = []
oldfeeChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=oldfeeChanged)
+ @pyqtProperty(QVariant, notify=oldfeeChanged)
def oldfee(self):
return self._oldfee
@oldfee.setter
- def oldfee(self, oldfee):
+ def oldfee(self, oldfee: QEAmount):
+ assert oldfee is None or isinstance(oldfee, QEAmount)
if self._oldfee != oldfee:
self._oldfee.copyFrom(oldfee)
self.oldfeeChanged.emit()
@@ -806,12 +811,13 @@ class QETxCanceller(TxFeeSlider, TxMonMixin):
self._rbf = True
oldfeeChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=oldfeeChanged)
+ @pyqtProperty(QVariant, notify=oldfeeChanged)
def oldfee(self):
return self._oldfee
@oldfee.setter
- def oldfee(self, oldfee):
+ def oldfee(self, oldfee: QEAmount):
+ assert oldfee is None or isinstance(oldfee, QEAmount)
if self._oldfee != oldfee:
self._oldfee.copyFrom(oldfee)
self.oldfeeChanged.emit()
@@ -938,12 +944,13 @@ class QETxCpfpFeeBumper(TxFeeSlider, TxMonMixin):
self._rbf = True
totalFeeChanged = pyqtSignal()
- @pyqtProperty(QEAmount, notify=totalFeeChanged)
+ @pyqtProperty(QVariant, notify=totalFeeChanged)
def totalFee(self):
return self._total_fee
@totalFee.setter
- def totalFee(self, totalfee):
+ def totalFee(self, totalfee: QEAmount):
+ assert totalfee is None or isinstance(totalfee, QEAmount)
if self._total_fee != totalfee:
self._total_fee.copyFrom(totalfee)
self.totalFeeChanged.emit()
Why this scored 25/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.