URI: 
       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())