コード例 #1
0
 def create_menu(self, position):
     items = self.selected_in_column(0)
     if len(items) > 1:
         keys = [item.data(ROLE_KEY) for item in items]
         menu = QMenu(self)
         menu.addAction(_("Delete requests"),
                        lambda: self.parent.delete_requests(keys))
         menu.exec_(self.viewport().mapToGlobal(position))
         return
     idx = self.indexAt(position)
     # TODO use siblingAtColumn when min Qt version is >=5.11
     item = self.item_from_index(idx.sibling(idx.row(), self.Columns.DATE))
     if not item:
         return
     key = item.data(ROLE_KEY)
     req = self.wallet.get_request(key)
     if req is None:
         self.update()
         return
     menu = QMenu(self)
     self.add_copy_menu(menu, idx)
     URI = self.wallet.get_request_URI(req)
     menu.addAction(_("Copy Request"),
                    lambda: self.parent.do_copy(URI, title='Dash URI'))
     menu.addAction(
         _("Copy Address"),
         lambda: self.parent.do_copy(req.get_address(),
                                     title='Dash Address'))
     #if 'view_url' in req:
     #    menu.addAction(_("View in web browser"), lambda: webopen(req['view_url']))
     menu.addAction(_("Delete"), lambda: self.parent.delete_requests([key]))
     run_hook('receive_list_menu', menu, key)
     menu.exec_(self.viewport().mapToGlobal(position))
コード例 #2
0
    def __init__(self, text=None):
        ButtonsTextEdit.__init__(self, text)
        self.setReadOnly(1)
        icon = "qrcode.png"
        self.addButton(icon, self.qr_show, _("Show as QR code"))

        run_hook('show_text_edit', self)
コード例 #3
0
    def __init__(self, text=None, *, config: SimpleConfig):
        ButtonsTextEdit.__init__(self, text)
        self.config = config
        self.setReadOnly(True)
        icon = "qrcode.png"
        self.addButton(icon, self.qr_show, _("Show as QR code"))

        run_hook('show_text_edit', self)
コード例 #4
0
 def __init__(self, text="", allow_multi=False):
     ButtonsTextEdit.__init__(self, text)
     self.allow_multi = allow_multi
     self.setReadOnly(0)
     self.addButton("file.png", self.file_input, _("Read file"))
     icon = "camera_white.png" if ColorScheme.dark_scheme else "camera_dark.png"
     self.addButton(icon, self.qr_input, _("Read QR code"))
     run_hook('scan_text_edit', self)
コード例 #5
0
 def close_window(self, window: ElectrumWindow):
     if window in self.windows:
         self.windows.remove(window)
     self.build_tray_menu()
     # save wallet path of last open window
     if not self.windows:
         self.config.save_last_wallet(window.wallet)
     run_hook('on_close_window', window)
     self.daemon.stop_wallet(window.wallet.storage.path)
コード例 #6
0
 def __init__(self, parent=None, msg=None):
     msg = msg or _('Please enter your password')
     WindowModalDialog.__init__(self, parent, _("Enter Password"))
     self.pw = pw = PasswordLineEdit()
     vbox = QVBoxLayout()
     vbox.addWidget(QLabel(msg))
     grid = QGridLayout()
     grid.setSpacing(8)
     grid.addWidget(QLabel(_('Password')), 1, 0)
     grid.addWidget(pw, 1, 1)
     vbox.addLayout(grid)
     vbox.addLayout(Buttons(CancelButton(self), OkButton(self)))
     self.setLayout(vbox)
     run_hook('password_dialog', pw, grid, 1)
コード例 #7
0
 def update_tx(self):
     try:
         # make unsigned transaction
         tx = self.make_tx()
     except NotEnoughFunds:
         self.warning = _("Not enough funds")
         self.ids.ok_button.disabled = True
         return
     except Exception as e:
         self.ids.ok_button.disabled = True
         self.app.logger.exception('')
         self.app.show_error(repr(e))
         return
     self.ids.ok_button.disabled = False
     amount = self.amount if self.amount != '!' else tx.output_value()
     tx_size = tx.estimated_size()
     fee = tx.get_fee()
     self.ids.fee_label.text = self.app.format_amount_and_units(fee)
     feerate = Decimal(fee) / Decimal(tx_size) * 1000  # duffs/kB
     self.ids.feerate_label.text = f'{feerate:.1f} duffs/kB'
     self.ids.amount_label.text = self.app.format_amount_and_units(amount)
     x_fee = run_hook('get_tx_extra_fee', self.app.wallet, tx)
     if x_fee:
         x_fee_address, x_fee_amount = x_fee
         self.extra_fee = self.app.format_amount_and_units(x_fee_amount)
     else:
         self.extra_fee = ''
     fee_warning_tuple = self.app.wallet.get_tx_fee_warning(
         invoice_amt=amount, tx_size=tx_size, fee=fee)
     if fee_warning_tuple:
         allow_send, long_warning, short_warning = fee_warning_tuple
         self.warning = long_warning
     else:
         self.warning = ''
     self.tx = tx
