You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
6.2 KiB
184 lines
6.2 KiB
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 electrum_gui.kivy.i18n import _ |
|
from datetime import datetime |
|
from electrum.util import InvalidPassword |
|
|
|
Builder.load_string(''' |
|
|
|
<TxDialog> |
|
id: popup |
|
title: _('Transaction') |
|
is_mine: True |
|
can_sign: False |
|
can_broadcast: False |
|
can_rbf: False |
|
fee_str: '' |
|
date_str: '' |
|
date_label:'' |
|
amount_str: '' |
|
tx_hash: '' |
|
status_str: '' |
|
description: '' |
|
outputs_str: '' |
|
BoxLayout: |
|
orientation: 'vertical' |
|
ScrollView: |
|
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: _('Status') |
|
value: root.status_str |
|
BoxLabel: |
|
text: _('Description') if root.description else '' |
|
value: root.description |
|
BoxLabel: |
|
text: root.date_label |
|
value: root.date_str |
|
BoxLabel: |
|
text: _('Amount sent') if root.is_mine else _('Amount received') |
|
value: root.amount_str |
|
BoxLabel: |
|
text: _('Transaction fee') if root.fee_str else '' |
|
value: root.fee_str |
|
TopLabel: |
|
text: _('Outputs') + ':' |
|
OutputList: |
|
height: self.minimum_height |
|
size_hint: 1, None |
|
id: output_list |
|
TopLabel: |
|
text: _('Transaction ID') + ':' if root.tx_hash else '' |
|
TxHashLabel: |
|
data: root.tx_hash |
|
name: _('Transaction ID') |
|
Widget: |
|
size_hint: 1, 0.1 |
|
|
|
BoxLayout: |
|
size_hint: 1, None |
|
height: '48dp' |
|
Button: |
|
size_hint: 0.5, None |
|
height: '48dp' |
|
text: _('Sign') if root.can_sign else _('Broadcast') if root.can_broadcast else _('Bump fee') if root.can_rbf else '' |
|
disabled: not(root.can_sign or root.can_broadcast or root.can_rbf) |
|
opacity: 0 if self.disabled else 1 |
|
on_release: |
|
if root.can_sign: root.do_sign() |
|
if root.can_broadcast: root.do_broadcast() |
|
if root.can_rbf: root.do_rbf() |
|
IconButton: |
|
size_hint: 0.5, None |
|
height: '48dp' |
|
icon: 'atlas://gui/kivy/theming/light/qrcode' |
|
on_release: root.show_qr() |
|
Button: |
|
size_hint: 0.5, None |
|
height: '48dp' |
|
text: _('Close') |
|
on_release: root.dismiss() |
|
''') |
|
|
|
|
|
class TxDialog(Factory.Popup): |
|
|
|
def __init__(self, app, tx): |
|
Factory.Popup.__init__(self) |
|
self.app = app |
|
self.wallet = self.app.wallet |
|
self.tx = tx |
|
|
|
def on_open(self): |
|
self.update() |
|
|
|
def update(self): |
|
format_amount = self.app.format_amount_and_units |
|
tx_hash, self.status_str, self.description, self.can_broadcast, self.can_rbf, amount, fee, height, conf, timestamp, exp_n = self.wallet.get_tx_info(self.tx) |
|
self.tx_hash = tx_hash or '' |
|
if timestamp: |
|
self.date_label = _('Date') |
|
self.date_str = datetime.fromtimestamp(timestamp).isoformat(' ')[:-3] |
|
elif exp_n: |
|
self.date_label = _('Mempool depth') |
|
self.date_str = _('{} from tip').format('%.2f MB'%(exp_n/1000000)) |
|
else: |
|
self.date_label = '' |
|
self.date_str = '' |
|
|
|
if amount is None: |
|
self.amount_str = _("Transaction unrelated to your wallet") |
|
elif amount > 0: |
|
self.is_mine = False |
|
self.amount_str = format_amount(amount) |
|
else: |
|
self.is_mine = True |
|
self.amount_str = format_amount(-amount) |
|
self.fee_str = format_amount(fee) if fee is not None else _('unknown') |
|
self.can_sign = self.wallet.can_sign(self.tx) |
|
self.ids.output_list.update(self.tx.outputs()) |
|
|
|
def do_rbf(self): |
|
from .bump_fee_dialog import BumpFeeDialog |
|
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(self.tx) |
|
if fee is None: |
|
self.app.show_error(_("Can't bump fee: unknown fee for original transaction.")) |
|
return |
|
size = self.tx.estimated_size() |
|
d = BumpFeeDialog(self.app, fee, size, self._do_rbf) |
|
d.open() |
|
|
|
def _do_rbf(self, old_fee, new_fee, is_final): |
|
if new_fee is None: |
|
return |
|
delta = new_fee - old_fee |
|
if delta < 0: |
|
self.app.show_error("fee too low") |
|
return |
|
try: |
|
new_tx = self.wallet.bump_fee(self.tx, delta) |
|
except BaseException as e: |
|
self.app.show_error(str(e)) |
|
return |
|
if is_final: |
|
new_tx.set_rbf(False) |
|
self.tx = new_tx |
|
self.update() |
|
self.do_sign() |
|
|
|
def do_sign(self): |
|
self.app.protected(_("Enter your PIN code in order to sign this transaction"), self._do_sign, ()) |
|
|
|
def _do_sign(self, password): |
|
self.status_str = _('Signing') + '...' |
|
Clock.schedule_once(lambda dt: self.__do_sign(password), 0.1) |
|
|
|
def __do_sign(self, password): |
|
try: |
|
self.app.wallet.sign_transaction(self.tx, password) |
|
except InvalidPassword: |
|
self.app.show_error(_("Invalid PIN")) |
|
self.update() |
|
|
|
def do_broadcast(self): |
|
self.app.broadcast(self.tx) |
|
|
|
def show_qr(self): |
|
from electrum.bitcoin import base_encode, bfh |
|
text = bfh(str(self.tx)) |
|
text = base_encode(text, base=43) |
|
self.app.qr_dialog(_("Raw Transaction"), text)
|
|
|