Example #1
0
 def make_unsigned_transaction(self,
                               *,
                               coins: Sequence[PartialTxInput],
                               outputs: List[PartialTxOutput],
                               fee=None,
                               change_addr: str = None,
                               is_sweep=False) -> PartialTransaction:
     mk_tx = lambda o: Multisig_Wallet.make_unsigned_transaction(
         self, coins=coins, outputs=o, fee=fee, change_addr=change_addr)
     extra_fee = self.extra_fee() if not is_sweep else 0
     if extra_fee:
         address = self.billing_info['billing_address_segwit']
         fee_output = PartialTxOutput.from_address_and_value(
             address, extra_fee)
         try:
             tx = mk_tx(outputs + [fee_output])
         except NotEnoughFunds:
             # TrustedCoin won't charge if the total inputs is
             # lower than their fee
             tx = mk_tx(outputs)
             if tx.input_value() >= extra_fee:
                 raise
             self.logger.info("not charging for this tx")
     else:
         tx = mk_tx(outputs)
     return tx
Example #2
0
 def read_invoice(self):
     address = str(self.address)
     if not address:
         self.app.show_error(
             _('Recipient not specified.') + ' ' +
             _('Please scan a Doichain 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 LNInvoice.from_bech32(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 Doichain Address') + ':\n' + address)
                 return
             outputs = [
                 PartialTxOutput.from_address_and_value(address, amount)
             ]
         return self.app.wallet.create_invoice(outputs=outputs,
                                               message=message,
                                               pr=self.payment_request,
                                               URI=self.parsed_URI)
Example #3
0
 def get_max_amount(self):
     from electrum.transaction import PartialTxOutput
     if run_hook('abort_send', self):
         return ''
     inputs = self.wallet.get_spendable_coins(None)
     if not inputs:
         return ''
     addr = None
     if self.send_screen:
         addr = str(self.send_screen.screen.address)
     if not addr:
         addr = self.wallet.dummy_address()
     outputs = [PartialTxOutput.from_address_and_value(addr, '!')]
     try:
         tx = self.wallet.make_unsigned_transaction(coins=inputs,
                                                    outputs=outputs)
     except NoDynamicFeeEstimates as e:
         Clock.schedule_once(
             lambda dt, bound_e=e: self.show_error(str(bound_e)))
         return ''
     except NotEnoughFunds:
         return ''
     except InternalAddressCorruption as e:
         self.show_error(str(e))
         send_exception_to_crash_reporter(e)
         return ''
     amount = tx.output_value()
     __, x_fee_amount = run_hook('get_tx_extra_fee', self.wallet,
                                 tx) or (None, 0)
     amount_after_all_fees = amount - x_fee_amount
     return format_satoshis_plain(amount_after_all_fees,
                                  self.decimal_point())
Example #4
0
    def make_tx(self, amount):
        self._logger.debug('make_tx amount = %s' % str(amount))

        if self.f_make_tx:
            tx = self.f_make_tx(amount)
        else:
            # default impl
            coins = self._wallet.wallet.get_spendable_coins(None)
            outputs = [
                PartialTxOutput.from_address_and_value(self.address, amount)
            ]
            tx = self._wallet.wallet.make_unsigned_transaction(coins=coins,
                                                               outputs=outputs,
                                                               fee=None,
                                                               rbf=self._rbf)

        self._logger.debug('fee: %d, inputs: %d, outputs: %d' %
                           (tx.get_fee(), len(tx.inputs()), len(tx.outputs())))

        outputs = []
        for o in tx.outputs():
            outputs.append({
                'address':
                o.get_ui_address_str(),
                'value_sats':
                o.value,
                'is_mine':
                self._wallet.wallet.is_mine(o.get_ui_address_str())
            })
        self.outputs = outputs

        return tx
Example #5
0
 def update_tx(self, onchain_amount):
     if onchain_amount is None:
         self.tx = None
         return
     outputs = [PartialTxOutput.from_address_and_value(ln_dummy_address(), onchain_amount)]
     coins = self.window.get_coins()
     self.tx = self.window.wallet.make_unsigned_transaction(
         coins=coins,
         outputs=outputs)
Example #6
0
    def do_send(self):
        if not is_address(self.str_recipient):
            print(_('Invalid address'))
            return
        try:
            amount = int(Decimal(self.str_amount) * COIN)
        except Exception:
            print(_('Invalid Amount'))
            return
        try:
            fee = int(Decimal(self.str_fee) * COIN)
        except Exception:
            print(_('Invalid Fee'))
            return

        if self.wallet.has_password():
            password = self.password_dialog()
            if not password:
                return
        else:
            password = None

        c = ""
        while c != "y":
            c = input("ok to send (y/n)?")
            if c == "n": return

        try:
            tx = self.wallet.mktx(outputs=[
                PartialTxOutput.from_address_and_value(self.str_recipient,
                                                       amount)
            ],
                                  password=password,
                                  fee=fee)
        except Exception as e:
            print(repr(e))
            return

        if self.str_description:
            self.wallet.labels[tx.txid()] = self.str_description

        print(_("Please wait..."))
        try:
            self.network.run_from_another_thread(
                self.network.broadcast_transaction(tx))
        except TxBroadcastError as e:
            msg = e.get_message_for_gui()
            print(msg)
        except BestEffortRequestFailed as e:
            msg = repr(e)
            print(msg)
        else:
            print(_('Payment sent.'))
