electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit feb47b0a6ff7c5f0dd4ab09ccdb1443133198ff9
parent b3a3267ede6a9ea97187c4b2d730b9d9ab1eec70
Author: ThomasV <thomasv@electrum.org>
Date:   Tue, 18 Feb 2020 12:34:09 +0100

Add lightning tx dialog (qt and kivy)

Diffstat:
Melectrum/gui/kivy/main_window.py | 5+++++
Aelectrum/gui/kivy/uix/dialogs/lightning_tx_dialog.py | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Melectrum/gui/kivy/uix/screens.py | 8+++++++-
Melectrum/gui/qt/history_list.py | 6++++++
Aelectrum/gui/qt/lightning_tx_dialog.py | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Melectrum/gui/qt/main_window.py | 5+++++
Melectrum/lnworker.py | 4++++
7 files changed, 222 insertions(+), 1 deletion(-)

diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py @@ -1040,6 +1040,11 @@ class ElectrumWindow(App): d = TxDialog(self, tx) d.open() + def lightning_tx_dialog(self, tx): + from .uix.dialogs.lightning_tx_dialog import LightningTxDialog + d = LightningTxDialog(self, tx) + d.open() + def sign_tx(self, *args): threading.Thread(target=self._sign_tx, args=args).start() diff --git a/electrum/gui/kivy/uix/dialogs/lightning_tx_dialog.py b/electrum/gui/kivy/uix/dialogs/lightning_tx_dialog.py @@ -0,0 +1,111 @@ +import copy +from datetime import datetime +from decimal import Decimal +from typing import NamedTuple, Callable, TYPE_CHECKING + +from kivy.app import App +from kivy.factory import Factory +from kivy.properties import ObjectProperty +from kivy.lang import Builder +from kivy.clock import Clock +from kivy.uix.label import Label +from kivy.uix.dropdown import DropDown +from kivy.uix.button import Button + +from electrum.gui.kivy.i18n import _ + + +if TYPE_CHECKING: + from ...main_window import ElectrumWindow + + +Builder.load_string(''' + +<LightningTxDialog> + id: popup + title: _('Lightning Payment') + preimage: '' + is_sent: False + amount_str: '' + fee_str: '' + date_str: '' + payment_hash: '' + description: '' + BoxLayout: + orientation: 'vertical' + ScrollView: + scroll_type: ['bars', 'content'] + bar_width: '25dp' + GridLayout: + height: self.minimum_height + size_hint_y: None + cols: 1 + spacing: '10dp' + padding: '10dp' + GridLayout: + height: self.minimum_height + size_hint_y: None + cols: 1 + spacing: '10dp' + BoxLabel: + text: _('Description') if root.description else '' + value: root.description + BoxLabel: + text: _('Date') + value: root.date_str + BoxLabel: + text: _('Amount sent') if root.is_sent else _('Amount received') + value: root.amount_str + BoxLabel: + text: _('Transaction fee') if root.fee_str else '' + value: root.fee_str + TopLabel: + text: _('Payment hash') + ':' + TxHashLabel: + data: root.payment_hash + name: _('Payment hash') + TopLabel: + text: _('Preimage') + TxHashLabel: + data: root.preimage + name: _('Preimage') + + Widget: + size_hint: 1, 0.1 + + BoxLayout: + size_hint: 1, None + height: '48dp' + Widget + Button: + size_hint: 0.5, None + height: '48dp' + text: _('Close') + on_release: root.dismiss() +''') + + +class ActionButtonOption(NamedTuple): + text: str + func: Callable + enabled: bool + + +class LightningTxDialog(Factory.Popup): + + def __init__(self, app, tx_item): + Factory.Popup.__init__(self) + self.app = app # type: ElectrumWindow + self.wallet = self.app.wallet + self._action_button_fn = lambda btn: None + self.is_sent = bool(tx_item['direction'] is 'sent') + self.description = tx_item['label'] + self.timestamp = tx_item['timestamp'] + self.date_str = datetime.fromtimestamp(self.timestamp).isoformat(' ')[:-3] + self.amount = Decimal(tx_item['amount_msat']) /1000 + self.payment_hash = tx_item['payment_hash'] + self.preimage = tx_item['preimage'] + format_amount = self.app.format_amount_and_units + self.amount_str = format_amount(self.amount) + if self.is_sent: + self.fee_str = format_amount(Decimal(tx_item['fee_msat']) / 1000) diff --git a/electrum/gui/kivy/uix/screens.py b/electrum/gui/kivy/uix/screens.py @@ -126,6 +126,10 @@ class HistoryScreen(CScreen): def show_item(self, obj): key = obj.key + tx_item = self.history.get(key) + if obj.is_lightning: + self.app.lightning_tx_dialog(tx_item) + return tx = self.app.wallet.db.get_transaction(key) if not tx: return @@ -156,6 +160,7 @@ class HistoryScreen(CScreen): fee_text = '' if fee is None else 'fee: %d sat'%fee ri = {} ri['screen'] = self + ri['is_lightning'] = is_lightning ri['key'] = key ri['icon'] = icon ri['date'] = status_str @@ -173,7 +178,8 @@ class HistoryScreen(CScreen): wallet = self.app.wallet if wallet is None: return - history = reversed(wallet.get_full_history(self.app.fx).values()) + self.history = wallet.get_full_history(self.app.fx) + history = reversed(self.history.values()) history_card = self.screen.ids.history_container history_card.data = [self.get_card(item) for item in history] diff --git a/electrum/gui/qt/history_list.py b/electrum/gui/qt/history_list.py @@ -580,6 +580,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): def show_transaction(self, tx_item): if tx_item.get('lightning'): + self.parent.show_lightning_transaction(tx_item) return tx_hash = tx_item['txid'] tx = self.wallet.db.get_transaction(tx_hash) @@ -608,6 +609,11 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): return tx_item = self.hm.transactions.value_from_pos(idx.row()) if tx_item.get('lightning'): + menu = QMenu() + #tx_hash = tx_item['txid'] + #menu.addAction(_("Copy Transaction ID"), lambda: self.place_text_on_clipboard(tx_hash, title="TXID")) + menu.addAction(_("Details"), lambda: self.parent.show_lightning_transaction(tx_item)) + menu.exec_(self.viewport().mapToGlobal(position)) return tx_hash = tx_item['txid'] tx = self.wallet.db.get_transaction(tx_hash) diff --git a/electrum/gui/qt/lightning_tx_dialog.py b/electrum/gui/qt/lightning_tx_dialog.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# +# Electrum - lightweight Bitcoin client +# Copyright (C) 2020 The Electrum Developers +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from typing import TYPE_CHECKING +from decimal import Decimal +import datetime +from PyQt5.QtWidgets import QVBoxLayout, QLabel, QGridLayout + +from electrum.i18n import _ +from .util import WindowModalDialog, ButtonsLineEdit, ColorScheme, Buttons, CloseButton + +if TYPE_CHECKING: + from .main_window import ElectrumWindow + + + +class LightningTxDialog(WindowModalDialog): + + def __init__(self, parent: 'ElectrumWindow', tx_item: dict): + WindowModalDialog.__init__(self, parent, _("Lightning Payment")) + self.parent = parent + self.is_sent = bool(tx_item['direction'] is 'sent') + self.label = tx_item['label'] + self.timestamp = tx_item['timestamp'] + self.amount = Decimal(tx_item['amount_msat']) /1000 + self.payment_hash = tx_item['payment_hash'] + self.preimage = tx_item['preimage'] + self.setMinimumWidth(700) + vbox = QVBoxLayout() + self.setLayout(vbox) + + vbox.addWidget(QLabel(_("Amount:") + self.parent.format_amount_and_units(self.amount))) + if self.is_sent: + fee = Decimal(tx_item['fee_msat']) / 1000 + vbox.addWidget(QLabel(_("Fee:") + self.parent.format_amount_and_units(fee))) + time_str = datetime.datetime.fromtimestamp(self.timestamp).isoformat(' ')[:-3] + vbox.addWidget(QLabel(_("Date:") + time_str)) + + qr_icon = "qrcode_white.png" if ColorScheme.dark_scheme else "qrcode.png" + + vbox.addWidget(QLabel(_("Payment hash:"))) + self.hash_e = ButtonsLineEdit(self.payment_hash) + self.hash_e.addCopyButton(self.parent.app) + self.hash_e.addButton(qr_icon, self.show_qr, _("Show QR Code")) + self.hash_e.setReadOnly(True) + vbox.addWidget(self.hash_e) + + vbox.addWidget(QLabel(_("Preimage:"))) + self.preimage_e = ButtonsLineEdit(self.preimage) + self.preimage_e.addCopyButton(self.parent.app) + self.preimage_e.addButton(qr_icon, self.show_qr, _("Show QR Code")) + self.preimage_e.setReadOnly(True) + vbox.addWidget(self.preimage_e) + + vbox.addLayout(Buttons(CloseButton(self))) + + def show_qr(self): + text = self.address + try: + self.parent.show_qrcode(text, '', parent=self) + except Exception as e: + self.show_message(repr(e)) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py @@ -956,6 +956,11 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): '''tx_desc is set only for txs created in the Send tab''' show_transaction(tx, parent=self, desc=tx_desc) + def show_lightning_transaction(self, tx_item): + from .lightning_tx_dialog import LightningTxDialog + d = LightningTxDialog(self, tx_item) + d.show() + def create_receive_tab(self): # A 4-column grid layout. All the stretch is in the last column. # The exchange rate plugin adds a fiat widget in column 2 diff --git a/electrum/lnworker.py b/electrum/lnworker.py @@ -502,6 +502,9 @@ class LNWallet(LNWorker): timestamp = min([htlc.timestamp for chan_id, htlc, _direction in plist]) fee_msat = None # fixme + payment_hash = bytes.fromhex(key) + preimage = self.get_preimage(payment_hash).hex() + item = { 'type': 'payment', 'label': label, @@ -511,6 +514,7 @@ class LNWallet(LNWorker): 'amount_msat': amount_msat, 'fee_msat': fee_msat, 'payment_hash': key, + 'preimage': preimage, } out.append(item) # add funding events