コード例 #8
0
    def __init__(self, config: 'SimpleConfig', daemon: 'Daemon',
                 plugins: 'Plugins'):
        set_language(config.get('language', get_default_language()))
        Logger.__init__(self)
        self.logger.info(
            f"Qt GUI starting up... Qt={QtCore.QT_VERSION_STR}, PyQt={QtCore.PYQT_VERSION_STR}"
        )
        # Uncomment this call to verify objects are being properly
        # GC-ed when windows are closed
        #network.add_jobs([DebugMem([Abstract_Wallet, SPV, Synchronizer,
        #                            ElectrumWindow], interval=5)])
        QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads)
        if hasattr(QtCore.Qt, "AA_ShareOpenGLContexts"):
            QtCore.QCoreApplication.setAttribute(
                QtCore.Qt.AA_ShareOpenGLContexts)
        if hasattr(QGuiApplication, 'setDesktopFileName'):
            QGuiApplication.setDesktopFileName('electrum-firo.desktop')
        self.gui_thread = threading.current_thread()
        self.config = config
        self.daemon = daemon
        self.plugins = plugins
        self.windows = []  # type: List[ElectrumWindow]
        self.efilter = OpenFileEventFilter(self.windows)
        self.app = QElectrumApplication(sys.argv)
        self.app.installEventFilter(self.efilter)
        self.app.setWindowIcon(read_QIcon("electrum-dash.png"))
        # timer
        self.timer = QTimer(self.app)
        self.timer.setSingleShot(False)
        self.timer.setInterval(500)  # msec

        self.network_dialog = None
        self.dash_net_dialog = None
        self.network_updated_signal_obj = QNetworkUpdatedSignalObject()
        self.dash_net_sobj = QDashNetSignalsObject()
        self._num_wizards_in_progress = 0
        self._num_wizards_lock = threading.Lock()
        # init tray
        self.dark_icon = self.config.get("dark_icon", False)
        self.tray = QSystemTrayIcon(self.tray_icon(), None)
        self.tray.setToolTip('Firo Electrum')
        self.tray.activated.connect(self.tray_activated)
        self.build_tray_menu()
        self.tray.show()
        self.app.new_window_signal.connect(self.start_new_window)
        self.set_dark_theme_if_needed()
        run_hook('init_qt', self)
コード例 #9
0
    def create_menu(self, position):
        menu = QMenu()
        idx = self.indexAt(position)
        column = idx.column() or self.Columns.NAME
        selected_keys = []
        for s_idx in self.selected_in_column(self.Columns.NAME):
            sel_key = self.model().itemFromIndex(s_idx).data(
                self.ROLE_CONTACT_KEY)
            selected_keys.append(sel_key)
        if not selected_keys or not idx.isValid():
            menu.addAction(_("New contact"),
                           lambda: self.parent.new_contact_dialog())
            menu.addAction(_("Import file"),
                           lambda: self.parent.import_contacts())
            menu.addAction(_("Export file"),
                           lambda: self.parent.export_contacts())
        else:
            column_title = self.model().horizontalHeaderItem(column).text()
            column_data = '\n'.join(
                self.model().itemFromIndex(s_idx).text()
                for s_idx in self.selected_in_column(column))
            menu.addAction(
                _("Copy {}").format(column_title),
                lambda: self.place_text_on_clipboard(column_data,
                                                     title=column_title))
            if column in self.editable_columns:
                item = self.model().itemFromIndex(idx)
                if item.isEditable():
                    # would not be editable if openalias
                    persistent = QPersistentModelIndex(idx)
                    menu.addAction(
                        _("Edit {}").format(column_title),
                        lambda p=persistent: self.edit(QModelIndex(p)))
            menu.addAction(_("Pay to"),
                           lambda: self.parent.payto_contacts(selected_keys))
            menu.addAction(_("Delete"),
                           lambda: self.parent.delete_contacts(selected_keys))
            URLs = [
                block_explorer_URL(self.config, 'addr', key)
                for key in filter(is_address, selected_keys)
            ]
            if URLs:
                menu.addAction(_("View on block explorer"),
                               lambda: [webopen(u) for u in URLs])

        run_hook('create_contact_menu', menu, selected_keys)
        menu.exec_(self.viewport().mapToGlobal(position))