Example #7
0
 def update_tx(self, onchain_amount):
     if onchain_amount is None:
         self.tx = None
         self.ok_button.setEnabled(False)
         return
     outputs = [PartialTxOutput.from_address_and_value(ln_dummy_address(), onchain_amount)]
     coins = self.window.get_coins()
     try:
         self.tx = self.window.wallet.make_unsigned_transaction(
             coins=coins,
             outputs=outputs)
     except (NotEnoughFunds, NoDynamicFeeEstimates) as e:
         self.tx = None
         self.ok_button.setEnabled(False)
Example #8
0
    def do_send(self):
        if not is_address(self.str_recipient):
            self.show_message(
                _('Invalid {name} address').format(name=constants.net.NAME))
            return
        try:
            amount = int(Decimal(self.str_amount) * constants.net.COIN)
        except Exception:
            self.show_message(_('Invalid Amount'))
            return
        try:
            fee = int(Decimal(self.str_fee) * constants.net.COIN)
        except Exception:
            self.show_message(_('Invalid Fee'))
            return

        if self.wallet.has_password():
            password = self.password_dialog()
            if not password:
                return
        else:
            password = None
        try:
            tx = self.wallet.mktx(outputs=[
                PartialTxOutput.from_address_and_value(self.str_recipient,
                                                       amount)
            ],
                                  password=password,
                                  fee=fee)
        except Exception as e:
            self.show_message(repr(e))
            return

        if self.str_description:
            self.wallet.labels[tx.txid()] = self.str_description

        self.show_message(_("Please wait..."), getchar=False)
        try:
            self.network.run_from_another_thread(
                self.network.broadcast_transaction(tx))
        except TxBroadcastError as e:
            msg = e.get_message_for_gui()
            self.show_message(msg)
        except BestEffortRequestFailed as e:
            msg = repr(e)
            self.show_message(msg)
        else:
            self.show_message(_('Payment sent.'))
            self.do_clear()
Example #9
0
 def update_tx(self, onchain_amount: Union[int, str]):
     """Updates the transaction associated with a forward swap."""
     if onchain_amount is None:
         self.tx = None
         self.ids.ok_button.disabled = True
         return
     outputs = [PartialTxOutput.from_address_and_value(ln_dummy_address(), onchain_amount)]
     coins = self.app.wallet.get_spendable_coins(None)
     try:
         self.tx = self.app.wallet.make_unsigned_transaction(
             coins=coins,
             outputs=outputs)
     except (NotEnoughFunds, NoDynamicFeeEstimates):
         self.tx = None
         self.ids.ok_button.disabled = True
Example #10
0
 def _update_tx(self, onchain_amount):
     """Updates self.tx. No other side-effects."""
     if self.is_reverse:
         return
     if onchain_amount is None:
         self.tx = None
         return
     outputs = [
         PartialTxOutput.from_address_and_value(ln_dummy_address(),
                                                onchain_amount)
     ]
     coins = self.window.get_coins()
     try:
         self.tx = self.window.wallet.make_unsigned_transaction(
             coins=coins, outputs=outputs)
     except (NotEnoughFunds, NoDynamicFeeEstimates) as e:
         self.tx = None
Example #11
0
    def save_invoice(self):
        assert self.canSave
        assert not self._amount.isMax

        self._logger.debug('saving invoice to %s, amount=%s, message=%s' % (self._recipient, repr(self._amount), self._message))

        inv_amt = self._amount.satsInt

        try:
            outputs = [PartialTxOutput.from_address_and_value(self._recipient, inv_amt)]
            self._logger.debug(repr(outputs))
            invoice = self._wallet.wallet.create_invoice(outputs=outputs, message=self._message, pr=None, URI=None)
        except InvoiceError as e:
            self.invoiceCreateError.emit('fatal', _('Error creating payment') + ':\n' + str(e))
            return

        self.key = self._wallet.wallet.get_key_for_outgoing_invoice(invoice)
        self._wallet.wallet.save_invoice(invoice)
        self.invoiceSaved.emit()
Example #12
0
    def send_onchain(self, address, amount, fee=None, rbf=False):
        self._logger.info('send_onchain: %s %d' % (address, amount))
        coins = self.wallet.get_spendable_coins(None)
        if not bitcoin.is_address(address):
            self._logger.warning('Invalid Bitcoin Address: ' + address)
            return False

        outputs = [PartialTxOutput.from_address_and_value(address, amount)]
        self._logger.info(str(outputs))
        output_values = [x.value for x in outputs]
        if any(parse_max_spend(outval) for outval in output_values):
            output_value = '!'
        else:
            output_value = sum(output_values)
        self._logger.info(str(output_value))
        # see qt/confirm_tx_dialog qt/main_window
        tx = self.wallet.make_unsigned_transaction(coins=coins,
                                                   outputs=outputs,
                                                   fee=None)
        self._logger.info(str(tx.to_json()))

        use_rbf = bool(self.wallet.config.get('use_rbf', True))
        tx.set_rbf(use_rbf)
        self.sign_and_broadcast(tx)
