Пример #1
0
 def read_invoice(self):
     address = str(self.address)
     if not address:
         self.app.show_error(_('Recipient not specified.') + ' ' + _('Please scan a Actinium address or a payment request'))
         return
     if not self.amount:
         self.app.show_error(_('Please enter an amount'))
         return
     try:
         amount = self.app.get_amount(self.amount)
     except:
         self.app.show_error(_('Invalid amount') + ':\n' + self.amount)
         return
     message = self.message
     if self.is_lightning:
         return parse_lightning_invoice(address)
     else:  # on-chain
         if self.payment_request:
             outputs = self.payment_request.get_outputs()
         else:
             if not bitcoin.is_address(address):
                 self.app.show_error(_('Invalid Actinium Address') + ':\n' + address)
                 return
             outputs = [PartialTxOutput.from_address_and_value(address, amount)]
         return self.app.wallet.create_invoice(outputs, message, self.payment_request, self.parsed_URI)
Пример #2
0
    def update_action_button(self):
        action_button = self.ids.action_button
        options = (
            ActionButtonOption(text=_('Sign'), func=lambda btn: self.do_sign(), enabled=self.can_sign),
            ActionButtonOption(text=_('Broadcast'), func=lambda btn: self.do_broadcast(), enabled=self.can_broadcast),
            ActionButtonOption(text=_('Bump fee'), func=lambda btn: self.do_rbf(), enabled=self.can_rbf),
            ActionButtonOption(text=_('Remove'), func=lambda btn: self.remove_local_tx(), enabled=self.can_remove_tx),
        )
        num_options = sum(map(lambda o: bool(o.enabled), options))
        # if no options available, hide button
        if num_options == 0:
            action_button.disabled = True
            action_button.opacity = 0
            return
        action_button.disabled = False
        action_button.opacity = 1

        if num_options == 1:
            # only one option, button will correspond to that
            for option in options:
                if option.enabled:
                    action_button.text = option.text
                    self._action_button_fn = option.func
        else:
            # multiple options. button opens dropdown which has one sub-button for each
            dropdown = DropDown()
            action_button.text = _('Options')
            self._action_button_fn = dropdown.open
            for option in options:
                if option.enabled:
                    btn = Button(text=option.text, size_hint_y=None, height='48dp')
                    btn.bind(on_release=option.func)
                    dropdown.add_widget(btn)
 def do_open_channel(self, conn_str, amount, password):
     coins = self.app.wallet.get_spendable_coins(None, nonlocal_only=True)
     funding_tx = self.app.wallet.lnworker.mktx_for_open_channel(
         coins=coins, funding_sat=amount)
     try:
         chan, funding_tx = self.app.wallet.lnworker.open_channel(
             connect_str=conn_str,
             funding_tx=funding_tx,
             funding_sat=amount,
             push_amt_sat=0,
             password=password)
     except Exception as e:
         self.app.show_error(
             _('Problem opening channel: ') + '\n' + repr(e))
         return
     n = chan.constraints.funding_txn_minimum_depth
     message = '\n'.join([
         _('Channel established.'),
         _('Remote peer ID') + ':' + chan.node_id.hex(),
         _('This channel will be usable after {} confirmations').format(n)
     ])
     if not funding_tx.is_complete():
         message += '\n\n' + _(
             'Please sign and broadcast the funding transaction')
     self.app.show_info(message)
     if not funding_tx.is_complete():
         self.app.tx_dialog(funding_tx)
Пример #4
0
 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
Пример #5
0
 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.actilectrum_config)
     for pr in _list:
         ci = self.get_card(pr)
         requests_list.add_widget(ci)
Пример #6
0
 def update_status(self):
     req = self.app.wallet.get_request(self.key)
     self.status, self.status_str = get_request_status(req)
     self.status_color = pr_color[self.status]
     if self.status == PR_UNPAID and self.is_lightning and self.app.wallet.lnworker:
         if self.amount and self.amount > self.app.wallet.lnworker.num_sats_can_receive(
         ):
             self.warning = _('Warning') + ': ' + _(
                 'This amount exceeds the maximum you can currently receive with your channels'
             )
 def update_status(self):
     req = self.app.wallet.get_invoice(self.key)
     self.status, self.status_str = get_request_status(req)
     self.status_color = pr_color[self.status]
     self.can_pay = self.status in [PR_UNPAID, PR_FAILED]
     if self.can_pay and self.is_lightning and self.app.wallet.lnworker:
         if self.amount and self.amount > self.app.wallet.lnworker.num_sats_can_send(
         ):
             self.warning = _('Warning') + ': ' + _(
                 'This amount exceeds the maximum you can currently send with your channels'
             )