コード例 #10
0
    def update(self):
        tx = self.tx
        self._update_amount_label()

        if self.not_enough_funds:
            text = _("Not enough funds")
            c, u, x = self.wallet.get_frozen_balance()
            if c + u + x:
                text += " ({} {} {})".format(
                    self.main_window.format_amount(c + u + x).strip(),
                    self.main_window.base_unit(), _("are frozen"))
            self.toggle_send_button(False, message=text)
            return

        if not tx:
            return

        psman = self.main_window.wallet.psman
        if (psman.is_hw_ks and psman.is_ps_ks_inputs_in_tx(tx)
                and psman.is_ps_ks_encrypted()):
            self.password_required = True

        fee = tx.get_fee()
        self.fee_label.setText(self.main_window.format_amount_and_units(fee))
        x_fee = run_hook('get_tx_extra_fee', self.wallet, tx)
        if x_fee:
            x_fee_address, x_fee_amount = x_fee
            self.extra_fee_label.setVisible(True)
            self.extra_fee_value.setVisible(True)
            self.extra_fee_value.setText(
                self.main_window.format_amount_and_units(x_fee_amount))

        amount = tx.output_value(
        ) if self.output_value == '!' else self.output_value
        feerate = Decimal(fee) / Decimal(
            tx.estimated_size() / 1000)  # duffs/kB
        fee_ratio = Decimal(fee) / amount if amount else 1
        if feerate < self.wallet.relayfee():
            msg = '\n'.join([
                _("This transaction requires a higher fee, or it will not be propagated by your current server"
                  ),
                _("Try to raise your transaction fee, or use a server with a lower relay fee."
                  )
            ])
            self.toggle_send_button(False, message=msg)
        elif fee_ratio >= FEE_RATIO_HIGH_WARNING:
            self.toggle_send_button(
                True,
                message=_('Warning') + ': ' +
                _("The fee for this transaction seems unusually high.") +
                f'\n({fee_ratio*100:.2f}% of amount)')
        elif feerate > FEERATE_WARNING_HIGH_FEE:
            self.toggle_send_button(
                True,
                message=_('Warning') + ': ' +
                _("The fee for this transaction seems unusually high.") +
                f'\n(feerate: {feerate:.1f} duffs/kB)')
        else:
            self.toggle_send_button(True)
コード例 #11
0
 def update(self):
     if self.maybe_defer_update():
         return
     current_key = self.current_item_user_role(col=self.Columns.NAME)
     self.model().clear()
     self.update_headers(self.__class__.headers)
     set_current = None
     for key in sorted(self.parent.contacts.keys()):
         contact_type, name = self.parent.contacts[key]
         items = [QStandardItem(x) for x in (name, key)]
         items[self.Columns.NAME].setEditable(contact_type != 'openalias')
         items[self.Columns.ADDRESS].setEditable(False)
         items[self.Columns.NAME].setData(key, Qt.UserRole)
         row_count = self.model().rowCount()
         self.model().insertRow(row_count, items)
         if key == current_key:
             idx = self.model().index(row_count, self.Columns.NAME)
             set_current = QPersistentModelIndex(idx)
     self.set_current_idx(set_current)
     # FIXME refresh loses sort order; so set "default" here:
     self.sortByColumn(self.Columns.NAME, Qt.AscendingOrder)
     self.filter()
     run_hook('update_contacts_tab', self)
コード例 #12
0
ファイル: console.py プロジェクト: margaryan/electrum-firo
 def __init__(self, parent=None, msg=None):
     msg = msg or _('Please enter your password')
     WindowModalDialog.__init__(self, parent, _('Enter Password'))
     self.pw = pw = QtWidgets.QLineEdit()
     pw.setEchoMode(2)
     vbox = QtWidgets.QVBoxLayout()
     vbox.addWidget(QtWidgets.QLabel(msg))
     inactivity_lb = QtWidgets.QLabel(_('Inactivity timeout in minutes'))
     self.inactivity_sb = QtWidgets.QSpinBox()
     self.inactivity_sb.setMinimum(1)
     self.inactivity_sb.setMaximum(10)
     self.config = parent.config
     timeout = parent.config.get('console_kbd_timeout', 1)
     self.inactivity_sb.setValue(timeout)
     grid = QtWidgets.QGridLayout()
     grid.setSpacing(8)
     grid.addWidget(QtWidgets.QLabel(_('Password')), 1, 0)
     grid.addWidget(pw, 1, 1)
     grid.addWidget(inactivity_lb, 20, 0)
     grid.addWidget(self.inactivity_sb, 20, 1, 1, -1)
     vbox.addLayout(grid)
     vbox.addLayout(Buttons(CancelButton(self), OkButton(self)))
     self.setLayout(vbox)
     run_hook('password_dialog', pw, grid, 1)
コード例 #13
0
    def update(self):
        tx = self.tx
        self._update_amount_label()

        if self.not_enough_funds:
            text = self.main_window.get_text_not_enough_funds_mentioning_frozen(
            )
            self.toggle_send_button(False, message=text)
            return

        if not tx:
            return

        psman = self.main_window.wallet.psman
        if (psman.is_hw_ks and psman.is_ps_ks_inputs_in_tx(tx)
                and psman.is_ps_ks_encrypted()):
            self.password_required = True

        self.pw_label.setVisible(self.password_required)
        self.pw.setVisible(self.password_required)

        fee = tx.get_fee()
        assert fee is not None
        self.fee_label.setText(self.main_window.format_amount_and_units(fee))
        x_fee = run_hook('get_tx_extra_fee', self.wallet, tx)
        if x_fee:
            x_fee_address, x_fee_amount = x_fee
            self.extra_fee_label.setVisible(True)
            self.extra_fee_value.setVisible(True)
            self.extra_fee_value.setText(
                self.main_window.format_amount_and_units(x_fee_amount))

        amount = tx.output_value(
        ) if self.output_value == '!' else self.output_value
        tx_size = tx.estimated_size()
        fee_warning_tuple = self.wallet.get_tx_fee_warning(invoice_amt=amount,
                                                           tx_size=tx_size,
                                                           fee=fee)
        if fee_warning_tuple:
            allow_send, long_warning, short_warning = fee_warning_tuple
            self.toggle_send_button(allow_send, message=long_warning)
        else:
            self.toggle_send_button(True)