Example #13
0
    def validateRecipient(self, recipient):
        if not recipient:
            self.setInvoiceType(QEInvoice.Type.Invalid)
            return

        maybe_lightning_invoice = recipient

        def _payment_request_resolved(request):
            self._logger.debug('resolved payment request')
            outputs = request.get_outputs()
            invoice = self.create_onchain_invoice(outputs, None, request, None)
            self.setValidOnchainInvoice(invoice)

        try:
            self._bip21 = parse_URI(recipient, _payment_request_resolved)
            if self._bip21:
                if 'r' in self._bip21 or ('name' in self._bip21 and 'sig' in self._bip21): # TODO set flag in util?
                    # let callback handle state
                    return
                if ':' not in recipient:
                    # address only
                    self.setValidAddressOnly()
                    self.validationSuccess.emit()
                    return
                else:
                    # fallback lightning invoice?
                    if 'lightning' in self._bip21:
                        maybe_lightning_invoice = self._bip21['lightning']
        except InvalidBitcoinURI as e:
            self._bip21 = None
            self._logger.debug(repr(e))

        lninvoice = None
        maybe_lightning_invoice = maybe_extract_lightning_payment_identifier(maybe_lightning_invoice)
        if maybe_lightning_invoice is not None:
            try:
                lninvoice = Invoice.from_bech32(maybe_lightning_invoice)
            except InvoiceError as e:
                e2 = e.__cause__
                if isinstance(e2, LnInvoiceException):
                    self.validationError.emit('unknown', _("Error parsing Lightning invoice") + f":\n{e2}")
                    self.clear()
                    return
                if isinstance(e2, lnutil.IncompatibleOrInsaneFeatures):
                    self.validationError.emit('unknown', _("Invoice requires unknown or incompatible Lightning feature") + f":\n{e2!r}")
                    self.clear()
                    return
                self._logger.exception(repr(e))

        if not lninvoice and not self._bip21:
            self.validationError.emit('unknown',_('Unknown invoice'))
            self.clear()
            return

        if lninvoice:
            if not self._wallet.wallet.has_lightning():
                if not self._bip21:
                    # TODO: lightning onchain fallback in ln invoice
                    #self.validationError.emit('no_lightning',_('Detected valid Lightning invoice, but Lightning not enabled for wallet'))
                    self.setValidLightningInvoice(lninvoice)
                    self.clear()
                    return
                else:
                    self._logger.debug('flow with LN but not LN enabled AND having bip21 uri')
                    self.setValidOnchainInvoice(self._bip21['address'])
            else:
                self.setValidLightningInvoice(lninvoice)
                if not self._wallet.wallet.lnworker.channels:
                    self.validationWarning.emit('no_channels',_('Detected valid Lightning invoice, but there are no open channels'))
                else:
                    self.validationSuccess.emit()
        else:
            self._logger.debug('flow without LN but having bip21 uri')
            if 'amount' not in self._bip21: #TODO can we have amount-less invoices?
                self.validationError.emit('no_amount', 'no amount in uri')
                return
            outputs = [PartialTxOutput.from_address_and_value(self._bip21['address'], self._bip21['amount'])]
            self._logger.debug(outputs)
            message = self._bip21['message'] if 'message' in self._bip21 else ''
            invoice = self.create_onchain_invoice(outputs, message, None, self._bip21)
            self._logger.debug(repr(invoice))
            self.setValidOnchainInvoice(invoice)
            self.validationSuccess.emit()
Example #14
0
locktime = 1602565200

# Build the Transaction Input
_, privkey, compressed = deserialize_privkey(wif)
pubkey = ECPrivkey(privkey).get_public_key_hex(compressed=compressed)
prevout = TxOutpoint(txid=txid, out_idx=vout)
txin = PartialTxInput(prevout=prevout)
txin.nsequence = sequence
txin.script_type = script_type
expiry = b2x(lx(b2x(locktime)))
redeem_script = compile([
    expiry, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', pubkey, 'OP_CHECKSIG'])
txin.redeem_script = x(redeem_script)

# Build the Transaction Output
txout = PartialTxOutput.from_address_and_value(address, sats_less_fees)

# Build and sign the transaction
tx = P2SHPartialTransaction.from_io([txin], [txout], locktime=locktime)
tx.version = 1
sig = tx.sign_txin(0, privkey)
txin.script_sig = x(compile([sig , redeem_script]))

# Get the serialized txn and compute txid
txn = tx.serialize()
txid = b2lx(sha256d(x(txn)))

# Ensure we arrived at where we intended
if txid != otxid:
    print("Did not achive target TXID hash")
    print("Perhaps R-value hashing needs to be reverted")