def update(self): self.menu_actions = [(_('Use'), self.do_use), (_('Details'), self.do_view)] wallet = self.app.wallet if self.show_change == 0: _list = wallet.get_receiving_addresses() elif self.show_change == 1: _list = wallet.get_change_addresses() else: _list = wallet.get_addresses() search = self.message container = self.ids.search_container n = 0 cards = [] for address in _list: label = wallet.labels.get(address, '') balance = sum(wallet.get_addr_balance(address)) is_used_and_empty = wallet.is_used(address) and balance == 0 if self.show_used == 1 and (balance or is_used_and_empty): continue if self.show_used == 2 and balance == 0: continue if self.show_used == 3 and not is_used_and_empty: continue card = self.get_card(address, balance, is_used_and_empty, label) if search and not self.ext_search(card, search): continue cards.append(card) n += 1 container.data = cards if not n: self.app.show_error('No address matching your search')
def update(self): format_amount = self.app.format_amount_and_units tx_hash, self.status_str, self.description, self.can_broadcast, self.can_rbf, amount, fee, height, conf, timestamp, exp_n = self.wallet.get_tx_info(self.tx) self.tx_hash = tx_hash or '' if timestamp: self.date_label = _('Date') self.date_str = datetime.fromtimestamp(timestamp).isoformat(' ')[:-3] elif exp_n: self.date_label = _('Mempool depth') self.date_str = _('{} from tip').format('%.2f MB'%(exp_n/1000000)) else: self.date_label = '' self.date_str = '' if amount is None: self.amount_str = _("Transaction unrelated to your wallet") elif amount > 0: self.is_mine = False self.amount_str = format_amount(amount) else: self.is_mine = True self.amount_str = format_amount(-amount) self.fee_str = format_amount(fee) if fee is not None else _('unknown') self.can_sign = self.wallet.can_sign(self.tx) self.ids.output_list.update(self.tx.get_outputs_for_UI())
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 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 send_report(self): try: loop = self.main_window.network.asyncio_loop proxy = self.main_window.network.proxy response = json.loads(BaseCrashReporter.send_report(self, loop, proxy, "/crash.json")) except (ValueError, ClientError): 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 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 unit_dialog(self, item, dt): if self._unit_dialog is None: def cb(text): self.app._set_bu(text) item.bu = self.app.base_unit self._unit_dialog = ChoiceDialog(_('Denomination'), base_units_list, self.app.base_unit, cb, keep_choice_order=True) self._unit_dialog.open()
def _do_send(self, amount, message, outputs, rbf): # make unsigned transaction config = self.app.electrum_config coins = self.app.wallet.get_spendable_coins(None, config) try: tx = self.app.wallet.make_unsigned_transaction(coins, outputs, config, None) except NotEnoughFunds: self.app.show_error(_("Not enough funds")) return except Exception as e: traceback.print_exc(file=sys.stdout) self.app.show_error(str(e)) return if rbf: tx.set_rbf(True) fee = tx.get_fee() msg = [ _("Amount to be sent") + ": " + self.app.format_amount_and_units(amount), _("Mining fee") + ": " + self.app.format_amount_and_units(fee), ] x_fee = run_hook('get_tx_extra_fee', self.app.wallet, tx) if x_fee: x_fee_address, x_fee_amount = x_fee msg.append(_("Additional fees") + ": " + self.app.format_amount_and_units(x_fee_amount)) if fee >= config.get('confirm_fee', 1000000): msg.append(_('Warning')+ ': ' + _("The fee for this transaction seems unusually high.")) msg.append(_("Enter your PIN code to proceed")) self.app.protected('\n'.join(msg), self.send_tx, (tx, message))
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 label_dialog(self, obj): from .dialogs.label_dialog import LabelDialog key = obj.tx_hash text = self.app.wallet.get_label(key) def callback(text): self.app.wallet.set_label(key, text) self.update() d = LabelDialog(_('Enter Transaction Label'), text, callback) d.open()
def coinselect_dialog(self, item, dt): if self._coinselect_dialog is None: choosers = sorted(coinchooser.COIN_CHOOSERS.keys()) chooser_name = coinchooser.get_name(self.config) def cb(text): self.config.set_key('coin_chooser', text) item.status = text self._coinselect_dialog = ChoiceDialog(_('Coin selection'), choosers, chooser_name, cb) self._coinselect_dialog.open()
def language_dialog(self, item, dt): if self._language_dialog is None: l = self.config.get('language', 'en_UK') def cb(key): self.config.set_key("language", key, True) item.lang = self.get_language_name() self.app.language = key self._language_dialog = ChoiceDialog(_('Language'), languages, l, cb) self._language_dialog.open()
def do_rbf(self): from .bump_fee_dialog import BumpFeeDialog is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(self.tx) if fee is None: self.app.show_error(_("Can't bump fee: unknown fee for original transaction.")) return size = self.tx.estimated_size() d = BumpFeeDialog(self.app, fee, size, self._do_rbf) d.open()
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 on_address(self, addr): req = self.app.wallet.get_payment_request(addr, self.app.electrum_config) self.screen.status = '' if req: self.screen.message = req.get('memo', '') amount = req.get('amount') self.screen.amount = self.app.format_amount_and_units(amount) if amount else '' status = req.get('status', PR_UNKNOWN) self.screen.status = _('Payment received') if status == PR_PAID else '' Clock.schedule_once(lambda dt: self.update_qr())
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 __init__(self, obj, action_list): Bubble.__init__(self) self.obj = obj for k, v in action_list: l = MenuItem() l.text = _(k) def func(f=v): Clock.schedule_once(lambda dt: f(obj), 0.15) l.on_release = func self.ids.buttons.add_widget(l)
def do_send(self): if self.screen.is_pr: if self.payment_request.has_expired(): self.app.show_error(_('Payment request has expired')) return outputs = self.payment_request.get_outputs() else: address = str(self.screen.address) if not address: self.app.show_error(_('Recipient not specified.') + ' ' + _('Please scan a Litecoin address or a payment request')) return if not bitcoin.is_address(address): self.app.show_error(_('Invalid Litecoin Address') + ':\n' + address) return try: amount = self.app.get_amount(self.screen.amount) except: self.app.show_error(_('Invalid amount') + ':\n' + self.screen.amount) return outputs = [TxOutput(bitcoin.TYPE_ADDRESS, address, amount)] message = self.screen.message amount = sum(map(lambda x:x[2], outputs)) if self.app.electrum_config.get('use_rbf'): from .dialogs.question import Question d = Question(_('Should this transaction be replaceable?'), lambda b: self._do_send(amount, message, outputs, b)) d.open() else: self._do_send(amount, message, outputs, False)
def get_card(self, pr): key = pr.get_id() ci = self.cards.get(key) if ci is None: ci = Factory.InvoiceItem() ci.key = key ci.screen = self self.cards[key] = ci ci.requestor = pr.get_requestor() ci.memo = pr.get_memo() amount = pr.get_amount() if amount: ci.amount = self.app.format_amount_and_units(amount) status = self.app.wallet.invoices.get_status(ci.key) ci.status = invoice_text[status] ci.icon = pr_icon[status] else: ci.amount = _('No Amount') ci.status = '' exp = pr.get_expiration_date() ci.date = format_time(exp) if exp else _('Never') return ci
def on_password(self, pw): if len(pw) == 6: if self.check_password(pw): if self.is_change == 0: self.success = True self.pw = pw self.message = _('Please wait...') self.dismiss() elif self.is_change == 1: self.pw = pw self.message = _('Enter new PIN') self.ids.kb.password = '' self.is_change = 2 elif self.is_change == 2: self.new_password = pw self.message = _('Confirm new PIN') self.ids.kb.password = '' self.is_change = 3 elif self.is_change == 3: self.success = pw == self.new_password self.dismiss() else: self.app.show_error(_('Wrong PIN')) self.ids.kb.password = ''
def set_URI(self, text): if not self.app.wallet: self.payment_request_queued = text return import electrum_ltc as electrum try: uri = electrum.util.parse_URI(text, self.app.on_pr) except: self.app.show_info(_("Not a Litecoin URI")) return amount = uri.get('amount') self.screen.address = uri.get('address', '') self.screen.message = uri.get('message', '') self.screen.amount = self.app.format_amount_and_units(amount) if amount else '' self.payment_request = None self.screen.is_pr = False
def save_request(self): addr = self.screen.address if not addr: return False amount = self.screen.amount message = self.screen.message amount = self.app.get_amount(amount) if amount else 0 req = self.app.wallet.make_payment_request(addr, amount, message, None) try: self.app.wallet.add_payment_request(req, self.app.electrum_config) added_request = True except Exception as e: self.app.show_error(_('Error adding payment request') + ':\n' + str(e)) added_request = False finally: self.app.update_tab('requests') return added_request
def do_save(self): if not self.screen.address: return if self.screen.is_pr: # it should be already saved return # save address as invoice from electrum_ltc.paymentrequest import make_unsigned_request, PaymentRequest req = {'address':self.screen.address, 'memo':self.screen.message} amount = self.app.get_amount(self.screen.amount) if self.screen.amount else 0 req['amount'] = amount pr = make_unsigned_request(req).SerializeToString() pr = PaymentRequest(pr) self.app.wallet.invoices.add(pr) self.app.show_info(_("Invoice saved")) if pr.is_pr(): self.screen.is_pr = True self.payment_request = pr else: self.screen.is_pr = False self.payment_request = None
def get_card(self, tx_hash, tx_mined_status, value, balance): status, status_str = self.app.wallet.get_tx_status(tx_hash, tx_mined_status) icon = "atlas://electrum_ltc/gui/kivy/theming/light/" + TX_ICONS[status] label = self.app.wallet.get_label(tx_hash) if tx_hash else _('Pruned transaction outputs') ri = {} ri['screen'] = self ri['tx_hash'] = tx_hash ri['icon'] = icon ri['date'] = status_str ri['message'] = label ri['confirmations'] = tx_mined_status.conf if value is not None: ri['is_mine'] = value < 0 if value < 0: value = - value ri['amount'] = self.app.format_amount_and_units(value) if self.app.fiat_unit: fx = self.app.fx fiat_value = value / Decimal(bitcoin.COIN) * self.app.wallet.price_at_timestamp(tx_hash, fx.timestamp_rate) fiat_value = Fiat(fiat_value, fx.ccy) ri['quote_text'] = str(fiat_value) return ri
def __do_sign(self, password): try: self.app.wallet.sign_transaction(self.tx, password) except InvalidPassword: self.app.show_error(_("Invalid PIN")) self.update()
def show_qr(self): original_raw_tx = str(self.tx) qr_data = self.tx.to_qr_data() self.app.qr_dialog(_("Raw Transaction"), qr_data, text_for_clipboard=original_raw_tx)
def add_currencies(self): currencies = [_('None')] + self.fx.get_currencies(True) my_ccy = self.fx.get_currency() if self.fx.is_enabled() else _('None') self.ids.ccy.values = currencies self.ids.ccy.text = my_ccy
def force_close(self): Question(_('Force-close channel?'), self._force_close).open()
def do_copy(self): uri = self.get_URI() self.app._clipboard.copy(uri) self.app.show_info(_('Request copied to clipboard'))
''') from kivy.properties import BooleanProperty from electrum_ltc.gui.kivy.i18n import _ from electrum_ltc.util import format_time from electrum_ltc.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED from electrum_ltc.gui.kivy.uix.context_menu import ContextMenu pr_icon = { PR_UNPAID: 'atlas://electrum_ltc/gui/kivy/theming/light/important', PR_UNKNOWN: 'atlas://electrum_ltc/gui/kivy/theming/light/important', PR_PAID: 'atlas://electrum_ltc/gui/kivy/theming/light/confirmed', PR_EXPIRED: 'atlas://electrum_ltc/gui/kivy/theming/light/close' } request_text = { PR_UNPAID: _('Pending'), PR_UNKNOWN: _('Unknown'), PR_PAID: _('Received'), PR_EXPIRED: _('Expired') } class RequestsDialog(Factory.Popup): def __init__(self, app, screen, callback): Factory.Popup.__init__(self) self.app = app self.screen = screen self.callback = callback self.cards = {} self.context_menu = None
def _do_sign(self, password): self.status_str = _('Signing') + '...' Clock.schedule_once(lambda dt: self.__do_sign(password), 0.1)
def do_sign(self): self.app.protected(_("Enter your PIN code in order to sign this transaction"), self._do_sign, ())
def copy_to_clipboard(self): Clipboard.copy(self.text_for_clipboard) msg = _('Text copied to clipboard.') Clock.schedule_once(lambda dt: self.app.show_info(msg))
def remove_backup(self): msg = _('Delete backup?') Question(msg, self._remove_backup).open()
def details(self): chan = self.chan status = self.app.wallet.lnworker.get_channel_status(chan) return { _('Short Chan ID'): format_short_channel_id(chan.short_channel_id), _('Initiator'): 'Local' if chan.constraints.is_initiator else 'Remote', _('State'): status, _('Local CTN'): chan.get_latest_ctn(LOCAL), _('Remote CTN'): chan.get_latest_ctn(REMOTE), _('Capacity'): self.app.format_amount_and_units(chan.constraints.capacity), _('Can send'): self.app.format_amount_and_units(chan.available_to_spend(LOCAL) // 1000), _('Current feerate'): str(chan.get_latest_feerate(LOCAL)), _('Node ID'): bh2u(chan.node_id), _('Channel ID'): bh2u(chan.channel_id), _('Funding TXID'): chan.funding_outpoint.txid, }
def close(self): Question(_('Close channel?'), self._close).open()
def do_sign(self): self.app.protected(_("Sign this transaction?"), self._do_sign, ())
def do_paste(self): contents = self.app._clipboard.paste() if not contents: self.app.show_info(_("Clipboard is empty")) return self.pubkey = contents
cols: 1 id: invoices_container size_hint: 1, None height: self.minimum_height spacing: '2dp' padding: '12dp' ''') from kivy.properties import BooleanProperty from electrum_ltc.gui.kivy.i18n import _ from electrum_ltc.util import format_time from electrum_ltc.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED from electrum_ltc.gui.kivy.uix.context_menu import ContextMenu invoice_text = { PR_UNPAID: _('Pending'), PR_UNKNOWN: _('Unknown'), PR_PAID: _('Paid'), PR_EXPIRED: _('Expired') } pr_icon = { PR_UNPAID: 'atlas://electrum_ltc/gui/kivy/theming/light/important', PR_UNKNOWN: 'atlas://electrum_ltc/gui/kivy/theming/light/important', PR_PAID: 'atlas://electrum_ltc/gui/kivy/theming/light/confirmed', PR_EXPIRED: 'atlas://electrum_ltc/gui/kivy/theming/light/close' } class InvoicesDialog(Factory.Popup): def __init__(self, app, screen, callback): Factory.Popup.__init__(self)
def do_sign(self): self.app.protected( _("Enter your PIN code in order to sign this transaction"), self._do_sign, ())
def request_force_close(self): msg = _('Request force close?') Question(msg, self._request_force_close).open()
def show_qr(self): from electrum_ltc.bitcoin import base_encode, bfh raw_tx = str(self.tx) text = bfh(raw_tx) text = base_encode(text, base=43) self.app.qr_dialog(_("Raw Transaction"), text, text_for_clipboard=raw_tx)
def do_share(self): self.app.do_share(self.data, _("Share Invoice")) self.dismiss()
class InfoBubble(Factory.Bubble): '''Bubble to be used to display short Help Information''' message = StringProperty(_('Nothing set !')) '''Message to be displayed; defaults to "nothing set"''' icon = StringProperty('') ''' Icon to be displayed along with the message defaults to '' :attr:`icon` is a `StringProperty` defaults to `''` ''' fs = BooleanProperty(False) ''' Show Bubble in half screen mode :attr:`fs` is a `BooleanProperty` defaults to `False` ''' modal = BooleanProperty(False) ''' Allow bubble to be hidden on touch. :attr:`modal` is a `BooleanProperty` defauult to `False`. ''' exit = BooleanProperty(False) '''Indicates whether to exit app after bubble is closed. :attr:`exit` is a `BooleanProperty` defaults to False. ''' dim_background = BooleanProperty(False) ''' Indicates Whether to draw a background on the windows behind the bubble. :attr:`dim` is a `BooleanProperty` defaults to `False`. ''' def on_touch_down(self, touch): if self.modal: return True self.hide() if self.collide_point(*touch.pos): return True def show(self, pos, duration, width=None, modal=False, exit=False): '''Animate the bubble into position''' self.modal, self.exit = modal, exit if width: self.width = width if self.modal: from kivy.uix.modalview import ModalView self._modal_view = m = ModalView(background_color=[.5, .5, .5, .2]) Window.add_widget(m) m.add_widget(self) else: Window.add_widget(self) # wait for the bubble to adjust its size according to text then animate Clock.schedule_once(lambda dt: self._show(pos, duration)) def _show(self, pos, duration): def on_stop(*l): if duration: Clock.schedule_once(self.hide, duration + .5) self.opacity = 0 arrow_pos = self.arrow_pos if arrow_pos[0] in ('l', 'r'): pos = pos[0], pos[1] - (self.height / 2) else: pos = pos[0] - (self.width / 2), pos[1] self.limit_to = Window anim = Factory.Animation(opacity=1, pos=pos, d=.32) anim.bind(on_complete=on_stop) anim.cancel_all(self) anim.start(self) def hide(self, now=False): ''' Auto fade out the Bubble ''' def on_stop(*l): if self.modal: m = self._modal_view m.remove_widget(self) Window.remove_widget(m) Window.remove_widget(self) if self.exit: App.get_running_app().stop() import sys sys.exit() else: App.get_running_app().is_exit = False if now: return on_stop() anim = Factory.Animation(opacity=0, d=.25) anim.bind(on_complete=on_stop) anim.cancel_all(self) anim.start(self)
def do_share(self): self.app.do_share(self.data, _("Share Litecoin Request")) self.dismiss()
def proxy_status(self): net_params = self.app.network.get_parameters() proxy = net_params.proxy return proxy.get('host') + ':' + proxy.get('port') if proxy else _( 'None')
def proxy_status(self): server, port, protocol, proxy, auto_connect = self.app.network.get_parameters( ) return proxy.get('host') + ':' + proxy.get('port') if proxy else _( 'None')
def remove_channel(self): msg = _('Are you sure you want to delete this channel? This will purge associated transactions from your wallet history.') Question(msg, self._remove_channel).open()