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 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 #3
0
 def parse_address_and_amount(self, line) -> PartialTxOutput:
     x, y = line.split(',')
     scriptpubkey = self.parse_output(x)
     amount = self.parse_amount(y)
     return PartialTxOutput(scriptpubkey=scriptpubkey,
                            value=amount,
                            is_display=True)
Example #4
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 #5
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)
    def get_outputs(self, is_max):
        if self.payto_scriptpubkey:
            asset = self.win.get_asset_from_spend_tab()
            script = self.payto_scriptpubkey
            if is_max:
                amount_rval = sum([
                    txin.value_sats()
                    for txin in self.win.get_coins(asset=asset)
                ], RavenValue())
                if asset:
                    amount = amount_rval.assets.get(asset, Satoshis(0))
                else:
                    amount = amount_rval.rvn_value
            else:
                amount = Satoshis(self.amount_edit.get_amount())
            if asset:
                script = assets.create_transfer_asset_script(
                    script, asset, amount)
            if amount == 0:
                self.errors.append(
                    PayToLineError('The amount cannot be 0.', None))
                return []
            self.outputs = [
                PartialTxOutput(scriptpubkey=script,
                                value=amount,
                                asset=asset,
                                is_max=is_max)
            ]

        return self.outputs[:]
Example #7
0
 def parse_address_and_amount(self, line) -> PartialTxOutput:
     try:
         x, y = line.split(',')
     except ValueError:
         raise Exception("expected two comma-separated values: (address, amount)") from None
     scriptpubkey = self.parse_output(x)
     amount = self.parse_amount(y)
     return PartialTxOutput(scriptpubkey=scriptpubkey, value=amount)
 def parse_address_and_amount(self, line) -> PartialTxOutput:
     try:
         x, y = line.split(',')
     except ValueError:
         raise Exception(
             "expected two comma-separated values: (address, amount)"
         ) from None
     scriptpubkey = self.parse_output(x)
     amount = self.parse_amount(y)
     asset = self.win.get_asset_from_spend_tab()
     if asset is not None:
         script = assets.create_transfer_asset_script(
             scriptpubkey, asset, amount)
         return PartialTxOutput(scriptpubkey=script,
                                value=amount,
                                asset=asset)
     else:
         return PartialTxOutput(scriptpubkey=scriptpubkey, value=amount)
Example #9
0
    def get_outputs(self, is_max):
        if self.payto_scriptpubkey:
            if is_max:
                amount = '!'
            else:
                amount = self.amount_edit.get_amount()
            self.outputs = [PartialTxOutput(scriptpubkey=self.payto_scriptpubkey, value=amount)]

        return self.outputs[:]
Example #10
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 #11
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 #12
0
    def get_outputs(self, is_max: bool) -> List[PartialTxOutput]:
        if self.payto_scriptpubkey:
            if is_max:
                amount = '!'
            else:
                amount = self.amount_edit.get_amount()
                if amount is None:
                    return []
            self.outputs = [
                PartialTxOutput(scriptpubkey=self.payto_scriptpubkey,
                                value=amount)
            ]

        return self.outputs[:]
Example #13
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 #14
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 #15
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 #16
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 #17
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 #18
0
 def do_send(self):
     from electrum.bitcoin import is_p2pkh, is_hash160, b58_address_to_hash160, bh2u, TYPE_SCRIPT
     from electrum.transaction import opcodes, contract_script, PartialTxOutput
     address = str(self.to_addr)
     if not address:
         self.app.show_error(
             _('Recipient not specified.') + ' ' +
             _('Please scan a Bitcoin address or a payment request'))
         return
     if is_p2pkh(address):
         addr_type, hash160 = b58_address_to_hash160(address)
         hash160 = bh2u(hash160)
     elif is_hash160(address):
         hash160 = address.lower()
     else:
         self.app.show_error(_('Invalid Bitcoin Address') + ':\n' + address)
         return
     if address == self.bind_addr:
         self.app.show_error(_('You can not send to bind address!'))
         return
     try:
         amount = self.app.get_token_amount(self.amount, self.symbol,
                                            self.decimals)
     except:
         self.app.show_error(
             _('Invalid amount') + ':\n' + self.screen.amount)
         return
     if self.balance < amount:
         self.app.show_error(_('token not enough'))
         return
     datahex = 'a9059cbb{}{:064x}'.format(hash160.zfill(64), amount)
     tx_desc = _('Pay out {} {}').format(amount / (10**self.decimals),
                                         self.symbol)
     gas_limit = int(self.gas_limit)
     gas_price = int(float(self.gas_price) * (10**8))
     script = contract_script(gas_limit, gas_price, datahex,
                              self.contract_addr, opcodes.OP_CALL)
     outputs = [PartialTxOutput(scriptpubkey=script, value=0)]
     amount = sum(map(lambda x: x[2], outputs))
     self._do_send(amount, tx_desc, outputs, gas_limit * gas_price)
Example #19
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 #20
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")
Example #21
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()