def func_wrapper(*args, **kwargs): run_next = kwargs['run_next'] wizard = args[0] wizard.back_button.setText(_('Back') if wizard.can_go_back() else _('Cancel')) try: out = func(*args, **kwargs) except GoBack: wizard.go_back() if wizard.can_go_back() else wizard.close() return except UserCancelled: return #if out is None: # out = () if type(out) is not tuple: out = (out,) run_next(*out)
def password_dialog(self, pw, grid, pos): vkb_button = QPushButton(_("+")) vkb_button.setFixedWidth(20) vkb_button.clicked.connect(lambda: self.toggle_vkb(grid, pw)) grid.addWidget(vkb_button, pos, 2) self.kb_pos = 2 self.vkb = None
def __init__(self, parent, config, name): HW_PluginBase.__init__(self, parent, config, name) try: # Minimal test if python-trezor is installed import trezorlib try: library_version = trezorlib.__version__ except AttributeError: # python-trezor only introduced __version__ in 0.9.0 library_version = 'unknown' if library_version == 'unknown' or \ versiontuple(library_version) < self.minimum_library: self.libraries_available_message = ( _("Library version for '{}' is too old.").format(name) + '\nInstalled: {}, Needed: {}'.format( library_version, self.minimum_library)) self.print_stderr(self.libraries_available_message) raise ImportError() self.libraries_available = True except ImportError: self.libraries_available = False return from . import client from . import transport import trezorlib.ckd_public import trezorlib.messages self.client_class = client.TrezorClient self.ckd_public = trezorlib.ckd_public self.types = trezorlib.messages self.DEVICE_IDS = ('TREZOR', ) self.transport_handler = transport.TrezorTransport() self.device_manager().register_enumerate_func(self.enumerate)
def seed_device_dialog(self): msg = _("Choose how to initialize your Digital Bitbox:\n") choices = [ (_("Generate a new random wallet")), (_("Load a wallet from the micro SD card")) ] try: reply = self.handler.win.query_choice(msg, choices) except Exception: return # Back button pushed if reply == 0: self.dbb_generate_wallet() else: if not self.dbb_load_backup(show_msg=False): return self.isInitialized = True
def message_dialog(self, msg): self.clear_dialog() self.dialog = dialog = WindowModalDialog(self.top_level_window(), _("Ledger Status")) l = QLabel(msg) vbox = QVBoxLayout(dialog) vbox.addWidget(l) dialog.show()
def __init__(self, parent, contract=None): QDialog.__init__(self, parent=parent) self.setWindowTitle(_('Smart Contract')) self.setMinimumSize(700, 400) self.main_window = parent run_hook('contract_edit_dialog', self) layout = ContractInfoLayout(self, contract, callback=self.save) self.setLayout(layout)
def __init__(self, data, parent=None, title="", show_text=False): WindowModalDialog.__init__(self, parent, title) vbox = QVBoxLayout() qrw = QRCodeWidget(data) qscreen = QApplication.primaryScreen() vbox.addWidget(qrw, 1) if show_text: text = QTextEdit() text.setText(data) text.setReadOnly(True) vbox.addWidget(text) hbox = QHBoxLayout() hbox.addStretch(1) config = electrum.get_config() if config: filename = os.path.join(config.path, "qrcode.png") def print_qr(): p = qscreen.grabWindow(qrw.winId()) p.save(filename, 'png') self.show_message(_("QR code saved to file") + " " + filename) def copy_to_clipboard(): p = qscreen.grabWindow(qrw.winId()) QApplication.clipboard().setPixmap(p) # p.save(filename, 'png') # QApplication.clipboard().setImage(QImage(filename)) self.show_message(_("QR code copied to clipboard")) b = QPushButton(_("Copy")) hbox.addWidget(b) b.clicked.connect(copy_to_clipboard) b = QPushButton(_("Save")) hbox.addWidget(b) b.clicked.connect(print_qr) b = QPushButton(_("Close")) hbox.addWidget(b) b.clicked.connect(self.accept) b.setDefault(True) vbox.addLayout(hbox) self.setLayout(vbox)
def on_new_window(self, window): wallet = window.wallet if not isinstance(wallet, self.wallet_class): return if wallet.can_sign_without_server(): msg = ' '.join([ _('This wallet was restored from seed, and it contains two master private keys.' ), _('Therefore, two-factor authentication is disabled.') ]) action = lambda: window.show_message(msg) else: action = partial(self.settings_dialog, window) button = StatusBarButton(QIcon(":icons/trustedcoin-status.png"), _("TrustedCoin"), action) window.statusBar().addPermanentWidget(button) self.start_request_thread(window.wallet)
def catch_exception(self, *args, **kwargs): try: return func(self, *args, **kwargs) except BTChipException as e: if e.sw == 0x6982: raise Exception(_('Your Ledger is locked. Please unlock it.')) else: raise
def request_otp_dialog(self, window, _id, otp_secret): vbox = QVBoxLayout() if otp_secret is not None: uri = "otpauth://totp/%s?secret=%s" % ('trustedcoin.com', otp_secret) l = QLabel( "Please scan the following QR code in Google Authenticator. You may as well use the following key: %s" % otp_secret) l.setWordWrap(True) vbox.addWidget(l) qrw = QRCodeWidget(uri) vbox.addWidget(qrw, 1) msg = _('Then, enter your Google Authenticator code:') else: label = QLabel( "This wallet is already registered with Trustedcoin. " "To finalize wallet creation, please enter your Google Authenticator Code. " ) label.setWordWrap(1) vbox.addWidget(label) msg = _('Google Authenticator code:') hbox = QHBoxLayout() hbox.addWidget(WWLabel(msg)) pw = AmountEdit(None, is_int=True) pw.setFocus(True) pw.setMaximumWidth(50) hbox.addWidget(pw) vbox.addLayout(hbox) cb_lost = QCheckBox(_("I have lost my Google Authenticator account")) cb_lost.setToolTip( _("Check this box to request a new secret. You will need to retype your seed." )) vbox.addWidget(cb_lost) cb_lost.setVisible(otp_secret is None) def set_enabled(): b = True if cb_lost.isChecked() else len(pw.text()) == 6 window.next_button.setEnabled(b) pw.textChanged.connect(set_enabled) cb_lost.toggled.connect(set_enabled) window.exec_layout(vbox, next_enabled=False, raise_on_cancel=False) return pw.get_amount(), cb_lost.isChecked()
def create_menu(self, position): item = self.currentItem() if not item: return menu = QMenu() server = item.data(1, Qt.UserRole) menu.addAction(_("Use as server"), lambda: self.set_server(server)) menu.exec_(self.viewport().mapToGlobal(position))
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) 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()
def create_menu(self, position): menu = QMenu() selected = self.selectedItems() multi_select = len(selected) > 1 if not selected: menu.addAction(_("Add contract"), lambda: self.parent.contract_add_dialog()) menu.addAction(_("Create contract"), lambda: self.parent.contract_create_dialog()) elif not multi_select: item = selected[0] name = item.text(0) address = item.text(1) column = self.currentColumn() column_title = self.headerItem().text(column) column_data = '\n'.join([item.text(column) for item in selected]) menu.addAction( _("Copy %s") % column_title, lambda: self.parent.app.clipboard().setText(column_data)) menu.addAction(_("Edit"), lambda: self.parent.contract_edit_dialog(address)) menu.addAction(_("Function"), lambda: self.parent.contract_func_dialog(address)) menu.addAction(_("Delete"), lambda: self.parent.delete_samart_contact(address)) URL = block_explorer_URL(self.config, {'contract': address}) if URL: menu.addAction(_("View on block explorer"), lambda: open_browser(URL)) run_hook('create_smart_contract_menu', menu, selected) menu.exec_(self.viewport().mapToGlobal(position))
def __init__(self, dialog, callback): """ :type dialog: QDialog :type callback: func """ QGridLayout.__init__(self) self.setSpacing(8) self.setColumnStretch(3, 1) self.callback = callback self.dialog = dialog if isinstance(self.dialog.parent().wallet.keystore, TrezorKeyStore): self.dialog.show_message( 'Trezor does not support QRC20 Token for now') self.dialog.reject() return self.addresses = self.dialog.parent( ).wallet.get_addresses_sort_by_balance() addr_type, __ = b58_address_to_hash160(self.addresses[0]) if not addr_type == constants.net.ADDRTYPE_P2PKH: self.dialog.show_message('only P2PKH address supports QRC20 Token') self.dialog.reject() return address_lb = QLabel(_("Contract Address:")) self.contract_addr_e = ButtonsLineEdit() self.addWidget(address_lb, 1, 0) self.addWidget(self.contract_addr_e, 1, 1, 1, -1) address_lb = QLabel(_("My Address:")) self.address_combo = QComboBox() self.address_combo.setMinimumWidth(300) self.address_combo.addItems(self.addresses) self.addWidget(address_lb, 2, 0) self.addWidget(self.address_combo, 2, 1, 1, -1) self.cancel_btn = CancelButton(dialog) self.save_btn = QPushButton(_('Save')) self.save_btn.setDefault(True) self.save_btn.clicked.connect(self.save_input) buttons = Buttons(*[self.cancel_btn, self.save_btn]) buttons.addStretch() self.addLayout(buttons, 3, 2, 2, -1)
def create_menu(self, position): self.selectedIndexes() item = self.currentItem() if not item: return column = self.currentColumn() tx_hash = item.data(0, Qt.UserRole) if not tx_hash: return if column is 0: column_title = "ID" column_data = tx_hash else: column_title = self.headerItem().text(column) column_data = item.text(column) tx_URL = block_explorer_URL(self.config, {'tx': tx_hash}) height, conf, timestamp = self.wallet.get_tx_height(tx_hash) tx = self.wallet.transactions.get(tx_hash) is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx) is_unconfirmed = height <= 0 pr_key = self.wallet.invoices.paid.get(tx_hash) menu = QMenu() if height == TX_HEIGHT_LOCAL: menu.addAction(_("Remove"), lambda: self.remove_local_tx(tx_hash)) menu.addAction( _("Copy %s") % column_title, lambda: self.parent.app.clipboard().setText(column_data)) if column in self.editable_columns: menu.addAction( _("Edit %s") % column_title, lambda: self.editItem(item, column)) menu.addAction(_("Details"), lambda: self.parent.show_transaction(tx)) if is_unconfirmed and tx: # note: the current implementation of RBF *needs* the old tx fee rbf = is_mine and not tx.is_final() and fee is not None if rbf: menu.addAction(_("Increase fee"), lambda: self.parent.bump_fee_dialog(tx)) else: child_tx = self.wallet.cpfp(tx, 0) if child_tx: menu.addAction(_("Child pays for parent"), lambda: self.parent.cpfp(tx, child_tx)) if pr_key: menu.addAction(self.icon_cache.get(":icons/seal"), _("View invoice"), lambda: self.parent.show_invoice(pr_key)) if tx_URL: menu.addAction(_("View on block explorer"), lambda: open_browser(tx_URL)) menu.exec_(self.viewport().mapToGlobal(position))
def create_menu(self, position): menu = QMenu() item = self.itemAt(position) if not item: return key = item.data(0, Qt.UserRole) column = self.currentColumn() column_title = self.headerItem().text(column) column_data = item.text(column) pr = self.parent.invoices.get(key) status = self.parent.invoices.get_status(key) if column_data: menu.addAction(_("Copy %s")%column_title, lambda: self.parent.app.clipboard().setText(column_data)) menu.addAction(_("Details"), lambda: self.parent.show_invoice(key)) if status == PR_UNPAID: menu.addAction(_("Pay Now"), lambda: self.parent.do_pay_invoice(key)) menu.addAction(_("Delete"), lambda: self.parent.delete_invoice(key)) menu.exec_(self.viewport().mapToGlobal(position))
def __init__(self, parent): QDialog.__init__(self, parent=parent) self.setWindowTitle(_('Create Smart Contract')) self.setMinimumSize(700, 400) self.setMaximumSize(780, 500) self.main_window = parent run_hook('contract_create_dialog', self) layout = ContractCreateLayout(self) self.setLayout(layout)
def update_dlg(self): self.modes.setCurrentIndex(self.cfg['mode']) self.modebox.setVisible(True) self.addPair.setText( _("Pair") if not self.cfg['pair'] else _("Re-Pair")) self.addPair.setVisible(self.txdata['confirmationType'] > 2) self.helpmsg.setText( helpTxt[self.cfg['mode'] if self.cfg['mode'] < 2 else 2 if self. cfg['pair'] else 4]) self.helpmsg.setMinimumHeight(180 if self.txdata['confirmationType'] == 1 else 100) self.pairbox.setVisible(False) self.helpmsg.setVisible(True) self.pinbox.setVisible(self.cfg['mode'] == 0) self.cardbox.setVisible(self.cfg['mode'] == 1) self.pintxt.setFocus( True) if self.cfg['mode'] == 0 else self.cardtxt.setFocus(True) self.setMaximumHeight(200)
def remove_local_tx(self, delete_tx): to_delete = {delete_tx} to_delete |= self.wallet.get_depending_transactions(delete_tx) question = _("Are you sure you want to remove this transaction?") if len(to_delete) > 1: question = _( "Are you sure you want to remove this transaction and {} child transactions?" .format(len(to_delete) - 1)) answer = QMessageBox.question(self.parent, _("Please confirm"), question, QMessageBox.Yes, QMessageBox.No) if answer == QMessageBox.No: return for tx in to_delete: self.wallet.remove_transaction(tx) self.wallet.save_transactions(write=True) # need to update at least: history_list, utxo_list, address_list self.parent.need_update.set()
def filename_field(parent, config, defaultname, select_msg): vbox = QVBoxLayout() vbox.addWidget(QLabel(_("Format"))) gb = QGroupBox("format", parent) b1 = QRadioButton(gb) b1.setText(_("CSV")) b1.setChecked(True) b2 = QRadioButton(gb) b2.setText(_("json")) vbox.addWidget(b1) vbox.addWidget(b2) hbox = QHBoxLayout() directory = config.get('io_dir', os.path.expanduser('~')) path = os.path.join(directory, defaultname) filename_e = QLineEdit() filename_e.setText(path) def func(): text = filename_e.text() _filter = "*.csv" if text.endswith( ".csv") else "*.json" if text.endswith(".json") else None p, __ = QFileDialog.getSaveFileName(None, select_msg, text, _filter) if p: filename_e.setText(p) button = QPushButton(_('File')) button.clicked.connect(func) hbox.addWidget(button) hbox.addWidget(filename_e) vbox.addLayout(hbox) def set_csv(v): text = filename_e.text() text = text.replace(".json", ".csv") if v else text.replace( ".csv", ".json") filename_e.setText(text) b1.clicked.connect(lambda: set_csv(True)) b2.clicked.connect(lambda: set_csv(False)) return vbox, filename_e, b1
def sign_message(self, sequence, message, password): sig = None try: message = message.encode('utf8') inputPath = self.get_derivation() + "/%d/%d" % sequence msg_hash = Hash(msg_magic(message)) inputHash = to_hexstr(msg_hash) hasharray = [] hasharray.append({'hash': inputHash, 'keypath': inputPath}) hasharray = json.dumps(hasharray) msg = b'{"sign":{"meta":"sign message", "data":%s}}' % hasharray.encode('utf8') dbb_client = self.plugin.get_client(self) if not dbb_client.is_paired(): raise Exception("Could not sign message.") reply = dbb_client.hid_send_encrypt(msg) self.handler.show_message(_("Signing message ...\r\n\r\n" \ "To continue, touch the Digital Bitbox's blinking light for 3 seconds.\r\n\r\n" \ "To cancel, briefly touch the blinking light or wait for the timeout.")) reply = dbb_client.hid_send_encrypt(msg) # Send twice, first returns an echo for smart verification (not implemented) self.handler.clear_dialog() if 'error' in reply: raise Exception(reply['error']['message']) if 'sign' not in reply: raise Exception("Could not sign message.") if 'recid' in reply['sign'][0]: # firmware > v2.1.1 sig = bytes([27 + int(reply['sign'][0]['recid'], 16) + 4]) + binascii.unhexlify(reply['sign'][0]['sig']) pk, compressed = pubkey_from_signature(sig, msg_hash) pk = point_to_ser(pk.pubkey.point, compressed) addr = public_key_to_p2pkh(pk) if verify_message(addr, sig, message) is False: raise Exception("Could not sign message") elif 'pubkey' in reply['sign'][0]: # firmware <= v2.1.1 for i in range(4): sig = bytes([27 + i + 4]) + binascii.unhexlify(reply['sign'][0]['sig']) try: addr = public_key_to_p2pkh(binascii.unhexlify(reply['sign'][0]['pubkey'])) if verify_message(addr, sig, message): break except Exception: continue else: raise Exception("Could not sign message") except BaseException as e: self.give_error(e) return sig
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 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 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 checkDevice(self): if not self.preflightDone: try: self.perform_hw1_preflight() except BTChipException as e: print_error('checkDevice', e) if (e.sw == 0x6d00 or e.sw == 0x6700): raise Exception(_("Device not in Btn mode")) from e raise e self.preflightDone = True
def f(b): self.is_seed = (lambda x: bool(x)) if b else self.saved_is_seed self.on_edit() self.is_bip39 = b if b: msg = ' '.join([ '<b>' + _('Warning') + ':</b> ', _('BIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.' ), _('However, we do not generate BIP39 seeds, because they do not meet our safety standard.' ), _('BIP39 seeds do not include a version number, which compromises compatibility with future software.' ), _('We do not guarantee that BIP39 imports will always be supported in Electrum.' ), ]) else: msg = '' self.seed_warning.setText(msg)
def __init__(self, parent): """ :type parent: ElectrumWindow :type token: Token """ QDialog.__init__(self, parent=parent) self.setMinimumSize(500, 100) self.setWindowTitle(_('Add Token')) layout = TokenAddLayout(self, callback=self.save) self.setLayout(layout)
def pin_changed(s): if len(s) < len(self.idxs): i = self.idxs[len(s)] addr = self.txdata['address'] addr = addr[:i] + '<u><b>' + addr[i:i + 1] + '</u></b>' + addr[i + 1:] self.addrtext.setHtml(str(addr)) else: self.addrtext.setHtml(_("Press Enter"))
def check_device_dialog(self): # Set password if fresh device if self.password is None and not self.dbb_has_password(): if not self.setupRunning: return False # A fresh device cannot connect to an existing wallet msg = _("An uninitialized Digital Bitbox is detected. " \ "Enter a new password below.\r\n\r\n REMEMBER THE PASSWORD!\r\n\r\n" \ "You cannot access your coins or a backup without the password.\r\n" \ "A backup is saved automatically when generating a new wallet.") if self.password_dialog(msg): reply = self.hid_send_plain(b'{"password":"******"}') else: return False # Get password from user if not yet set msg = _("Enter your Digital Bitbox password:"******"led":"blink"}') if 'error' in reply: self.password = None if reply['error']['code'] == 109: msg = _("Incorrect password entered.\r\n\r\n" \ + reply['error']['message'] + "\r\n\r\n" \ "Enter your Digital Bitbox password:"******"Unexpected error occurred.\r\n\r\n" \ + reply['error']['message'] + "\r\n\r\n" \ "Enter your Digital Bitbox password:"******"device":"info"}') if reply['device']['id'] != "": self.recover_or_erase_dialog() # Already seeded else: self.seed_device_dialog() # Seed if not initialized self.mobile_pairing_dialog() return self.isInitialized
def receive_menu(self, menu, addrs, wallet): if type(wallet) is not Standard_Wallet: return keystore = wallet.get_keystore() if type(keystore) == self.keystore_class and len(addrs) == 1: def show_address(): keystore.thread.add( partial(self.show_address, wallet, addrs[0])) menu.addAction(_("Show on Ledger"), show_address)
def get_tooltip(self, pos, fee_rate): from btn_electrum.util import fee_levels rate_str = self.window.format_amount(fee_rate) + ' ' + self.window.base_unit() + '/kB' if self.dyn: tooltip = fee_levels[pos] + '\n' + rate_str else: tooltip = 'Fixed rate: ' + rate_str if self.config.has_fee_estimates(): i = self.config.reverse_dynfee(fee_rate) tooltip += '\n' + (_('Low fee') if i < 0 else 'Within %d blocks'%i) return tooltip
def get_xpub(self, device_id, derivation, xtype, wizard): if xtype not in self.SUPPORTED_XTYPES: raise ScriptTypeNotSupported( _('This type of script is not supported with {}.').format( self.device)) devmgr = self.device_manager() client = devmgr.client_by_id(device_id) client.handler = wizard xpub = client.get_xpub(derivation, xtype) client.used() return xpub