示例#1
0
 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()
示例#3
0
 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()
示例#4
0
 def settings_widget(self, window: WindowModalDialog):
     return EnterButton(_('Settings'),
                        partial(self.settings_dialog, window))
示例#5
0
 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])}')
示例#6
0
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.  "
示例#7
0
    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)
示例#8
0
 def decrypt_message(self, sequence, message, password):
     raise RuntimeError(
         _('Encryption and decryption are not implemented by {}').format(
             self.device))
示例#9
0
    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):
示例#10
0
    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_()
示例#11
0
 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))
示例#12
0
 def format_date(self, d):
     return str(datetime.date(d.year, d.month, d.day)) if d else _('None')
示例#13
0
    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()
示例#14
0
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)
示例#15
0
 def on_m(m):
     m_label.setText(_('Require {0} signatures').format(m))
     cw.set_m(m)
示例#16
0
 def decrypt_message(self, pubkey, message, password):
     raise UserFacingException(
         _('Encryption and decryption are currently not supported for {}').
         format(self.device))
示例#17
0
 def on_n(n):
     n_label.setText(_('From {0} cosigners').format(n))
     cw.set_n(n)
     m_edit.setMaximum(n)
示例#18
0
    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()
示例#19
0
    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())
示例#20
0
 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)
示例#21
0
 def slider_moved():
     mins = timeout_slider.sliderPosition()
     timeout_minutes.setText(_("%2d minutes") % mins)
示例#22
0
 def on_success(result):
     window.show_message(
         _("Your transaction was sent to the cosigning pool.") + '\n' +
         _("Open your cosigner wallet to retrieve it."))
示例#23
0
 def done_processing_success(self, dialog, result):
     dialog.show_message(_("Your labels have been synchronised."))
示例#24
0
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)
示例#26
0
    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
示例#27
0
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'),
示例#28
0
 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
示例#29
0
    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))
示例#30
0
 def change_label(self, label):
     self.msg = _("Confirm the new label on your {} device")
     self.apply_settings(label=label)