diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index f4a357e8c..9b9ff53d1 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -846,7 +846,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): self.update_status() # resolve aliases # FIXME this might do blocking network calls that has a timeout of several seconds - self.send_tab.payto_e.on_timer_check_text() + # self.send_tab.payto_e.on_timer_check_text() self.notify_transactions() def format_amount( diff --git a/electrum/gui/qt/paytoedit.py b/electrum/gui/qt/paytoedit.py index 0d5be55f0..ad106f5c0 100644 --- a/electrum/gui/qt/paytoedit.py +++ b/electrum/gui/qt/paytoedit.py @@ -190,12 +190,6 @@ class PayToEdit(Logger, GenericInputHandler): self.text_edit.setText(text) self.text_edit.setFocus() - def on_timer_check_text(self): - if self.editor.hasFocus(): - return - text = self.toPlainText() - self._check_text(text, full_check=True) - def _check_text(self, text, *, full_check: bool): """ side effects: self.is_multiline """ text = str(text).strip() diff --git a/electrum/gui/qt/send_tab.py b/electrum/gui/qt/send_tab.py index 185479ad7..6dc677d1e 100644 --- a/electrum/gui/qt/send_tab.py +++ b/electrum/gui/qt/send_tab.py @@ -33,7 +33,7 @@ class SendTab(QWidget, MessageBoxMixin, Logger): resolve_done_signal = pyqtSignal(object) finalize_done_signal = pyqtSignal(object) - round_3_signal = pyqtSignal(object) + notify_merchant_done_signal = pyqtSignal(object) def __init__(self, window: 'ElectrumWindow'): QWidget.__init__(self, window) @@ -182,8 +182,8 @@ class SendTab(QWidget, MessageBoxMixin, Logger): run_hook('create_send_tab', grid) self.resolve_done_signal.connect(self.on_resolve_done) - self.finalize_done_signal.connect(self.on_round_2) - self.round_3_signal.connect(self.on_round_3) + self.finalize_done_signal.connect(self.on_finalize_done) + self.notify_merchant_done_signal.connect(self.on_notify_merchant_done) def do_paste(self): text = self.window.app.clipboard().text() @@ -438,7 +438,7 @@ class SendTab(QWidget, MessageBoxMixin, Logger): # must not be None return self.amount_e.get_amount() or 0 - def on_round_2(self, pi): + def on_finalize_done(self, pi): self.do_clear() if pi.error: self.show_error(pi.error) @@ -449,9 +449,6 @@ class SendTab(QWidget, MessageBoxMixin, Logger): self.pending_invoice = invoice self.do_pay_invoice(invoice) - def on_round_3(self): - pass - def do_pay_or_get_invoice(self): pi = self.payment_identifier if pi.need_finalize(): @@ -634,7 +631,11 @@ class SendTab(QWidget, MessageBoxMixin, Logger): txid = tx.txid() if self.payment_identifier.need_merchant_notify(): refund_address = self.wallet.get_receiving_address() - self.payment_identifier.notify_merchant(tx=tx, refund_address=refund_address) + self.payment_identifier.notify_merchant( + tx=tx, + refund_address=refund_address, + on_finished=self.notify_merchant_done_signal.emit + ) return True, txid # Capture current TL window; override might be removed on return @@ -658,6 +659,14 @@ class SendTab(QWidget, MessageBoxMixin, Logger): WaitingDialog(self, _('Broadcasting transaction...'), broadcast_thread, broadcast_done, self.window.on_error) + def on_notify_merchant_done(self, pi): + if pi.is_error(): + self.logger.debug(f'merchant notify error: {pi.get_error()}') + else: + self.logger.debug(f'merchant notify result: {pi.merchant_ack_status}: {pi.merchant_ack_message}') + # TODO: show user? if we broadcasted the tx succesfully, do we care? + # BitPay complains with a NAK if tx is RbF + def toggle_paytomany(self): self.payto_e.toggle_paytomany() if self.payto_e.is_paytomany(): diff --git a/electrum/payment_identifier.py b/electrum/payment_identifier.py index 7137f9397..a87873c65 100644 --- a/electrum/payment_identifier.py +++ b/electrum/payment_identifier.py @@ -256,6 +256,9 @@ class PaymentIdentifier(Logger): def is_multiline(self): return bool(self.multiline_outputs) + def is_error(self) -> bool: + return self._state >= PaymentIdentifierState.ERROR + def get_error(self) -> str: return self.error @@ -267,6 +270,10 @@ class PaymentIdentifier(Logger): if outputs := self._parse_as_multiline(text): self._type = 'multiline' self.multiline_outputs = outputs + if self.error: + self.set_state(PaymentIdentifierState.INVALID) + else: + self.set_state(PaymentIdentifierState.AVAILABLE) elif invoice_or_lnurl := maybe_extract_lightning_payment_identifier(text): if invoice_or_lnurl.startswith('lnurl'): self._type = 'lnurl' @@ -457,15 +464,15 @@ class PaymentIdentifier(Logger): for i, line in enumerate(lines): try: output = self.parse_address_and_amount(line) + outputs.append(output) + if parse_max_spend(output.value): + is_max = True + else: + total += output.value except Exception as e: errors.append(PayToLineError( idx=i, line_content=line.strip(), exc=e, is_multiline=True)) continue - outputs.append(output) - if parse_max_spend(output.value): - is_max = True - else: - total += output.value if is_multiline and errors: self.error = str(errors) if errors else None self.logger.debug(f'multiline: {outputs!r}, {self.error}') @@ -477,6 +484,8 @@ class PaymentIdentifier(Logger): except ValueError: raise Exception("expected two comma-separated values: (address, amount)") from None scriptpubkey = self.parse_output(x) + if not scriptpubkey: + raise Exception('Invalid address') amount = self.parse_amount(y) return PartialTxOutput(scriptpubkey=scriptpubkey, value=amount)