コード例 #14
0
ファイル: screens.py プロジェクト: hakonamatata/electrum-firo
    def _do_pay_onchain(self, invoice: OnchainInvoice, is_ps=False) -> None:
        # make unsigned transaction
        outputs = invoice.outputs
        wallet = self.app.wallet
        mix_rounds = None if not is_ps else wallet.psman.mix_rounds
        include_ps = (mix_rounds is None)
        coins = wallet.get_spendable_coins(None, include_ps=include_ps,
                                           min_rounds=mix_rounds)
        try:
            tx = wallet.make_unsigned_transaction(coins=coins, outputs=outputs,
                                                  min_rounds=mix_rounds)
        except NotEnoughFunds:
            self.app.show_error(_("Not enough funds"))
            return
        except Exception as e:
            self.logger.exception('')
            self.app.show_error(repr(e))
            return
        fee = tx.get_fee()
        amount = sum(map(lambda x: x.value, outputs)) if '!' not in [x.value for x in outputs] else tx.output_value()
        msg = [
            _("Amount to be sent") + ": " + self.app.format_amount_and_units(amount),
            _("Mining fee") + ": " + self.app.format_amount_and_units(fee),
        ]
        x_fee = run_hook('get_tx_extra_fee', self.app.wallet, tx)
        if x_fee:
            x_fee_address, x_fee_amount = x_fee
            msg.append(_("Additional fees") + ": " + self.app.format_amount_and_units(x_fee_amount))

        feerate = Decimal(fee) / Decimal(tx.estimated_size() / 1000)  # duffs/kB
        fee_ratio = Decimal(fee) / amount if amount else 1
        if fee_ratio >= FEE_RATIO_HIGH_WARNING:
            msg.append(_('Warning') + ': ' + _("The fee for this transaction seems unusually high.")
                       + f' ({fee_ratio*100:.2f}% of amount)')
        elif feerate > FEERATE_WARNING_HIGH_FEE:
            msg.append(_('Warning') + ': ' + _("The fee for this transaction seems unusually high.")
                       + f' (feerate: {feerate:.1f} duffs/kB)')
        self.app.protected('\n'.join(msg), self.send_tx, (tx, invoice))
