def change_homescreen(self, homescreen): self.msg = _("Confirm on your {} device to change your home screen") self.apply_settings(homescreen=homescreen)
def __init__(self, tx, parent, desc, prompt_if_unsaved): '''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) # Take a copy; it might get updated in the main window by # e.g. the FX plugin. If this happens during or after a long # sign operation the signatures are lost. self.tx = copy.deepcopy(tx) try: self.tx.deserialize() except BaseException as e: raise SerializationError(e) self.main_window = parent self.wallet = parent.wallet self.prompt_if_unsaved = prompt_if_unsaved self.saved = False self.desc = desc self.setMinimumWidth(750) self.setWindowTitle(_("Transaction")) vbox = QVBoxLayout() self.setLayout(vbox) vbox.addWidget(QLabel(_("Transaction ID:"))) self.tx_hash_e = ButtonsLineEdit() qr_show = lambda: parent.show_qrcode(str(self.tx_hash_e.text()), 'Transaction ID', parent=self) self.tx_hash_e.addButton(":icons/qrcode.png", qr_show, _("Show as QR code")) self.tx_hash_e.setReadOnly(True) vbox.addWidget(self.tx_hash_e) self.tx_desc = QLabel() vbox.addWidget(self.tx_desc) self.status_label = QLabel() vbox.addWidget(self.status_label) self.date_label = QLabel() vbox.addWidget(self.date_label) self.amount_label = QLabel() vbox.addWidget(self.amount_label) self.size_label = QLabel() vbox.addWidget(self.size_label) self.fee_label = QLabel() vbox.addWidget(self.fee_label) self.add_io(vbox) vbox.addStretch(1) 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 = QPushButton(_("Save")) save_button_disabled = not tx.is_complete() self.save_button.setDisabled(save_button_disabled) if save_button_disabled: self.save_button.setToolTip(_("Please sign this transaction in order to save it")) else: self.save_button.setToolTip("") self.save_button.clicked.connect(self.save) self.export_button = b = QPushButton(_("Export")) b.clicked.connect(self.export) self.cancel_button = b = QPushButton(_("Close")) b.clicked.connect(self.close) b.setDefault(True) self.qr_button = b = QPushButton() b.setIcon(QIcon(":icons/qrcode.png")) b.clicked.connect(self.show_qr) self.copy_button = CopyButton(lambda: str(self.tx), parent.app) # Action buttons self.buttons = [self.sign_button, self.broadcast_button, self.save_button, self.cancel_button] # Transaction sharing buttons self.sharing_buttons = [self.copy_button, self.qr_button, self.export_button] run_hook('transaction_dialog', self) hbox = QHBoxLayout() hbox.addLayout(Buttons(*self.sharing_buttons)) hbox.addStretch(1) hbox.addLayout(Buttons(*self.buttons)) vbox.addLayout(hbox) self.update()
def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> QVariant: assert index.isValid() col = index.column() coin_item = index.internalPointer() address = coin_item['address'] is_frozen_addr = coin_item['is_frozen_addr'] is_frozen_coin = coin_item['is_frozen_coin'] height = coin_item['height'] time_str = '' if self.view.config.get('show_utxo_time', False): prevout_timestamp = coin_item['prevout_timestamp'] time_str = (format_time(prevout_timestamp) if prevout_timestamp < math.inf else _('unknown')) outpoint = coin_item['outpoint'] out_short = coin_item['out_short'] label = coin_item['label'] balance = coin_item['balance'] if (role == self.view.ROLE_CLIPBOARD_DATA and col == UTXOColumns.OUTPOINT): return QVariant(outpoint) elif role == Qt.ToolTipRole: if col == UTXOColumns.ADDRESS and is_frozen_addr: return QVariant(_('Address is frozen')) elif col == UTXOColumns.OUTPOINT and is_frozen_coin: return QVariant(f'{outpoint}\n{_("Coin is frozen")}') elif outpoint in (self.view._spend_set or set()): if col == UTXOColumns.OUTPOINT: return QVariant(f'{outpoint}\n{SELECTED_TO_SPEND_TOOLTIP}') else: return QVariant(SELECTED_TO_SPEND_TOOLTIP) elif col == UTXOColumns.OUTPOINT: return QVariant(outpoint) elif role not in (Qt.DisplayRole, Qt.EditRole): if role == Qt.TextAlignmentRole: if col in [ UTXOColumns.DATE, UTXOColumns.AMOUNT, UTXOColumns.HEIGHT ]: return QVariant(Qt.AlignRight | Qt.AlignVCenter) else: return QVariant(Qt.AlignVCenter) elif role == Qt.FontRole: return QVariant(QFont(MONOSPACE_FONT)) elif role == Qt.BackgroundRole: if col == UTXOColumns.ADDRESS and is_frozen_addr: return QVariant(ColorScheme.BLUE.as_color(True)) elif col == UTXOColumns.OUTPOINT and is_frozen_coin: return QVariant(ColorScheme.BLUE.as_color(True)) elif outpoint in (self.view._spend_set or set()): return QVariant(ColorScheme.GREEN.as_color(True)) elif col == UTXOColumns.DATE: return QVariant(time_str) elif col == UTXOColumns.OUTPOINT: return QVariant(out_short) elif col == UTXOColumns.ADDRESS: return QVariant(address) elif col == UTXOColumns.LABEL: return QVariant(label) elif col == UTXOColumns.AMOUNT: return QVariant(balance) elif col == UTXOColumns.HEIGHT: return QVariant(height) else: return QVariant()
def settings_widget(self, window: WindowModalDialog): return EnterButton(_('Settings'), partial(self.settings_dialog, window))
def done_processing_error(self, dialog, exc_info): self.logger.error("Error synchronising labels", exc_info=exc_info) dialog.show_error(_("Error synchronising labels") + f':\n{repr(exc_info[1])}')
import threading from PyQt5.Qt import Qt from PyQt5.Qt import QGridLayout, QInputDialog, QPushButton from PyQt5.Qt import QVBoxLayout, QLabel from electrum_zcash_gui.qt.util import * from .trezor import TIM_NEW, TIM_RECOVER, TIM_MNEMONIC from ..hw_wallet.qt import QtHandlerBase, QtPluginBase from electrum_zcash.i18n import _ from electrum_zcash.plugins import hook, DeviceMgr from electrum_zcash.util import PrintError, UserCancelled, bh2u from electrum_zcash.wallet import Wallet, Standard_Wallet PASSPHRASE_HELP_SHORT = _( "Passphrases allow you to access new wallets, each " "hidden behind a particular case-sensitive passphrase.") PASSPHRASE_HELP = PASSPHRASE_HELP_SHORT + " " + _( "You need to create a separate Electrum-Spacecoin wallet for each passphrase " "you use as they each generate different addresses. Changing " "your passphrase does not lose other wallets, each is still " "accessible behind its own passphrase.") RECOMMEND_PIN = _( "You should enable PIN protection. Your PIN is the only protection " "for your Spacecoin coins if your device is lost or stolen.") PASSPHRASE_NOT_PIN = _( "If you forget a passphrase you will be unable to access any " "Spacecoin coins in the wallet behind it. A passphrase is not a PIN. " "Only change this if you are sure you understand it.") CHARACTER_RECOVERY = ( "Use the recovery cipher shown on your device to input your seed words. "
def __init__(self, window, plugin, keystore, device_id): title = _("{} Settings").format(plugin.device) super(SettingsDialog, self).__init__(window, title) self.setMaximumWidth(540) devmgr = plugin.device_manager() config = devmgr.config handler = keystore.handler thread = keystore.thread hs_rows, hs_cols = (64, 128) def invoke_client(method, *args, **kw_args): unpair_after = kw_args.pop('unpair_after', False) def task(): client = devmgr.client_by_id(device_id) if not client: raise RuntimeError("Device not connected") if method: getattr(client, method)(*args, **kw_args) if unpair_after: devmgr.unpair_id(device_id) return client.features thread.add(task, on_success=update) def update(features): self.features = features set_label_enabled() if features.bootloader_hash: bl_hash = bh2u(features.bootloader_hash) bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]]) else: bl_hash = "N/A" noyes = [_("No"), _("Yes")] endis = [_("Enable Passphrases"), _("Disable Passphrases")] disen = [_("Disabled"), _("Enabled")] setchange = [_("Set a PIN"), _("Change PIN")] version = "%d.%d.%d" % (features.major_version, features.minor_version, features.patch_version) coins = ", ".join(coin.coin_name for coin in features.coins) device_label.setText(features.label) pin_set_label.setText(noyes[features.pin_protection]) passphrases_label.setText(disen[features.passphrase_protection]) bl_hash_label.setText(bl_hash) label_edit.setText(features.label) device_id_label.setText(features.device_id) initialized_label.setText(noyes[features.initialized]) version_label.setText(version) coins_label.setText(coins) clear_pin_button.setVisible(features.pin_protection) clear_pin_warning.setVisible(features.pin_protection) pin_button.setText(setchange[features.pin_protection]) pin_msg.setVisible(not features.pin_protection) passphrase_button.setText(endis[features.passphrase_protection]) language_label.setText(features.language) def set_label_enabled(): label_apply.setEnabled(label_edit.text() != self.features.label) def rename(): invoke_client('change_label', label_edit.text()) def toggle_passphrase(): title = _("Confirm Toggle Passphrase Protection") currently_enabled = self.features.passphrase_protection if currently_enabled: msg = _( "After disabling passphrases, you can only pair this " "Electrum-Spacecoin wallet if it had an empty passphrase. " "If its passphrase was not empty, you will need to " "create a new wallet with the install wizard. You " "can use this wallet again at any time by re-enabling " "passphrases and entering its passphrase.") else: msg = _( "Your current Electrum-Spacecoin wallet can only be used with " "an empty passphrase. You must create a separate " "wallet with the install wizard for other passphrases " "as each one generates a new set of addresses.") msg += "\n\n" + _("Are you sure you want to proceed?") if not self.question(msg, title=title): return invoke_client('toggle_passphrase', unpair_after=currently_enabled) def change_homescreen(): dialog = QFileDialog(self, _("Choose Homescreen")) filename, __ = dialog.getOpenFileName() if filename.endswith('.toif'): img = open(filename, 'rb').read() if img[:8] != b'TOIf\x90\x00\x90\x00': raise Exception( 'File is not a TOIF file with size of 144x144') else: from PIL import Image # FIXME im = Image.open(filename) if im.size != (128, 64): raise Exception('Image must be 128 x 64 pixels') im = im.convert('1') pix = im.load() img = bytearray(1024) for j in range(64): for i in range(128): if pix[i, j]: o = (i + j * 128) img[o // 8] |= (1 << (7 - o % 8)) img = bytes(img) invoke_client('change_homescreen', img) def clear_homescreen(): invoke_client('change_homescreen', b'\x00') def set_pin(): invoke_client('set_pin', remove=False) def clear_pin(): invoke_client('set_pin', remove=True) def wipe_device(): wallet = window.wallet if wallet and sum(wallet.get_balance()): title = _("Confirm Device Wipe") msg = _("Are you SURE you want to wipe the device?\n" "Your wallet still has Spacecoin coins in it!") if not self.question( msg, title=title, icon=QMessageBox.Critical): return invoke_client('wipe_device', unpair_after=True) def slider_moved(): mins = timeout_slider.sliderPosition() timeout_minutes.setText(_("%2d minutes") % mins) def slider_released(): config.set_session_timeout(timeout_slider.sliderPosition() * 60) # Information tab info_tab = QWidget() info_layout = QVBoxLayout(info_tab) info_glayout = QGridLayout() info_glayout.setColumnStretch(2, 1) device_label = QLabel() pin_set_label = QLabel() passphrases_label = QLabel() version_label = QLabel() device_id_label = QLabel() bl_hash_label = QLabel() bl_hash_label.setWordWrap(True) coins_label = QLabel() coins_label.setWordWrap(True) language_label = QLabel() initialized_label = QLabel() rows = [ (_("Device Label"), device_label), (_("PIN set"), pin_set_label), (_("Passphrases"), passphrases_label), (_("Firmware Version"), version_label), (_("Device ID"), device_id_label), (_("Bootloader Hash"), bl_hash_label), (_("Supported Coins"), coins_label), (_("Language"), language_label), (_("Initialized"), initialized_label), ] for row_num, (label, widget) in enumerate(rows): info_glayout.addWidget(QLabel(label), row_num, 0) info_glayout.addWidget(widget, row_num, 1) info_layout.addLayout(info_glayout) # Settings tab settings_tab = QWidget() settings_layout = QVBoxLayout(settings_tab) settings_glayout = QGridLayout() # Settings tab - Label label_msg = QLabel( _("Name this {}. If you have multiple devices " "their labels help distinguish them.").format(plugin.device)) label_msg.setWordWrap(True) label_label = QLabel(_("Device Label")) label_edit = QLineEdit() label_edit.setMinimumWidth(150) label_edit.setMaxLength(plugin.MAX_LABEL_LEN) label_apply = QPushButton(_("Apply")) label_apply.clicked.connect(rename) label_edit.textChanged.connect(set_label_enabled) settings_glayout.addWidget(label_label, 0, 0) settings_glayout.addWidget(label_edit, 0, 1, 1, 2) settings_glayout.addWidget(label_apply, 0, 3) settings_glayout.addWidget(label_msg, 1, 1, 1, -1) # Settings tab - PIN pin_label = QLabel(_("PIN Protection")) pin_button = QPushButton() pin_button.clicked.connect(set_pin) settings_glayout.addWidget(pin_label, 2, 0) settings_glayout.addWidget(pin_button, 2, 1) pin_msg = QLabel( _("PIN protection is strongly recommended. " "A PIN is your only protection against someone " "stealing your Spacecoin coins if they obtain physical " "access to your {}.").format(plugin.device)) pin_msg.setWordWrap(True) pin_msg.setStyleSheet("color: red") settings_glayout.addWidget(pin_msg, 3, 1, 1, -1) # Settings tab - Homescreen if plugin.device != 'KeepKey': # Not yet supported by KK firmware homescreen_layout = QHBoxLayout() homescreen_label = QLabel(_("Homescreen")) homescreen_change_button = QPushButton(_("Change...")) homescreen_clear_button = QPushButton(_("Reset")) homescreen_change_button.clicked.connect(change_homescreen) homescreen_clear_button.clicked.connect(clear_homescreen) homescreen_msg = QLabel( _("You can set the homescreen on your " "device to personalize it. You must " "choose a {} x {} monochrome black and " "white image.").format(hs_rows, hs_cols)) homescreen_msg.setWordWrap(True) settings_glayout.addWidget(homescreen_label, 4, 0) settings_glayout.addWidget(homescreen_change_button, 4, 1) settings_glayout.addWidget(homescreen_clear_button, 4, 2) settings_glayout.addWidget(homescreen_msg, 5, 1, 1, -1) # Settings tab - Session Timeout timeout_label = QLabel(_("Session Timeout")) timeout_minutes = QLabel() timeout_slider = QSlider(Qt.Horizontal) timeout_slider.setRange(1, 60) timeout_slider.setSingleStep(1) timeout_slider.setTickInterval(5) timeout_slider.setTickPosition(QSlider.TicksBelow) timeout_slider.setTracking(True) timeout_msg = QLabel( _("Clear the session after the specified period " "of inactivity. Once a session has timed out, " "your PIN and passphrase (if enabled) must be " "re-entered to use the device.")) timeout_msg.setWordWrap(True) timeout_slider.setSliderPosition(config.get_session_timeout() // 60) slider_moved() timeout_slider.valueChanged.connect(slider_moved) timeout_slider.sliderReleased.connect(slider_released) settings_glayout.addWidget(timeout_label, 6, 0) settings_glayout.addWidget(timeout_slider, 6, 1, 1, 3) settings_glayout.addWidget(timeout_minutes, 6, 4) settings_glayout.addWidget(timeout_msg, 7, 1, 1, -1) settings_layout.addLayout(settings_glayout) settings_layout.addStretch(1) # Advanced tab advanced_tab = QWidget() advanced_layout = QVBoxLayout(advanced_tab) advanced_glayout = QGridLayout() # Advanced tab - clear PIN clear_pin_button = QPushButton(_("Disable PIN")) clear_pin_button.clicked.connect(clear_pin) clear_pin_warning = QLabel( _("If you disable your PIN, anyone with physical access to your " "{} device can spend your Spacecoin coins.").format( plugin.device)) clear_pin_warning.setWordWrap(True) clear_pin_warning.setStyleSheet("color: red") advanced_glayout.addWidget(clear_pin_button, 0, 2) advanced_glayout.addWidget(clear_pin_warning, 1, 0, 1, 5) # Advanced tab - toggle passphrase protection passphrase_button = QPushButton() passphrase_button.clicked.connect(toggle_passphrase) passphrase_msg = WWLabel(PASSPHRASE_HELP) passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN) passphrase_warning.setStyleSheet("color: red") advanced_glayout.addWidget(passphrase_button, 3, 2) advanced_glayout.addWidget(passphrase_msg, 4, 0, 1, 5) advanced_glayout.addWidget(passphrase_warning, 5, 0, 1, 5) # Advanced tab - wipe device wipe_device_button = QPushButton(_("Wipe Device")) wipe_device_button.clicked.connect(wipe_device) wipe_device_msg = QLabel( _("Wipe the device, removing all data from it. The firmware " "is left unchanged.")) wipe_device_msg.setWordWrap(True) wipe_device_warning = QLabel( _("Only wipe a device if you have the recovery seed written down " "and the device wallet(s) are empty, otherwise the Spacecoin coins " "will be lost forever.")) wipe_device_warning.setWordWrap(True) wipe_device_warning.setStyleSheet("color: red") advanced_glayout.addWidget(wipe_device_button, 6, 2) advanced_glayout.addWidget(wipe_device_msg, 7, 0, 1, 5) advanced_glayout.addWidget(wipe_device_warning, 8, 0, 1, 5) advanced_layout.addLayout(advanced_glayout) advanced_layout.addStretch(1) tabs = QTabWidget(self) tabs.addTab(info_tab, _("Information")) tabs.addTab(settings_tab, _("Settings")) tabs.addTab(advanced_tab, _("Advanced")) dialog_vbox = QVBoxLayout(self) dialog_vbox.addWidget(tabs) dialog_vbox.addLayout(Buttons(CloseButton(self))) # Update information invoke_client(None)
def decrypt_message(self, sequence, message, password): raise RuntimeError( _('Encryption and decryption are not implemented by {}').format( self.device))
from btchip.btchipComm import HIDDongleHIDAPI, DongleWait from btchip.btchip import btchip from btchip.btchipUtils import compress_public_key, format_transaction, get_regular_input_script, get_p2sh_input_script from btchip.btchipFirmwareWizard import checkFirmware, updateFirmware from btchip.btchipException import BTChipException from .btchip_zcash import btchip_zcash, zcashTransaction btchip.setAlternateCoinVersions = setAlternateCoinVersions BTCHIP = True BTCHIP_DEBUG = False except ImportError as e: if not (isinstance(e, ModuleNotFoundError) and e.name == 'btchip'): _logger.exception('error importing ledger plugin deps') BTCHIP = False btchip = object # to test whithout btchip modules (see btchip_zcash class) MSG_NEEDS_FW_UPDATE_GENERIC = _('Firmware version too old. Please update at') + \ ' https://www.ledgerwallet.com' MSG_NEEDS_FW_UPDATE_OVERWINTER = (_('Firmware version too old for ' 'Overwinter/Sapling support. ' 'Please update at') + ' https://www.ledgerwallet.com') MULTI_OUTPUT_SUPPORT = '1.1.4' ALTERNATIVE_COIN_VERSION = '1.0.1' OVERWINTER_SUPPORT = '1.3.3' def test_pin_unlocked(func): """Function decorator to test the Ledger for being unlocked, and if not, raise a human-readable exception. """ def catch_exception(self, *args, **kwargs):
def show_summary(self): fx = self.parent.fx show_fiat = fx and fx.is_enabled() and fx.get_history_config() if not show_fiat: self.parent.show_message( _("Enable fiat exchange rate with history.")) return h = self.parent.wallet.get_detailed_history( from_timestamp=time.mktime(self.start_date.timetuple()) if self.start_date else None, to_timestamp=time.mktime(self.end_date.timetuple()) if self.end_date else None, fx=fx) summary = h['summary'] if not summary: self.parent.show_message(_("Nothing to summarize.")) return start = summary['begin'] end = summary['end'] flow = summary['flow'] start_date = start.get('date') end_date = end.get('date') format_amount = lambda x: self.parent.format_amount( x.value) + ' ' + self.parent.base_unit() format_fiat = lambda x: str(x) + ' ' + self.parent.fx.ccy d = WindowModalDialog(self, _("Summary")) d.setMinimumSize(600, 150) vbox = QVBoxLayout() msg = messages.to_rtf(messages.MSG_CAPITAL_GAINS) vbox.addWidget(WWLabel(msg)) grid = QGridLayout() grid.addWidget(QLabel(_("Begin")), 0, 1) grid.addWidget(QLabel(_("End")), 0, 2) # grid.addWidget(QLabel(_("Date")), 1, 0) grid.addWidget(QLabel(self.format_date(start_date)), 1, 1) grid.addWidget(QLabel(self.format_date(end_date)), 1, 2) # grid.addWidget(QLabel(_("Zcash balance")), 2, 0) grid.addWidget(QLabel(format_amount(start['BTC_balance'])), 2, 1) grid.addWidget(QLabel(format_amount(end['BTC_balance'])), 2, 2) # grid.addWidget(QLabel(_("Zcash Fiat price")), 3, 0) grid.addWidget(QLabel(format_fiat(start.get('BTC_fiat_price'))), 3, 1) grid.addWidget(QLabel(format_fiat(end.get('BTC_fiat_price'))), 3, 2) # grid.addWidget(QLabel(_("Fiat balance")), 4, 0) grid.addWidget(QLabel(format_fiat(start.get('fiat_balance'))), 4, 1) grid.addWidget(QLabel(format_fiat(end.get('fiat_balance'))), 4, 2) # grid.addWidget(QLabel(_("Acquisition price")), 5, 0) grid.addWidget(QLabel(format_fiat(start.get('acquisition_price', ''))), 5, 1) grid.addWidget(QLabel(format_fiat(end.get('acquisition_price', ''))), 5, 2) # grid.addWidget(QLabel(_("Unrealized capital gains")), 6, 0) grid.addWidget(QLabel(format_fiat(start.get('unrealized_gains', ''))), 6, 1) grid.addWidget(QLabel(format_fiat(end.get('unrealized_gains', ''))), 6, 2) # grid2 = QGridLayout() grid2.addWidget(QLabel(_("Zcash incoming")), 0, 0) grid2.addWidget(QLabel(format_amount(flow['BTC_incoming'])), 0, 1) grid2.addWidget(QLabel(_("Fiat incoming")), 1, 0) grid2.addWidget(QLabel(format_fiat(flow.get('fiat_incoming'))), 1, 1) grid2.addWidget(QLabel(_("Zcash outgoing")), 2, 0) grid2.addWidget(QLabel(format_amount(flow['BTC_outgoing'])), 2, 1) grid2.addWidget(QLabel(_("Fiat outgoing")), 3, 0) grid2.addWidget(QLabel(format_fiat(flow.get('fiat_outgoing'))), 3, 1) # grid2.addWidget(QLabel(_("Realized capital gains")), 4, 0) grid2.addWidget( QLabel(format_fiat(flow.get('realized_capital_gains'))), 4, 1) vbox.addLayout(grid) vbox.addWidget(QLabel(_('Cash flow'))) vbox.addLayout(grid2) vbox.addLayout(Buttons(CloseButton(d))) d.setLayout(vbox) d.exec_()
def create_menu(self, position: QPoint): idx: QModelIndex = self.indexAt(position) if not idx.isValid(): # can happen e.g. before list is populated for the first time return tx_item = idx.internalPointer() tx_hash = tx_item['txid'] group_txid = tx_item.get('group_txid') is_parent = ('group_label' in tx_item) if is_parent and tx_hash in self.hm.expanded_groups: expanded = True else: expanded = False tx = self.wallet.db.get_transaction(tx_hash) if not tx: return tx_URL = block_explorer_URL(self.config, 'tx', tx_hash) tx_details = self.wallet.get_tx_info(tx) menu = QMenu() if group_txid: collapse_m = lambda: self.collapse_tx_group(group_txid) menu.addAction(_("Collapse Tx Group"), collapse_m) if is_parent: if expanded: collapse_m = lambda: self.collapse_tx_group(tx_hash) menu.addAction(_("Collapse Tx Group"), collapse_m) else: expand_m = lambda: self.expand_tx_group(tx_hash) menu.addAction(_("Expand Tx Group"), expand_m) if tx_details.can_remove and (not is_parent or expanded): menu.addAction(_("Remove"), lambda: self.remove_local_tx(tx_hash)) cc = self.add_copy_menu(menu, idx) cc.addAction( _("Transaction ID"), lambda: self.place_text_on_clipboard(tx_hash, title="TXID")) for c in self.editable_columns: if is_parent and not expanded: continue if self.isColumnHidden(c): continue label = self.hm.headerData(c, Qt.Horizontal, Qt.DisplayRole) # TODO use siblingAtColumn when min Qt version is >=5.11 persistent = QPersistentModelIndex(idx.sibling(idx.row(), c)) menu.addAction(_("Edit {}").format(label), lambda p=persistent: self.edit(QModelIndex(p))) menu.addAction(_("View Transaction"), lambda: self.show_transaction(tx_hash)) invoices = self.wallet.get_relevant_invoices_for_tx(tx) if len(invoices) == 1: menu.addAction( _("View invoice"), lambda inv=invoices[0]: self.parent.show_onchain_invoice(inv)) elif len(invoices) > 1: menu_invs = menu.addMenu(_("Related invoices")) for inv in invoices: menu_invs.addAction( _("View invoice"), lambda inv=inv: self.parent.show_onchain_invoice(inv)) if tx_URL: menu.addAction(_("View on block explorer"), lambda: webopen(tx_URL)) menu.exec_(self.viewport().mapToGlobal(position))
def format_date(self, d): return str(datetime.date(d.year, d.month, d.day)) if d else _('None')
def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> QVariant: assert index.isValid() col = index.column() tx_item = index.internalPointer() tx_hash = tx_item['txid'] conf = tx_item['confirmations'] is_parent = ('group_label' in tx_item) if is_parent and tx_hash in self.expanded_groups: expanded = True else: expanded = False if not is_parent: tx_group_icon = None elif not expanded: tx_group_icon = self.tx_group_expand_icn else: tx_group_icon = self.tx_group_collapse_icn try: status, status_str = self.tx_status_cache[tx_hash] except KeyError: tx_mined_info = self.tx_mined_info_from_tx_item(tx_item) status, status_str = self.parent.wallet.get_tx_status( tx_hash, tx_mined_info) if role not in (Qt.DisplayRole, Qt.EditRole): if col == HistoryColumns.TX_GROUP and role == Qt.DecorationRole: if tx_group_icon: return QVariant(tx_group_icon) if col == HistoryColumns.STATUS and role == Qt.DecorationRole: return QVariant(read_QIcon(TX_ICONS[status])) elif col == HistoryColumns.STATUS and role == Qt.ToolTipRole: if tx_item['height'] == TX_HEIGHT_LOCAL: msg = _( "This transaction is only available on your local machine.\n" "The currently connected server does not know about it.\n" "You can either broadcast it now, or simply remove it." ) return QVariant(msg) c = str(conf) + _(' confirmation' + ('s' if conf != 1 else '')) return QVariant(c) elif col not in [HistoryColumns.DESCRIPTION ] and role == Qt.TextAlignmentRole: return QVariant(int(Qt.AlignRight | Qt.AlignVCenter)) elif col != HistoryColumns.DESCRIPTION and role == Qt.FontRole: monospace_font = QFont(MONOSPACE_FONT) return QVariant(monospace_font) #elif col == HistoryColumns.DESCRIPTION and role == Qt.DecorationRole \ # and self.parent.wallet.invoices.paid.get(tx_hash): # return QVariant(read_QIcon("seal")) elif (col in (HistoryColumns.DESCRIPTION, HistoryColumns.AMOUNT) and role == Qt.ForegroundRole): if is_parent and not expanded: value = tx_item['group_value'].value else: value = tx_item['value'].value if value < 0: red_brush = QBrush(QColor("#BC1E1E")) return QVariant(red_brush) elif col == HistoryColumns.FIAT_VALUE and role == Qt.ForegroundRole \ and not tx_item.get('fiat_default') and tx_item.get('fiat_value') is not None: blue_brush = QBrush(QColor("#1E1EFF")) return QVariant(blue_brush) return QVariant() if col == HistoryColumns.STATUS: return QVariant(status_str) elif col == HistoryColumns.DESCRIPTION: if is_parent and not expanded: return QVariant(tx_item['group_label']) else: return QVariant(tx_item['label']) elif col == HistoryColumns.AMOUNT: if is_parent and not expanded: value = tx_item['group_value'].value else: value = tx_item['value'].value v_str = self.parent.format_amount(value, is_diff=True, whitespaces=True) return QVariant(v_str) elif col == HistoryColumns.BALANCE: if is_parent and not expanded: balance = tx_item['group_balance'].value else: balance = tx_item['balance'].value balance_str = self.parent.format_amount(balance, whitespaces=True) return QVariant(balance_str) elif col == HistoryColumns.FIAT_VALUE and 'fiat_value' in tx_item: if is_parent and not expanded: return value_str = self.parent.fx.format_fiat(tx_item['fiat_value'].value) return QVariant(value_str) elif col == HistoryColumns.FIAT_ACQ_PRICE and \ tx_item['value'].value < 0 and 'acquisition_price' in tx_item: if is_parent and not expanded: return # fixme: should use is_mine acq = tx_item['acquisition_price'].value return QVariant(self.parent.fx.format_fiat(acq)) elif col == HistoryColumns.FIAT_CAP_GAINS and 'capital_gain' in tx_item: if is_parent and not expanded: return cg = tx_item['capital_gain'].value return QVariant(self.parent.fx.format_fiat(cg)) elif col == HistoryColumns.TXID: return QVariant(tx_hash) return QVariant()
class GuiMixin(object): # Requires: self.proto, self.device messages = { 3: _("Confirm the transaction output on your {} device"), 4: _("Confirm internal entropy on your {} device to begin"), 5: _("Write down the seed word shown on your {}"), 6: _("Confirm on your {} that you want to wipe it clean"), 7: _("Confirm on your {} device the message to sign"), 8: _("Confirm the total amount spent and the transaction fee on your " "{} device"), 10: _("Confirm wallet address on your {} device"), 'default': _("Check your {} device to continue"), } def callback_Failure(self, msg): # BaseClient's unfortunate call() implementation forces us to # raise exceptions on failure in order to unwind the stack. # However, making the user acknowledge they cancelled # gets old very quickly, so we suppress those. The NotInitialized # one is misnamed and indicates a passphrase request was cancelled. if msg.code in (self.types.Failure_PinCancelled, self.types.Failure_ActionCancelled, self.types.Failure_NotInitialized): raise UserCancelled() raise RuntimeError(msg.message) def callback_ButtonRequest(self, msg): message = self.msg if not message: message = self.messages.get(msg.code, self.messages['default']) self.handler.show_message(message.format(self.device), self.cancel) return self.proto.ButtonAck() def callback_PinMatrixRequest(self, msg): if msg.type == 2: msg = _("Enter a new PIN for your {}:") elif msg.type == 3: msg = (_("Re-enter the new PIN for your {}.\n\n" "NOTE: the positions of the numbers have changed!")) else: msg = _("Enter your current {} PIN:") pin = self.handler.get_pin(msg.format(self.device)) if len(pin) > 9: self.handler.show_error( _('The PIN cannot be longer than 9 characters.')) pin = '' # to cancel below if not pin: return self.proto.Cancel() return self.proto.PinMatrixAck(pin=pin) def callback_PassphraseRequest(self, req): if self.creating_wallet: msg = _("Enter a passphrase to generate this wallet. Each time " "you use this wallet your {} will prompt you for the " "passphrase. If you forget the passphrase you cannot " "access the Spacecoin coins in the wallet.").format( self.device) else: msg = _("Enter the passphrase to unlock this wallet:") passphrase = self.handler.get_passphrase(msg, self.creating_wallet) if passphrase is None: return self.proto.Cancel() passphrase = bip39_normalize_passphrase(passphrase) ack = self.proto.PassphraseAck(passphrase=passphrase) length = len(ack.passphrase) if length > 50: self.handler.show_error( _("Too long passphrase ({} > 50 chars).").format(length)) return self.proto.Cancel() return ack def callback_WordRequest(self, msg): self.step += 1 msg = _("Step {}/24. Enter seed word as explained on " "your {}:").format(self.step, self.device) word = self.handler.get_word(msg) # Unfortunately the device can't handle self.proto.Cancel() return self.proto.WordAck(word=word) def callback_CharacterRequest(self, msg): char_info = self.handler.get_char(msg) if not char_info: return self.proto.Cancel() return self.proto.CharacterAck(**char_info)
def on_m(m): m_label.setText(_('Require {0} signatures').format(m)) cw.set_m(m)
def decrypt_message(self, pubkey, message, password): raise UserFacingException( _('Encryption and decryption are currently not supported for {}'). format(self.device))
def on_n(n): n_label.setText(_('From {0} cosigners').format(n)) cw.set_n(n) m_edit.setMaximum(n)
def sign_transaction(self, tx, password): if tx.is_complete(): return inputs = [] inputsPaths = [] chipInputs = [] redeemScripts = [] changePath = "" output = None p2shTransaction = False pin = "" client_ledger = self.get_client( ) # prompt for the PIN before displaying the dialog if necessary client_electrum = self.get_client_electrum() assert client_electrum if tx.overwintered: if not client_electrum.supports_overwinter(): self.give_error(MSG_NEEDS_FW_UPDATE_OVERWINTER) # Fetch inputs of the transaction to sign for txin in tx.inputs(): if txin.is_coinbase_input(): self.give_error( "Coinbase not supported") # should never happen if txin.script_type in ['p2sh']: p2shTransaction = True my_pubkey, full_path = self.find_my_pubkey_in_txinout(txin) if not full_path: self.give_error("No matching pubkey for sign_transaction" ) # should never happen full_path = convert_bip32_intpath_to_strpath(full_path)[2:] redeemScript = Transaction.get_preimage_script(txin) txin_prev_tx = txin.utxo if txin_prev_tx is None: raise UserFacingException( _('Missing previous tx for legacy input.')) txin_prev_tx_raw = txin_prev_tx.serialize( ) if txin_prev_tx else None inputs.append([ txin_prev_tx_raw, txin.prevout.out_idx, redeemScript, txin.prevout.txid.hex(), my_pubkey, txin.nsequence, txin.value_sats() ]) inputsPaths.append(full_path) # Sanity check if p2shTransaction: for txin in tx.inputs(): if txin.script_type != 'p2sh': self.give_error( "P2SH / regular input mixed in same transaction not supported" ) # should never happen txOutput = var_int(len(tx.outputs())) for o in tx.outputs(): txOutput += int_to_hex(o.value, 8) script = o.scriptpubkey.hex() txOutput += var_int(len(script) // 2) txOutput += script txOutput = bfh(txOutput) if not client_electrum.supports_multi_output(): if len(tx.outputs()) > 2: self.give_error( "Transaction with more than 2 outputs not supported") for txout in tx.outputs(): if client_electrum.is_hw1( ) and txout.address and not is_b58_address(txout.address): self.give_error( _("This {} device can only send to base58 addresses."). format(self.device)) if not txout.address: if client_electrum.is_hw1(): self.give_error( _("Only address outputs are supported by {}").format( self.device)) # note: max_size based on https://github.com/LedgerHQ/ledger-app-btc/commit/3a78dee9c0484821df58975803e40d58fbfc2c38#diff-c61ccd96a6d8b54d48f54a3bc4dfa7e2R26 validate_op_return_output(txout, max_size=190) # Output "change" detection # - only one output and one change is authorized (for hw.1 and nano) # - at most one output can bypass confirmation (~change) (for all) if not p2shTransaction: has_change = False any_output_on_change_branch = is_any_tx_output_on_change_branch(tx) for txout in tx.outputs(): if txout.is_mine and len(tx.outputs()) > 1 \ and not has_change: # prioritise hiding outputs on the 'change' branch from user # because no more than one change address allowed if txout.is_change == any_output_on_change_branch: my_pubkey, changePath = self.find_my_pubkey_in_txinout( txout) assert changePath changePath = convert_bip32_intpath_to_strpath( changePath)[2:] has_change = True else: output = txout.address else: output = txout.address if not self.get_client_electrum().canAlternateCoinVersions: v, h = b58_address_to_hash160(output) if v == constants.net.ADDRTYPE_P2PKH: output = hash160_to_b58_address(h, 0) self.handler.show_message( _("Confirm Transaction on your Ledger device...")) try: # Get trusted inputs from the original transactions for utxo in inputs: sequence = int_to_hex(utxo[5], 4) if tx.overwintered: txtmp = zcashTransaction(bfh(utxo[0])) tmp = bfh(utxo[3])[::-1] tmp += bfh(int_to_hex(utxo[1], 4)) tmp += txtmp.outputs[utxo[1]].amount chipInputs.append({'value': tmp, 'sequence': sequence}) redeemScripts.append(bfh(utxo[2])) elif (not p2shTransaction ) or client_electrum.supports_multi_output(): txtmp = zcashTransaction(bfh(utxo[0])) trustedInput = client_ledger.getTrustedInput( txtmp, utxo[1]) trustedInput['sequence'] = sequence chipInputs.append(trustedInput) if p2shTransaction: redeemScripts.append(bfh(utxo[2])) else: redeemScripts.append(txtmp.outputs[utxo[1]].script) else: tmp = bfh(utxo[3])[::-1] tmp += bfh(int_to_hex(utxo[1], 4)) chipInputs.append({'value': tmp, 'sequence': sequence}) redeemScripts.append(bfh(utxo[2])) # Sign all inputs firstTransaction = True inputIndex = 0 rawTx = tx.serialize_to_network() client_ledger.enableAlternate2fa(False) if tx.overwintered: self.get_client().startUntrustedTransaction( True, inputIndex, chipInputs, redeemScripts[inputIndex], version=tx.version, overwintered=tx.overwintered) # we don't set meaningful outputAddress, amount and fees # as we only care about the alternateEncoding==True branch if tx.overwintered: inputSignature = client_ledger.untrustedHashSign( '', pin, lockTime=tx.locktime, overwintered=tx.overwintered) outputData = client_ledger.finalizeInput( b'', 0, 0, changePath, bfh(rawTx)) outputData['outputData'] = txOutput if outputData['confirmationNeeded']: outputData['address'] = output self.handler.finished() # do the authenticate dialog and get pin: pin = self.handler.get_auth(outputData, client=client_electrum) if not pin: raise UserWarning() self.handler.show_message( _("Confirmed. Signing Transaction...")) while inputIndex < len(inputs): singleInput = [chipInputs[inputIndex]] client_ledger.startUntrustedTransaction( False, 0, singleInput, redeemScripts[inputIndex], version=tx.version, overwintered=tx.overwintered) inputSignature = client_ledger.untrustedHashSign( inputsPaths[inputIndex], pin, lockTime=tx.locktime, overwintered=tx.overwintered) inputSignature[0] = 0x30 # force for 1.4.9+ my_pubkey = inputs[inputIndex][4] tx.add_signature_to_txin(txin_idx=inputIndex, signing_pubkey=my_pubkey.hex(), sig=inputSignature.hex()) inputIndex = inputIndex + 1 else: while inputIndex < len(inputs): client_ledger.startUntrustedTransaction( firstTransaction, inputIndex, chipInputs, redeemScripts[inputIndex], version=tx.version) # we don't set meaningful outputAddress, amount and fees # as we only care about the alternateEncoding==True branch outputData = client_ledger.finalizeInput( b'', 0, 0, changePath, bfh(rawTx)) outputData['outputData'] = txOutput if outputData['confirmationNeeded']: outputData['address'] = output self.handler.finished() # do the authenticate dialog and get pin: pin = self.handler.get_auth(outputData, client=client_electrum) if not pin: raise UserWarning() self.handler.show_message( _("Confirmed. Signing Transaction...")) else: # Sign input with the provided PIN inputSignature = client_ledger.untrustedHashSign( inputsPaths[inputIndex], pin, lockTime=tx.locktime) inputSignature[0] = 0x30 # force for 1.4.9+ my_pubkey = inputs[inputIndex][4] tx.add_signature_to_txin( txin_idx=inputIndex, signing_pubkey=my_pubkey.hex(), sig=inputSignature.hex()) inputIndex = inputIndex + 1 firstTransaction = False except UserWarning: self.handler.show_error(_('Cancelled by user')) return except BTChipException as e: if e.sw in (0x6985, 0x6d00): # cancelled by user return elif e.sw == 0x6982: raise # pin lock. decorator will catch it else: self.logger.exception('') self.give_error(e, True) except BaseException as e: self.logger.exception('') self.give_error(e, True) finally: self.handler.finished()
def request_trezor_init_settings(self, wizard, method, device): vbox = QVBoxLayout() next_enabled = True label = QLabel(_("Enter a label to name your device:")) name = QLineEdit() hl = QHBoxLayout() hl.addWidget(label) hl.addWidget(name) hl.addStretch(1) vbox.addLayout(hl) def clean_text(widget): text = widget.toPlainText().strip() return ' '.join(text.split()) if method in [TIM_NEW, TIM_RECOVER]: gb = QGroupBox() hbox1 = QHBoxLayout() gb.setLayout(hbox1) # KeepKey recovery doesn't need a word count if method == TIM_NEW or self.device == 'TREZOR': vbox.addWidget(gb) gb.setTitle(_("Select your seed length:")) bg = QButtonGroup() for i, count in enumerate([12, 18, 24]): rb = QRadioButton(gb) rb.setText(_("%d words") % count) bg.addButton(rb) bg.setId(rb, i) hbox1.addWidget(rb) rb.setChecked(True) cb_pin = QCheckBox(_('Enable PIN protection')) cb_pin.setChecked(True) else: text = QTextEdit() text.setMaximumHeight(60) if method == TIM_MNEMONIC: msg = _("Enter your BIP39 mnemonic:") else: msg = _("Enter the master private key beginning with xprv:") def set_enabled(): from electrum_zcash.keystore import is_xprv wizard.next_button.setEnabled(is_xprv(clean_text(text))) text.textChanged.connect(set_enabled) next_enabled = False vbox.addWidget(QLabel(msg)) vbox.addWidget(text) pin = QLineEdit() pin.setValidator(QRegExpValidator(QRegExp('[1-9]{0,9}'))) pin.setMaximumWidth(100) hbox_pin = QHBoxLayout() hbox_pin.addWidget(QLabel(_("Enter your PIN (digits 1-9):"))) hbox_pin.addWidget(pin) hbox_pin.addStretch(1) if method in [TIM_NEW, TIM_RECOVER]: vbox.addWidget(WWLabel(RECOMMEND_PIN)) vbox.addWidget(cb_pin) else: vbox.addLayout(hbox_pin) passphrase_msg = WWLabel(PASSPHRASE_HELP_SHORT) passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN) passphrase_warning.setStyleSheet("color: red") cb_phrase = QCheckBox(_('Enable passphrases')) cb_phrase.setChecked(False) vbox.addWidget(passphrase_msg) vbox.addWidget(passphrase_warning) vbox.addWidget(cb_phrase) wizard.exec_layout(vbox, next_enabled=next_enabled) if method in [TIM_NEW, TIM_RECOVER]: item = bg.checkedId() pin = cb_pin.isChecked() else: item = ' '.join(str(clean_text(text)).split()) pin = str(pin.text()) return (item, name.text(), pin, cb_phrase.isChecked())
def transaction_dialog(self, d: 'TxDialog'): d.cosigner_send_button = b = QPushButton(_("Send to cosigner")) b.clicked.connect(lambda: self.do_send(d.tx)) d.buttons.insert(0, b) b.setVisible(False)
def slider_moved(): mins = timeout_slider.sliderPosition() timeout_minutes.setText(_("%2d minutes") % mins)
def on_success(result): window.show_message( _("Your transaction was sent to the cosigning pool.") + '\n' + _("Open your cosigner wallet to retrieve it."))
def done_processing_success(self, dialog, result): dialog.show_message(_("Your labels have been synchronised."))
from electrum_zcash import Wallet, WalletStorage from electrum_zcash.util import UserCancelled, InvalidPassword from electrum_zcash.base_wizard import BaseWizard, HWD_SETUP_DECRYPT_WALLET from electrum_zcash.i18n import _ from .seed_dialog import SeedLayout, KeysLayout from .network_dialog import NetworkChoiceLayout from .util import * from .password_dialog import PasswordLayout, PasswordLayoutForHW, PW_NEW class GoBack(Exception): pass MSG_ENTER_PASSWORD = _("Choose a password to encrypt your wallet keys.") + '\n'\ + _("Leave this field empty if you want to disable encryption.") MSG_HW_STORAGE_ENCRYPTION = _("Set wallet file encryption.") + '\n'\ + _("Your wallet file does not contain secrets, mostly just metadata. ") \ + _("It also contains your master public key that allows watching your addresses.") + '\n\n'\ + _("Note: If you enable this setting, you will need your hardware device to open your wallet.") class CosignWidget(QWidget): size = 120 def __init__(self, m, n): QWidget.__init__(self) self.R = QRect(0, 0, self.size, self.size) self.setGeometry(self.R) self.setMinimumHeight(self.size)
def update(self): desc = self.desc base_unit = self.main_window.base_unit() format_amount = self.main_window.format_amount tx_hash, status, label, can_broadcast, amount, fee, height, conf, timestamp, exp_n = self.wallet.get_tx_info(self.tx) size = self.tx.estimated_size() self.broadcast_button.setEnabled(can_broadcast) can_sign = not self.tx.is_complete() and \ (self.wallet.can_sign(self.tx) or bool(self.main_window.tx_external_keypairs)) self.sign_button.setEnabled(can_sign) self.tx_hash_e.setText(tx_hash or _('Unknown')) if desc is None: self.tx_desc.hide() else: self.tx_desc.setText(_("Description") + ': ' + desc) self.tx_desc.show() self.status_label.setText(_('Status:') + ' ' + status) if timestamp: time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3] self.date_label.setText(_("Date: {}").format(time_str)) self.date_label.show() elif exp_n: text = '%.2f MB'%(exp_n/1000000) self.date_label.setText(_('Position in mempool') + ': ' + text + ' ' + _('from tip')) self.date_label.show() else: self.date_label.hide() if amount is None: amount_str = _("Transaction unrelated to your wallet") elif amount > 0: amount_str = _("Amount received:") + ' %s'% format_amount(amount) + ' ' + base_unit else: amount_str = _("Amount sent:") + ' %s'% format_amount(-amount) + ' ' + base_unit 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) confirm_rate = simple_config.FEERATE_WARNING_HIGH_FEE if fee_rate > confirm_rate: fee_str += ' - ' + _('Warning') + ': ' + _("high fee") + '!' self.amount_label.setText(amount_str) self.fee_label.setText(fee_str) self.size_label.setText(size_str) run_hook('transaction_dialog_update', self)
def run_and_get_wallet(self, get_wallet_from_daemon): vbox = QVBoxLayout() hbox = QHBoxLayout() hbox.addWidget(QLabel(_('Wallet') + ':')) self.name_e = QLineEdit() hbox.addWidget(self.name_e) button = QPushButton(_('Choose...')) hbox.addWidget(button) vbox.addLayout(hbox) self.msg_label = QLabel('') vbox.addWidget(self.msg_label) hbox2 = QHBoxLayout() self.pw_e = QLineEdit('', self) self.pw_e.setFixedWidth(150) self.pw_e.setEchoMode(2) self.pw_label = QLabel(_('Password') + ':') hbox2.addWidget(self.pw_label) hbox2.addWidget(self.pw_e) hbox2.addStretch() vbox.addLayout(hbox2) self.set_layout(vbox, title=_('Electrum-Spacecoin wallet')) wallet_folder = os.path.dirname(self.storage.path) def on_choose(): path, __ = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder) if path: self.name_e.setText(path) def on_filename(filename): path = os.path.join(wallet_folder, filename) wallet_from_memory = get_wallet_from_daemon(path) try: if wallet_from_memory: self.storage = wallet_from_memory.storage else: self.storage = WalletStorage(path, manual_upgrades=True) self.next_button.setEnabled(True) except BaseException: traceback.print_exc(file=sys.stderr) self.storage = None self.next_button.setEnabled(False) if self.storage: if not self.storage.file_exists(): msg =_("This file does not exist.") + '\n' \ + _("Press 'Next' to create this wallet, or choose another file.") pw = False elif not wallet_from_memory: if self.storage.is_encrypted_with_user_pw(): msg = _("This file is encrypted with a password.") + '\n' \ + _('Enter your password or choose another file.') pw = True elif self.storage.is_encrypted_with_hw_device(): msg = _("This file is encrypted using a hardware device.") + '\n' \ + _("Press 'Next' to choose device to decrypt.") pw = False else: msg = _("Press 'Next' to open this wallet.") pw = False else: msg = _("This file is already open in memory.") + "\n" \ + _("Press 'Next' to create/focus window.") pw = False else: msg = _('Cannot read file') pw = False self.msg_label.setText(msg) if pw: self.pw_label.show() self.pw_e.show() self.pw_e.setFocus() else: self.pw_label.hide() self.pw_e.hide() button.clicked.connect(on_choose) self.name_e.textChanged.connect(on_filename) n = os.path.basename(self.storage.path) self.name_e.setText(n) while True: if self.storage.file_exists() and not self.storage.is_encrypted(): break if self.loop.exec_() != 2: # 2 = next return if not self.storage.file_exists(): break wallet_from_memory = get_wallet_from_daemon(self.storage.path) if wallet_from_memory: return wallet_from_memory if self.storage.file_exists() and self.storage.is_encrypted(): if self.storage.is_encrypted_with_user_pw(): password = self.pw_e.text() try: self.storage.decrypt(password) break except InvalidPassword as e: QMessageBox.information(None, _('Error'), str(e)) continue except BaseException as e: traceback.print_exc(file=sys.stdout) QMessageBox.information(None, _('Error'), str(e)) return elif self.storage.is_encrypted_with_hw_device(): try: self.run('choose_hw_device', HWD_SETUP_DECRYPT_WALLET) except InvalidPassword as e: QMessageBox.information( None, _('Error'), _('Failed to decrypt using this hardware device.') + '\n' + _('If you use a passphrase, make sure it is correct.')) self.stack = [] return self.run_and_get_wallet(get_wallet_from_daemon) except BaseException as e: traceback.print_exc(file=sys.stdout) QMessageBox.information(None, _('Error'), str(e)) return if self.storage.is_past_initial_decryption(): break else: return else: raise Exception('Unexpected encryption version') path = self.storage.path if self.storage.requires_split(): self.hide() msg = _("The wallet '{}' contains multiple accounts, which are no longer supported since Electrum-Spacecoin 2.7.\n\n" "Do you want to split your wallet into multiple files?").format(path) if not self.question(msg): return file_list = '\n'.join(self.storage.split_accounts()) msg = _('Your accounts have been moved to') + ':\n' + file_list + '\n\n'+ _('Do you want to delete the old file') + ':\n' + path if self.question(msg): os.remove(path) self.show_warning(_('The file was removed')) return if self.storage.requires_upgrade(): self.storage.upgrade() self.wallet = Wallet(self.storage) return self.wallet action = self.storage.get_action() if action and action != 'new': self.hide() msg = _("The file '{}' contains an incompletely created wallet.\n" "Do you want to complete its creation now?").format(path) if not self.question(msg): if self.question(_("Do you want to delete '{}'?").format(path)): os.remove(path) self.show_warning(_('The file was removed')) return self.show() if action: # self.wallet is set in run self.run(action) return self.wallet self.wallet = Wallet(self.storage) return self.wallet
from functools import partial from PyQt5.QtCore import (pyqtSignal, Qt, QModelIndex, QVariant, QAbstractItemModel, QItemSelectionModel) from PyQt5.QtGui import QFont from PyQt5.QtWidgets import (QAbstractItemView, QHeaderView, QComboBox, QLabel, QMenu) from electrum_zcash.i18n import _ from electrum_zcash.transaction import PartialTxInput from electrum_zcash.logging import Logger from electrum_zcash.util import profiler, format_time from .util import MyTreeView, ColorScheme, MONOSPACE_FONT, EnterButton, GetDataThread SELECTED_TO_SPEND_TOOLTIP = _('Coin selected to be spent') class UTXOColumns(IntEnum): DATE = 0 OUTPOINT = 1 ADDRESS = 2 LABEL = 3 AMOUNT = 4 HEIGHT = 5 UTXOHeaders = { UTXOColumns.DATE: _('Date'), UTXOColumns.ADDRESS: _('Address'), UTXOColumns.LABEL: _('Label'),
def show_seed_dialog(self, run_next, seed_text): title = _("Your wallet generation seed is:") slayout = SeedLayout(seed=seed_text, title=title, msg=True, options=['ext']) self.exec_layout(slayout) return slayout.is_ext
def create_menu(self, position): w = self.wallet selected = self.selectionModel().selectedRows() if not selected: return menu = QMenu() menu.setSeparatorsCollapsible(True) coins = [] for idx in selected: if not idx.isValid(): return coin_item = idx.internalPointer() if not coin_item: return outpoint = coin_item['outpoint'] coins.append(self._utxo_dict[outpoint]) if len(coins) == 0: menu.addAction(_("Spend (select none)"), lambda: self.set_spend_list(coins)) else: menu.addAction(_("Spend"), lambda: self.set_spend_list(coins)) if len(coins) == 1: utxo = coins[0] address = utxo.address txid = utxo.prevout.txid.hex() outpoint = utxo.prevout.to_str() # "Details" tx = w.db.get_transaction(txid) if tx: # Prefer None if empty # (None hides the Description: field in the window) label = w.get_label_for_txid(txid) menu.addAction( _("Details"), lambda: self.parent.show_transaction(tx, tx_desc=label)) # "Copy ..." idx = self.indexAt(position) if not idx.isValid(): return self.add_copy_menu(menu, idx) # "Freeze coin" set_frozen_state_c = self.parent.set_frozen_state_of_coins if not w.is_frozen_coin(utxo): menu.addAction(_("Freeze Coin"), lambda: set_frozen_state_c([utxo], True)) else: menu.addSeparator() menu.addAction(_("Coin is frozen"), lambda: None).setEnabled(False) menu.addAction(_("Unfreeze Coin"), lambda: set_frozen_state_c([utxo], False)) menu.addSeparator() # "Freeze address" set_frozen_state_a = self.parent.set_frozen_state_of_addresses if not w.is_frozen_address(address): menu.addAction(_("Freeze Address"), lambda: set_frozen_state_a([address], True)) else: menu.addSeparator() menu.addAction(_("Address is frozen"), lambda: None).setEnabled(False) menu.addAction(_("Unfreeze Address"), lambda: set_frozen_state_a([address], False)) menu.addSeparator() elif len(coins) > 1: # multiple items selected # multiple items selected menu.addSeparator() addrs = set([utxo.address for utxo in coins]) is_coin_frozen = [w.is_frozen_coin(utxo) for utxo in coins] is_addr_frozen = [ w.is_frozen_address(utxo.address) for utxo in coins ] set_frozen_state_c = self.parent.set_frozen_state_of_coins if not all(is_coin_frozen): menu.addAction(_("Freeze Coins"), lambda: set_frozen_state_c(coins, True)) if any(is_coin_frozen): menu.addAction(_("Unfreeze Coins"), lambda: set_frozen_state_c(coins, False)) set_frozen_state_a = self.parent.set_frozen_state_of_addresses if not all(is_addr_frozen): menu.addAction(_("Freeze Addresses"), lambda: set_frozen_state_a(addrs, True)) if any(is_addr_frozen): menu.addAction(_("Unfreeze Addresses"), lambda: set_frozen_state_a(addrs, False)) menu.exec_(self.viewport().mapToGlobal(position))
def change_label(self, label): self.msg = _("Confirm the new label on your {} device") self.apply_settings(label=label)