Пример #8
0
class PincodeDialog(AbstractPasswordDialog, Factory.Popup):
    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 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 ipport_dialog(self):
        def callback(text):
            self.ipport = text

        d = LabelDialog(_('IP/port in format:\n[host]:[port]'), self.ipport,
                        callback)
        d.open()
Пример #10
0
 def show_log(self):
     if self.log:
         log_str = _('Payment log:') + '\n\n'
         for payment_attempt_log in self.log:
             route_str, chan_str, message = payment_attempt_log.formatted_tuple(
             )
             log_str += chan_str + '  ---  ' + message + '\n'
         self.app.show_info(log_str)
Пример #11
0
 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')
Пример #12
0
    def _do_pay_onchain(self, invoice, rbf):
        # make unsigned transaction
        outputs = invoice['outputs']  # type: List[PartialTxOutput]
        amount = sum(map(lambda x: x.value, outputs))
        coins = self.app.wallet.get_spendable_coins(None)
        try:
            tx = self.app.wallet.make_unsigned_transaction(coins=coins, outputs=outputs)
        except NotEnoughFunds:
            self.app.show_error(_("Not enough funds"))
            return
        except Exception as e:
            Logger.exception('')
            self.app.show_error(repr(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))

        feerate_warning = simple_config.FEERATE_WARNING_HIGH_FEE
        if fee > feerate_warning * tx.estimated_size() / 1000:
            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,))
Пример #13
0
 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()
Пример #14
0
    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()
Пример #15
0
 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 ''
Пример #16
0
 def on_password(self, pw: str):
     # 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)
Пример #17
0
 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()
Пример #18
0
 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())
Пример #19
0
 def label_dialog(self):
     from .label_dialog import LabelDialog
     key = self.tx.txid()
     text = self.app.wallet.get_label(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()
Пример #20
0
    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 = self.app.get_amount(self.amount)
     self.app.protected('Enter PIN to create a new channel',
                        self.do_open_channel, (conn_str, amount))
     self.dismiss()
Пример #22
0
 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)
Пример #23
0
    def delete_dialog(self):
        from .question import Question

        def cb(result):
            if result:
                self.app.wallet.delete_invoice(self.key)
                self.dismiss()
                self.app.send_screen.update()

        d = Question(_('Delete invoice?'), cb)
        d.open()
Пример #24
0
    def show_qr(self):
        from actilectrum.bitcoin import base_encode, bfh
        original_raw_tx = str(self.tx)
        tx = copy.deepcopy(self.tx)  # make copy as we mutate tx
        if isinstance(tx, PartialTransaction):
            # this makes QR codes a lot smaller (or just possible in the first place!)
            tx.convert_all_utxos_to_witness_utxos()

        text = tx.serialize_as_bytes()
        text = base_encode(text, base=43)
        self.app.qr_dialog(_("Raw Transaction"), text, text_for_clipboard=original_raw_tx)
Пример #25
0
    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()
Пример #26
0
    def do_delete(self, req):
        from .question import Question

        def cb(result):
            if result:
                self.app.wallet.remove_payment_request(
                    req.address, self.app.actilectrum_config)
                self.hide_menu()
                self.update()

        d = Question(_('Delete request'), cb)
        d.open()
Пример #27
0
    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()
Пример #28
0
    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)
Пример #29
0
 def set_ln_invoice(self, invoice):
     try:
         invoice = str(invoice).lower()
         lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
     except Exception as e:
         self.app.show_info(invoice + _(" is not a valid Lightning invoice: ") + repr(e)) # repr because str(Exception()) == ''
         return
     self.address = invoice
     self.message = dict(lnaddr.tags).get('d', None)
     self.amount = self.app.format_amount_and_units(lnaddr.amount * bitcoin.COIN) if lnaddr.amount else ''
     self.payment_request = None
     self.is_lightning = True
Пример #30
0
class PasswordDialog(AbstractPasswordDialog, Factory.Popup):
    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 clear_password(self):
        self.ids.textinput_generic_password.text = ''

    def on_password(self, pw: str):
        # 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 select_file(self):
        self.app.wallets_dialog()