コード例 #15
0
    def update(self):
        if not self.finalized:
            self.update_fee_fields()
            self.finalize_button.setEnabled(self.can_finalize())
        if self.tx is None:
            return
        self.update_io()
        desc = self.desc
        base_unit = self.main_window.base_unit()
        format_amount = self.main_window.format_amount
        format_fiat_and_units = self.main_window.format_fiat_and_units
        tx_details = self.wallet.get_tx_info(self.tx)
        tx_mined_status = tx_details.tx_mined_status
        exp_n = tx_details.mempool_depth_bytes
        amount, fee = tx_details.amount, tx_details.fee
        size = self.tx.estimated_size()
        txid = self.tx.txid()
        fx = self.main_window.fx
        tx_item_fiat = None
        if (self.
                finalized  # ensures we don't use historical rates for tx being constructed *now*
                and txid is not None and fx.is_enabled()
                and amount is not None):
            tx_item_fiat = self.wallet.get_tx_item_fiat(tx_hash=txid,
                                                        amount_sat=abs(amount),
                                                        fx=fx,
                                                        tx_fee=fee)
        self.broadcast_button.setEnabled(tx_details.can_broadcast)
        can_sign = not self.tx.is_complete() and \
            (self.wallet.can_sign(self.tx) or bool(self.external_keypairs))
        self.sign_button.setEnabled(can_sign)
        if self.finalized and tx_details.txid:
            self.tx_hash_e.setText(tx_details.txid)
        else:
            # note: when not finalized, locktime changes do not trigger
            #       a make_tx, so the txid is unreliable, hence:
            self.tx_hash_e.setText(_('Unknown'))
        if not desc:
            self.tx_desc.hide()
        else:
            self.tx_desc.setText(_("Description") + ': ' + desc)
            self.tx_desc.show()
        self.status_label.setText(_('Status:') + ' ' + tx_details.status)

        islock = tx_details.islock
        timestamp = tx_mined_status.timestamp
        if not timestamp and islock:
            timestamp = islock
        if timestamp:
            dttm = datetime.datetime.fromtimestamp(timestamp)
            time_str = dttm.isoformat(' ')[:-3]
            self.date_label.setText(_("Date: {}").format(time_str))
            self.date_label.show()
        elif exp_n is not None:
            text = '%.2f MB' % (exp_n / 1000000)
            self.date_label.setText(
                _('Position in mempool: {} from tip').format(text))
            self.date_label.show()
        else:
            self.date_label.hide()
        if self.tx.locktime <= NLOCKTIME_BLOCKHEIGHT_MAX:
            locktime_final_str = f"LockTime: {self.tx.locktime} (height)"
        else:
            locktime_final_str = f"LockTime: {self.tx.locktime} ({datetime.datetime.fromtimestamp(self.tx.locktime)})"
        self.locktime_final_label.setText(locktime_final_str)
        if self.locktime_e.get_locktime() is None:
            self.locktime_e.set_locktime(self.tx.locktime)

        if tx_mined_status.header_hash:
            self.block_hash_label.setText(
                _("Included in block: {}").format(tx_mined_status.header_hash))
            self.block_height_label.setText(
                _("At block height: {}").format(tx_mined_status.height))
        else:
            self.block_hash_label.hide()
            self.block_height_label.hide()
        if amount is None:
            amount_str = _("Transaction unrelated to your wallet")
        elif amount is None:
            amount_str = ''
        else:
            if amount > 0:
                amount_str = _("Amount received:") + ' %s' % format_amount(
                    amount) + ' ' + base_unit
            else:
                amount_str = _("Amount sent:") + ' %s' % format_amount(
                    -amount) + ' ' + base_unit
            if fx.is_enabled():
                if tx_item_fiat:
                    amount_str += ' (%s)' % tx_item_fiat[
                        'fiat_value'].to_ui_string()
                else:
                    amount_str += ' (%s)' % format_fiat_and_units(abs(amount))
        if amount_str:
            self.amount_label.setText(amount_str)
        else:
            self.amount_label.hide()
        size_str = _("Size:") + ' %d bytes' % size
        if fee is None:
            fee_str = _("Fee") + ': ' + _("unknown")
        else:
            fee_str = _("Fee") + f': {format_amount(fee)} {base_unit}'
            if fx.is_enabled():
                if tx_item_fiat:
                    fiat_fee_str = tx_item_fiat['fiat_fee'].to_ui_string()
                else:
                    fiat_fee_str = format_fiat_and_units(fee)
                fee_str += f' ({fiat_fee_str})'
        if fee is not None:
            fee_rate = Decimal(fee) / size  # sat/byte
            fee_str += '  ( %s ) ' % self.main_window.format_fee_rate(
                fee_rate * 1000)
            if isinstance(self.tx, PartialTransaction):
                if isinstance(self, PreviewTxDialog):
                    invoice_amt = self.tx.output_value(
                    ) if self.output_value == '!' else self.output_value
                else:
                    invoice_amt = amount
                fee_warning_tuple = self.wallet.get_tx_fee_warning(
                    invoice_amt=invoice_amt, tx_size=size, fee=fee)
                if fee_warning_tuple:
                    allow_send, long_warning, short_warning = fee_warning_tuple
                    fee_str += " - <font color={color}>{header}: {body}</font>".format(
                        header=_('Warning'),
                        body=short_warning,
                        color=ColorScheme.RED.as_color().name(),
                    )
        if isinstance(self.tx, PartialTransaction):
            risk_of_burning_coins = (
                can_sign and fee is not None
                and self.wallet.get_warning_for_risk_of_burning_coins_as_fees(
                    self.tx))
            self.fee_warning_icon.setToolTip(str(risk_of_burning_coins))
            self.fee_warning_icon.setVisible(bool(risk_of_burning_coins))
        self.fee_label.setText(fee_str)
        self.size_label.setText(size_str)
        show_psbt_only_widgets = self.finalized and isinstance(
            self.tx, PartialTransaction)
        for widget in self.psbt_only_widgets:
            if isinstance(widget, QMenu):
                widget.menuAction().setVisible(show_psbt_only_widgets)
            else:
                widget.setVisible(show_psbt_only_widgets)

        self.save_button.setEnabled(tx_details.can_save_as_local)
        if tx_details.can_save_as_local:
            self.save_button.setToolTip(_("Save transaction offline"))
        else:
            self.save_button.setToolTip(
                _("Transaction already saved or not yet signed."))

        tx_type = self.tx.tx_type
        if tx_type == 0:
            self.extra_pld_lb.hide()
            self.extra_pld.hide()

            txid = self.tx.txid()
            if txid:
                tx_type, completed = self.wallet.db.get_ps_tx(txid)
        else:
            extra_payload = self.tx.extra_payload
            self.extra_pld.set_extra_data(tx_type, extra_payload)
            self.extra_pld_lb.show()
            self.extra_pld.show()
        tx_type_name = '%s: %s, ' % (_('Type'), SPEC_TX_NAMES[tx_type])
        self.txid_lb.setText(tx_type_name + _('Transaction ID:'))

        run_hook('transaction_dialog_update', self)
