class PasswordDialog(AbstractPasswordDialog): enter_pw_message = _('Enter your password') enter_new_pw_message = _('Enter new password') confirm_new_pw_message = _('Confirm new password') wrong_password_message = _('Wrong password') allow_disable = False def __init__(self, app, **kwargs): AbstractPasswordDialog.__init__(self, app, **kwargs) def clear_password(self): self.ids.textinput_generic_password.text = '' def on_password(self, pw: str): # if not self.require_password: self.success = True self.message = _('Please wait...') self.dismiss() return # if setting new generic password, enforce min length if self.level > 0: if len(pw) < 6: self.app.show_error( _('Password is too short (min {} characters)').format(6)) return # don't enforce minimum length on existing self.do_check(pw)
def update_item(self, item): chan = item._chan item.status = chan.get_state_for_GUI() item.short_channel_id = chan.short_id_for_GUI() l, r = self.format_fields(chan) item.local_balance = _('Local') + ':' + l item.remote_balance = _('Remote') + ': ' + r self.update_can_send()
def update(self): self.menu_actions = [(_('Show'), self.do_show), (_('Delete'), self.do_delete)] requests_list = self.ids.requests_container requests_list.clear_widgets() _list = self.app.wallet.get_sorted_requests(self.app.electrum_config) for pr in _list: ci = self.get_card(pr) requests_list.add_widget(ci)
def get_card(self, addr, balance, is_used, label): ci = {} ci['screen'] = self ci['address'] = addr ci['memo'] = label ci['amount'] = self.app.format_amount_and_units(balance) ci['status'] = _('Used') if is_used else _( 'Funded') if balance > 0 else _('Unused') return ci
def _close(self, b): if not b: return loop = self.app.wallet.network.asyncio_loop coro = asyncio.run_coroutine_threadsafe( self.app.wallet.lnworker.close_channel(self.chan.channel_id), loop) try: coro.result(5) self.app.show_info(_('Channel closed')) except Exception as e: self.logger.exception("Could not close channel") self.app.show_info(_('Could not close channel: ') + repr(e)) # repr because str(Exception()) == ''
def __init__(self, msg, callback, *, yes_str: str = None, no_str: str = None, title: str = None): Factory.Popup.__init__(self) self.yes_str = yes_str or _('Yes') self.no_str = no_str or _('No') self.title = title or _('Question') self.message = msg self.callback = callback
def export_backup(self): text = self.app.wallet.lnworker.export_channel_backup( self.chan.channel_id) # TODO: some messages are duplicated between Kivy and Qt. help_text = ' '.join([ _("Channel backups can be imported in another instance of the same wallet, by scanning this QR code." ), _("Please note that channel backups cannot be used to restore your channels." ), _("If you lose your wallet file, the only thing you can do with a backup is to request your channel to be closed, so that your funds will be sent on-chain." ), ]) self.app.qr_dialog(_("Channel Backup " + self.chan.short_id_for_GUI()), text, help_text=help_text)
def on_password(self, pw: str): # if not self.require_password: self.success = True self.message = _('Please wait...') self.dismiss() return # if setting new generic password, enforce min length if self.level > 0: if len(pw) < 6: self.app.show_error( _('Password is too short (min {} characters)').format(6)) return # don't enforce minimum length on existing self.do_check(pw)
def get_card(self, req: Invoice) -> Dict[str, Any]: is_lightning = req.is_lightning() if not is_lightning: assert isinstance(req, OnchainInvoice) address = req.get_address() key = address else: assert isinstance(req, LNInvoice) key = req.rhash address = req.invoice amount = req.get_amount_sat() description = req.message status = self.app.wallet.get_request_status(key) status_str = req.get_status_str(status) ci = {} ci['screen'] = self ci['address'] = address ci['is_lightning'] = is_lightning ci['key'] = key ci['amount'] = self.app.format_amount_and_units( amount) if amount else '' ci['memo'] = description or _('No Description') ci['status'] = status ci['status_str'] = status_str return ci
def new_request(self, lightning): amount = self.amount amount = self.app.get_amount(amount) if amount else 0 message = self.message if lightning: key = self.app.wallet.lnworker.add_request(amount, message, self.expiry()) else: addr = self.address or self.app.wallet.get_unused_address() if not addr: if not self.app.wallet.is_deterministic(): addr = self.app.wallet.get_receiving_address() else: self.app.show_info( _('No address available. Please remove some of your pending requests.' )) return self.address = addr req = self.app.wallet.make_payment_request(addr, amount, message, self.expiry()) self.app.wallet.add_payment_request(req) key = addr self.clear() self.update() self.app.show_request(lightning, key)
def do_pay_invoice(self, invoice): if invoice.is_lightning(): if self.app.wallet.lnworker: self.app.protected(_('Pay lightning invoice?'), self._do_pay_lightning, (invoice, )) else: self.app.show_error( _("Lightning payments are not available for this wallet")) else: do_pay = lambda rbf: self._do_pay_onchain(invoice, rbf) if self.app.electrum_config.get('use_rbf'): d = Question(_('Should this transaction be replaceable?'), do_pay) d.open() else: do_pay(False)
def get_card(self, item: Invoice): status = self.app.wallet.get_invoice_status(item) status_str = item.get_status_str(status) is_lightning = item.type == PR_TYPE_LN if is_lightning: assert isinstance(item, LNInvoice) key = item.rhash address = key if self.app.wallet.lnworker: log = self.app.wallet.lnworker.logs.get(key) if status == PR_INFLIGHT and log: status_str += '... (%d)' % len(log) is_bip70 = False else: assert isinstance(item, OnchainInvoice) key = item.id address = item.get_address() is_bip70 = bool(item.bip70) return { 'is_lightning': is_lightning, 'is_bip70': is_bip70, 'screen': self, 'status': status, 'status_str': status_str, 'key': key, 'memo': item.message or _('No Description'), 'address': address, 'amount': self.app.format_amount_and_units(item.get_amount_sat() or 0), }
def __init__(self, chan: Channel, app: 'ElectrumWindow', **kwargs): Popup.__init__(self, **kwargs) Logger.__init__(self) self.is_closed = chan.is_closed() self.is_redeemed = chan.is_redeemed() self.app = app self.chan = chan self.title = _('Channel details') self.node_id = bh2u(chan.node_id) self.channel_id = bh2u(chan.channel_id) self.funding_txid = chan.funding_outpoint.txid self.short_id = format_short_channel_id(chan.short_channel_id) self.capacity = self.app.format_amount_and_units( chan.constraints.capacity) self.state = chan.get_state_for_GUI() self.local_ctn = chan.get_latest_ctn(LOCAL) self.remote_ctn = chan.get_latest_ctn(REMOTE) self.local_csv = chan.config[LOCAL].to_self_delay self.remote_csv = chan.config[REMOTE].to_self_delay self.initiator = 'Local' if chan.constraints.is_initiator else 'Remote' self.feerate = chan.get_latest_feerate(LOCAL) self.can_send = self.app.format_amount_and_units( chan.available_to_spend(LOCAL) // 1000) self.can_receive = self.app.format_amount_and_units( chan.available_to_spend(REMOTE) // 1000) self.is_open = chan.is_open() closed = chan.get_closing_height() if closed: self.closing_txid, closing_height, closing_timestamp = closed
def update_status(self): req = self.app.wallet.get_request(self.key) self.status = self.app.wallet.get_request_status(self.key) self.status_str = req.get_status_str(self.status) self.status_color = pr_color[self.status] if self.status == PR_UNPAID and self.is_lightning and self.app.wallet.lnworker: if self.amount_sat and self.amount_sat > self.app.wallet.lnworker.num_sats_can_receive( ): self.warning = _('Warning') + ': ' + _( 'This amount exceeds the maximum you can currently receive with your channels' ) if self.status == PR_UNPAID and not self.is_lightning: address = req.get_address() if self.app.wallet.is_used(address): self.warning = _('Warning') + ': ' + _( 'This address is being reused')
def ipport_dialog(self): def callback(text): self.ipport = text d = LabelDialog(_('IP/port in format:\n[host]:[port]'), self.ipport, callback) d.open()
def fx_status(self): fx = self.app.fx if fx.is_enabled(): source = fx.exchange.name() ccy = fx.get_currency() return '%s [%s]' % (ccy, source) else: return _('None')
def __init__(self, chan: AbstractChannel, app: 'ElectrumWindow', **kwargs): Popup.__init__(self, **kwargs) Logger.__init__(self) self.chan = chan self.app = app self.short_id = format_short_channel_id(chan.short_channel_id) self.state = chan.get_state_for_GUI() self.title = _('Channel Backup')
class PincodeDialog(AbstractPasswordDialog): enter_pw_message = _('Enter your PIN') enter_new_pw_message = _('Enter new PIN') confirm_new_pw_message = _('Confirm new PIN') wrong_password_message = _('Wrong PIN') allow_disable = True def __init__(self, app, **kwargs): AbstractPasswordDialog.__init__(self, app, **kwargs) def clear_password(self): self.ids.kb.password = '' def on_password(self, pw: str): # PIN codes are exactly 6 chars if len(pw) >= 6: self.do_check(pw)
def expiration_dialog(self, obj): from .dialogs.choice_dialog import ChoiceDialog def callback(c): self.app.electrum_config.set_key('request_expiry', c) d = ChoiceDialog(_('Expiration date'), pr_expiration_values, self.expiry(), callback) d.open()
def on_address(self, addr): req = self.app.wallet.get_request(addr) self.status = '' if req: self.message = req.get('memo', '') amount = req.get('amount') self.amount = self.app.format_amount_and_units( amount) if amount else '' status = req.get('status', PR_UNKNOWN) self.status = _('Payment received') if status == PR_PAID else ''
def _force_close(self, b): if not b: return if self.chan.is_closed(): self.app.show_error(_('Channel already closed')) return loop = self.app.wallet.network.asyncio_loop coro = asyncio.run_coroutine_threadsafe( self.app.wallet.lnworker.force_close_channel(self.chan.channel_id), loop) try: coro.result(1) self.app.show_info( _('Channel closed, you may need to wait at least {} blocks, because of CSV delays' .format(self.chan.config[REMOTE].to_self_delay))) except Exception as e: self.logger.exception("Could not force close channel") self.app.show_info(_('Could not force close channel: ') + repr(e)) # repr because str(Exception()) == ''
def on_currency(self, ccy): b = (ccy != _('None')) self.fx.set_enabled(b) if b: if ccy != self.fx.get_currency(): self.fx.set_currency(ccy) self.app.fiat_unit = ccy else: self.app.is_fiat = False Clock.schedule_once(lambda dt: self.add_exchanges())
def remove_local_tx(self): txid = self.tx.txid() to_delete = {txid} to_delete |= self.wallet.get_depending_transactions(txid) 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)) def on_prompt(b): if b: for tx in to_delete: self.wallet.remove_transaction(tx) self.wallet.save_db() self.app._trigger_update_wallet() # FIXME private... self.dismiss() d = Question(question, on_prompt) d.open()
def delete_dialog(self): from .question import Question def cb(result): if result: self.app.wallet.delete_request(self.key) self.dismiss() self.app.receive_screen.update() d = Question(_('Delete request?'), cb) d.open()
def open_channel(self): if not self.pubkey or not self.amount: self.app.show_info(_('All fields must be filled out')) return conn_str = self.pubkey if self.ipport: conn_str += '@' + self.ipport.strip() amount = '!' if self.is_max else self.app.get_amount(self.amount) self.app.protected('Create a new channel?', self.do_open_channel, (conn_str, amount)) self.dismiss()
def send_report(self): try: loop = self.main_window.network.asyncio_loop proxy = self.main_window.network.proxy # FIXME network request in GUI thread... response = json.loads( BaseCrashReporter.send_report(self, loop, proxy, "/crash.json", timeout=10)) except (ValueError, ClientError): #self.logger.debug("", exc_info=True) self.show_popup(_('Unable to send report'), _("Please check your network connection.")) else: self.show_popup(_('Report sent'), response["text"]) if response["location"]: self.open_url(response["location"]) self.dismiss()
def do_delete(self, obj): from .question import Question def cb(result): if result: self.app.wallet.invoices.remove(obj.key) self.hide_menu() self.update() d = Question(_('Delete invoice?'), cb) d.open()
def __init__(self, parent, address, balance, status, **kwargs): super(AddressPopup, self).__init__(**kwargs) self.title = _('Address Details') self.parent_dialog = parent self.app = parent.app self.address = address self.status = status self.script_type = self.app.wallet.get_txin_type(self.address) self.balance = self.app.format_amount_and_units(balance) self.address_color, self.address_background_color = address_colors( self.app.wallet, address)
def do_delete(self, req): from .question import Question def cb(result): if result: self.app.wallet.remove_payment_request( req.address, self.app.electrum_config) self.hide_menu() self.update() d = Question(_('Delete request'), cb) d.open()
def label_dialog(self): from .label_dialog import LabelDialog key = self.tx.txid() text = self.app.wallet.get_label_for_txid(key) def callback(text): self.app.wallet.set_label(key, text) self.update() self.app.history_screen.update() d = LabelDialog(_('Enter Transaction Label'), text, callback) d.open()