tconfirm_tx_dialog.py - electrum - Electrum Bitcoin wallet
HTML git clone https://git.parazyd.org/electrum
DIR Log
DIR Files
DIR Refs
DIR Submodules
---
tconfirm_tx_dialog.py (5800B)
---
1 from decimal import Decimal
2 from typing import TYPE_CHECKING
3
4 from kivy.app import App
5 from kivy.factory import Factory
6 from kivy.properties import ObjectProperty
7 from kivy.lang import Builder
8 from kivy.uix.checkbox import CheckBox
9 from kivy.uix.label import Label
10 from kivy.uix.widget import Widget
11 from kivy.clock import Clock
12
13 from electrum.simple_config import FEERATE_WARNING_HIGH_FEE, FEE_RATIO_HIGH_WARNING
14 from electrum.gui.kivy.i18n import _
15 from electrum.plugin import run_hook
16 from electrum.util import NotEnoughFunds
17
18 from .fee_dialog import FeeSliderDialog, FeeDialog
19
20 if TYPE_CHECKING:
21 from electrum.gui.kivy.main_window import ElectrumWindow
22
23 Builder.load_string('''
24 <ConfirmTxDialog@Popup>
25 id: popup
26 title: _('Confirm Payment')
27 message: ''
28 warning: ''
29 extra_fee: ''
30 show_final: False
31 size_hint: 0.8, 0.8
32 pos_hint: {'top':0.9}
33 BoxLayout:
34 orientation: 'vertical'
35 BoxLayout:
36 orientation: 'horizontal'
37 size_hint: 1, 0.5
38 Label:
39 text: _('Amount to be sent:')
40 Label:
41 id: amount_label
42 text: ''
43 BoxLayout:
44 orientation: 'horizontal'
45 size_hint: 1, 0.5
46 Label:
47 text: _('Mining fee:')
48 Label:
49 id: fee_label
50 text: ''
51 BoxLayout:
52 orientation: 'horizontal'
53 size_hint: 1, (0.5 if root.extra_fee else 0.01)
54 Label:
55 text: _('Additional fees') if root.extra_fee else ''
56 Label:
57 text: root.extra_fee
58 BoxLayout:
59 orientation: 'horizontal'
60 size_hint: 1, 0.5
61 Label:
62 text: _('Fee target:')
63 Button:
64 id: fee_button
65 text: ''
66 background_color: (0,0,0,0)
67 bold: True
68 on_release:
69 root.on_fee_button()
70 Slider:
71 id: slider
72 range: 0, 4
73 step: 1
74 on_value: root.on_slider(self.value)
75 BoxLayout:
76 orientation: 'horizontal'
77 size_hint: 1, 0.2
78 Label:
79 text: _('Final')
80 opacity: int(root.show_final)
81 CheckBox:
82 id: final_cb
83 opacity: int(root.show_final)
84 disabled: not root.show_final
85 Label:
86 text: root.warning
87 text_size: self.width, None
88 Widget:
89 size_hint: 1, 0.5
90 BoxLayout:
91 orientation: 'horizontal'
92 size_hint: 1, 0.5
93 Button:
94 text: _('Cancel')
95 size_hint: 0.5, None
96 height: '48dp'
97 on_release:
98 popup.dismiss()
99 Button:
100 text: _('OK')
101 size_hint: 0.5, None
102 height: '48dp'
103 on_release:
104 root.pay()
105 popup.dismiss()
106 ''')
107
108
109
110
111 class ConfirmTxDialog(FeeSliderDialog, Factory.Popup):
112
113 def __init__(self, app: 'ElectrumWindow', invoice):
114
115 Factory.Popup.__init__(self)
116 FeeSliderDialog.__init__(self, app.electrum_config, self.ids.slider)
117 self.app = app
118 self.show_final = bool(self.config.get('use_rbf'))
119 self.invoice = invoice
120 self.update_slider()
121 self.update_text()
122 self.update_tx()
123
124 def update_tx(self):
125 outputs = self.invoice.outputs
126 try:
127 # make unsigned transaction
128 coins = self.app.wallet.get_spendable_coins(None)
129 tx = self.app.wallet.make_unsigned_transaction(coins=coins, outputs=outputs)
130 except NotEnoughFunds:
131 self.warning = _("Not enough funds")
132 return
133 except Exception as e:
134 self.logger.exception('')
135 self.app.show_error(repr(e))
136 return
137 rbf = not bool(self.ids.final_cb.active) if self.show_final else False
138 tx.set_rbf(rbf)
139 amount = sum(map(lambda x: x.value, outputs)) if '!' not in [x.value for x in outputs] else tx.output_value()
140 tx_size = tx.estimated_size()
141 fee = tx.get_fee()
142 feerate = Decimal(fee) / tx_size # sat/byte
143 self.ids.fee_label.text = self.app.format_amount_and_units(fee) + f' ({feerate:.1f} sat/B)'
144 self.ids.amount_label.text = self.app.format_amount_and_units(amount)
145 x_fee = run_hook('get_tx_extra_fee', self.app.wallet, tx)
146 if x_fee:
147 x_fee_address, x_fee_amount = x_fee
148 self.extra_fee = self.app.format_amount_and_units(x_fee_amount)
149 else:
150 self.extra_fee = ''
151 fee_warning_tuple = self.app.wallet.get_tx_fee_warning(
152 invoice_amt=amount, tx_size=tx_size, fee=fee)
153 if fee_warning_tuple:
154 allow_send, long_warning, short_warning = fee_warning_tuple
155 self.warning = long_warning
156 else:
157 self.warning = ''
158 self.tx = tx
159
160 def on_slider(self, value):
161 self.save_config()
162 self.update_text()
163 Clock.schedule_once(lambda dt: self.update_tx())
164
165 def update_text(self):
166 target, tooltip, dyn = self.config.get_fee_target()
167 self.ids.fee_button.text = target
168
169 def pay(self):
170 self.app.protected(_('Send payment?'), self.app.send_screen.send_tx, (self.tx, self.invoice))
171
172 def on_fee_button(self):
173 fee_dialog = FeeDialog(self, self.config, self.after_fee_changed)
174 fee_dialog.open()
175
176 def after_fee_changed(self):
177 self.read_config()
178 self.update_slider()
179 self.update_text()
180 Clock.schedule_once(lambda dt: self.update_tx())