コード例 #16
0
    def __init__(self,
                 *,
                 parent: 'ElectrumWindow',
                 desc,
                 prompt_if_unsaved,
                 finalized: bool,
                 external_keypairs=None):
        '''Transactions in the wallet will show their description.
        Pass desc to give a description for txs not yet in the wallet.
        '''
        # We want to be a top-level window
        QDialog.__init__(self, parent=None)
        self.tx = None  # type: Optional[Transaction]
        self.external_keypairs = external_keypairs
        self.finalized = finalized
        self.main_window = parent
        self.config = parent.config
        self.wallet = parent.wallet
        self.prompt_if_unsaved = prompt_if_unsaved
        self.saved = False
        self.desc = desc
        self.setMinimumWidth(640)
        self.resize(1200, 600)
        self.set_title()

        self.psbt_only_widgets = []  # type: List[QWidget]

        vbox = QVBoxLayout()
        self.setLayout(vbox)

        self.txid_lb = QLabel(_('Transaction ID:'))
        vbox.addWidget(self.txid_lb)
        self.tx_hash_e = ButtonsLineEdit()
        qr_show = lambda: parent.show_qrcode(
            str(self.tx_hash_e.text()), 'Transaction ID', parent=self)
        qr_icon = "qrcode.png"
        self.tx_hash_e.addButton(qr_icon, qr_show, _("Show as QR code"))
        self.tx_hash_e.setReadOnly(True)
        vbox.addWidget(self.tx_hash_e)

        self.add_tx_stats(vbox)

        vbox.addSpacing(10)

        self.inputs_header = QLabel()
        vbox.addWidget(self.inputs_header)
        self.inputs_textedit = QTextEditWithDefaultSize()
        vbox.addWidget(self.inputs_textedit)

        self.txo_color_recv = TxOutputColoring(
            legend=_("Receiving Address"),
            color=ColorScheme.GREEN,
            tooltip=_("Wallet receive address"))
        self.txo_color_change = TxOutputColoring(
            legend=_("Change Address"),
            color=ColorScheme.YELLOW,
            tooltip=_("Wallet change address"))

        outheader_hbox = QHBoxLayout()
        outheader_hbox.setContentsMargins(0, 0, 0, 0)
        vbox.addLayout(outheader_hbox)
        self.outputs_header = QLabel()
        outheader_hbox.addWidget(self.outputs_header)
        outheader_hbox.addStretch(2)
        outheader_hbox.addWidget(self.txo_color_recv.legend_label)
        outheader_hbox.addWidget(self.txo_color_change.legend_label)

        self.outputs_textedit = QTextEditWithDefaultSize()
        vbox.addWidget(self.outputs_textedit)

        self.extra_pld_lb = QLabel('Extra payload:')
        self.extra_pld_lb.hide()
        vbox.addWidget(self.extra_pld_lb)
        self.extra_pld = ExtraPayloadWidget()
        self.extra_pld.hide()
        vbox.addWidget(self.extra_pld)

        self.sign_button = b = QPushButton(_("Sign"))
        b.clicked.connect(self.sign)

        self.broadcast_button = b = QPushButton(_("Broadcast"))
        b.clicked.connect(self.do_broadcast)

        self.save_button = b = QPushButton(_("Save"))
        b.clicked.connect(self.save)

        self.cancel_button = b = QPushButton(_("Close"))
        b.clicked.connect(self.close)
        b.setDefault(True)

        self.export_actions_menu = export_actions_menu = QMenu()
        self.add_export_actions_to_menu(export_actions_menu)
        export_actions_menu.addSeparator()
        export_submenu = export_actions_menu.addMenu(
            _("For CoinJoin; strip privates"))
        self.add_export_actions_to_menu(export_submenu,
                                        gettx=self._gettx_for_coinjoin)
        self.psbt_only_widgets.append(export_submenu)
        export_submenu = export_actions_menu.addMenu(
            _("For hardware device; include xpubs"))
        self.add_export_actions_to_menu(export_submenu,
                                        gettx=self._gettx_for_hardware_device)
        self.psbt_only_widgets.append(export_submenu)

        self.export_actions_button = QToolButton()
        self.export_actions_button.setObjectName("blue_toolbutton")
        self.export_actions_button.setText(_("Export"))
        self.export_actions_button.setMenu(export_actions_menu)
        self.export_actions_button.setPopupMode(QToolButton.InstantPopup)

        self.finalize_button = QPushButton(_('Finalize'))
        self.finalize_button.clicked.connect(self.on_finalize)

        partial_tx_actions_menu = QMenu()
        ptx_merge_sigs_action = QAction(_("Merge signatures from"), self)
        ptx_merge_sigs_action.triggered.connect(self.merge_sigs)
        partial_tx_actions_menu.addAction(ptx_merge_sigs_action)
        self.partial_tx_actions_button = QToolButton()
        self.partial_tx_actions_button.setObjectName("blue_toolbutton")
        self.partial_tx_actions_button.setText(_("Combine"))
        self.partial_tx_actions_button.setMenu(partial_tx_actions_menu)
        self.partial_tx_actions_button.setPopupMode(QToolButton.InstantPopup)
        self.psbt_only_widgets.append(self.partial_tx_actions_button)

        # Action buttons
        self.buttons = [
            self.partial_tx_actions_button, self.sign_button,
            self.broadcast_button, self.cancel_button
        ]
        # Transaction sharing buttons
        self.sharing_buttons = [
            self.finalize_button, self.export_actions_button, self.save_button
        ]
        run_hook('transaction_dialog', self)
        if not self.finalized:
            self.create_fee_controls()
            vbox.addWidget(self.feecontrol_fields)
        self.hbox = hbox = QHBoxLayout()
        hbox.addLayout(Buttons(*self.sharing_buttons))
        hbox.addStretch(1)
        hbox.addLayout(Buttons(*self.buttons))
        vbox.addLayout(hbox)
        self.set_buttons_visibility()

        dialogs.append(self)
コード例 #17
0
    def update(self):
        if not self.finalized:
            self.update_fee_fields()
            self.finalize_button.setEnabled(self.can_finalize())
        if self.tx is None:
            return
        self.update_io()
        desc = self.desc
        base_unit = self.main_window.base_unit()
        format_amount = self.main_window.format_amount
        tx_details = self.wallet.get_tx_info(self.tx)
        tx_mined_status = tx_details.tx_mined_status
        exp_n = tx_details.mempool_depth_bytes
        amount, fee = tx_details.amount, tx_details.fee
        size = self.tx.estimated_size()
        txid = self.tx.txid()
        self.broadcast_button.setEnabled(tx_details.can_broadcast)
        can_sign = not self.tx.is_complete() and \
            (self.wallet.can_sign(self.tx) or bool(self.external_keypairs))
        self.sign_button.setEnabled(can_sign)
        if self.finalized and tx_details.txid:
            self.tx_hash_e.setText(tx_details.txid)
        else:
            # note: when not finalized, locktime changes do not trigger
            #       a make_tx, so the txid is unreliable, hence:
            self.tx_hash_e.setText(_('Unknown'))
        if not desc:
            self.tx_desc.hide()
        else:
            self.tx_desc.setText(_("Description") + ': ' + desc)
            self.tx_desc.show()
        self.status_label.setText(_('Status:') + ' ' + tx_details.status)

        islock = tx_details.islock
        timestamp = tx_mined_status.timestamp
        if not timestamp and islock:
            timestamp = islock
        if timestamp:
            dttm = datetime.datetime.fromtimestamp(timestamp)
            time_str = dttm.isoformat(' ')[:-3]
            self.date_label.setText(_("Date: {}").format(time_str))
            self.date_label.show()
        elif exp_n is not None:
            text = '%.2f MB'%(exp_n/1000000)
            self.date_label.setText(_('Position in mempool: {} from tip').format(text))
            self.date_label.show()
        else:
            self.date_label.hide()
        if self.tx.locktime <= NLOCKTIME_BLOCKHEIGHT_MAX:
            locktime_final_str = f"LockTime: {self.tx.locktime} (height)"
        else:
            locktime_final_str = f"LockTime: {self.tx.locktime} ({datetime.datetime.fromtimestamp(self.tx.locktime)})"
        self.locktime_final_label.setText(locktime_final_str)
        if self.locktime_e.get_locktime() is None:
            self.locktime_e.set_locktime(self.tx.locktime)

        if tx_mined_status.header_hash:
            self.block_hash_label.setText(_("Included in block: {}")
                                          .format(tx_mined_status.header_hash))
            self.block_height_label.setText(_("At block height: {}")
                                            .format(tx_mined_status.height))
        else:
            self.block_hash_label.hide()
            self.block_height_label.hide()
        if amount is None:
            amount_str = _("Transaction unrelated to your wallet")
        elif amount is None:
            amount_str = ''
        elif amount > 0:
            amount_str = _("Amount received:") + ' %s'% format_amount(amount) + ' ' + base_unit
        else:
            amount_str = _("Amount sent:") + ' %s'% format_amount(-amount) + ' ' + base_unit
        if amount_str:
            self.amount_label.setText(amount_str)
        else:
            self.amount_label.hide()
        size_str = _("Size:") + ' %d bytes'% size
        fee_str = _("Fee") + ': %s' % (format_amount(fee) + ' ' + base_unit if fee is not None else _('unknown'))
        if fee is not None:
            fee_rate = fee/size*1000
            fee_str += '  ( %s ) ' % self.main_window.format_fee_rate(fee_rate)
            feerate_warning = simple_config.FEERATE_WARNING_HIGH_FEE
            if fee_rate > feerate_warning:
                fee_str += ' - ' + _('Warning') + ': ' + _("high fee") + '!'
        if isinstance(self.tx, PartialTransaction):
            risk_of_burning_coins = (can_sign and fee is not None
                                     and self.wallet.get_warning_for_risk_of_burning_coins_as_fees(self.tx))
            self.fee_warning_icon.setToolTip(str(risk_of_burning_coins))
            self.fee_warning_icon.setVisible(bool(risk_of_burning_coins))
        self.fee_label.setText(fee_str)
        self.size_label.setText(size_str)
        show_psbt_only_widgets = self.finalized and isinstance(self.tx, PartialTransaction)
        for widget in self.psbt_only_widgets:
            if isinstance(widget, QMenu):
                widget.menuAction().setVisible(show_psbt_only_widgets)
            else:
                widget.setVisible(show_psbt_only_widgets)

        self.save_button.setEnabled(tx_details.can_save_as_local)
        if tx_details.can_save_as_local:
            self.save_button.setToolTip(_("Save transaction offline"))
        else:
            self.save_button.setToolTip(_("Transaction already saved or not yet signed."))

        if self.tx.tx_type == 0:
            txid = self.tx.txid()
            tx_type, completed = self.wallet.db.get_ps_tx(txid)
        else:
            tx_type = self.tx.tx_type
            if tx_type:
                extra_payload = self.tx.extra_payload
                self.extra_pld.set_extra_data(tx_type, extra_payload)
                self.extra_pld_lb.show()
                self.extra_pld.show()
            else:
                self.extra_pld_lb.hide()
                self.extra_pld.hide()
        tx_type_name = '%s: %s, ' % (_('Type'), SPEC_TX_NAMES[tx_type])
        self.txid_lb.setText(tx_type_name + _('Transaction ID:'))

        run_hook('transaction_dialog_update', self)
コード例 #18
0
    def create_menu(self, position):
        from electrum_firo.wallet import Multisig_Wallet
        is_multisig = isinstance(self.wallet, Multisig_Wallet)
        can_delete = self.wallet.can_delete_address()
        selected = self.selectionModel().selectedRows()
        if not selected:
            return
        multi_select = len(selected) > 1
        addr_items = []
        for idx in selected:
            if not idx.isValid():
                return
            addr_items.append(idx.internalPointer())
        addrs = [addr_item['addr'] for addr_item in addr_items]
        menu = QMenu()
        if not multi_select:
            idx = self.indexAt(position)
            if not idx.isValid():
                return
            item = addr_items[0]
            if not item:
                return
            addr = item['addr']
            is_ps = item['is_ps']
            is_ps_ks = item['is_ps_ks']

            hd = self.am.headerData
            addr_title = hd(AddrColumns.LABEL, None, Qt.DisplayRole)
            label_idx = idx.sibling(idx.row(), AddrColumns.LABEL)

            self.add_copy_menu(menu, idx)
            menu.addAction(_('Details'),
                           lambda: self.parent.show_address(addr))

            persistent = QPersistentModelIndex(label_idx)
            menu.addAction(_("Edit {}").format(addr_title),
                           lambda p=persistent: self.edit(QModelIndex(p)))

            #if not is_ps and not is_ps_ks:
            #    menu.addAction(_("Request payment"),
            #                   lambda: self.parent.receive_at(addr))
            if self.wallet.can_export() or self.wallet.psman.is_ps_ks(addr):
                menu.addAction(_("Private key"),
                               lambda: self.parent.show_private_key(addr))
            if not is_multisig and not self.wallet.is_watching_only():
                menu.addAction(_("Sign/verify message"),
                               lambda: self.parent.sign_verify_message(addr))
                menu.addAction(_("Encrypt/decrypt message"),
                               lambda: self.parent.encrypt_message(addr))
            if can_delete:
                menu.addAction(_("Remove from wallet"),
                               lambda: self.parent.remove_address(addr))
            addr_URL = block_explorer_URL(self.config, 'addr', addr)
            if addr_URL:
                menu.addAction(_("View on block explorer"),
                               lambda: webopen(addr_URL))

            if not is_ps:

                def set_frozen_state(addrs, state):
                    self.parent.set_frozen_state_of_addresses(addrs, state)

                if not self.wallet.is_frozen_address(addr):
                    menu.addAction(_("Freeze"),
                                   lambda: set_frozen_state([addr], True))
                else:
                    menu.addAction(_("Unfreeze"),
                                   lambda: set_frozen_state([addr], False))

        coins = self.wallet.get_spendable_coins(addrs)
        if coins:
            menu.addAction(_("Spend from"),
                           lambda: self.parent.utxo_list.set_spend_list(coins))

        run_hook('receive_menu', menu, addrs, self.wallet)
        menu.exec_(self.viewport().mapToGlobal(position))
コード例 #19
0
 def on_cb_active(self, is_checked):
     if self.active != is_checked:
         self.app.plugins.toggle(self.name)
         self.update()
         run_hook('init_kivy', self.app)