def test_payto(self, mock_save_db):
        wallet = restore_wallet_from_text('ignore hospital shallow unit river glue battle chat pet option position icon',
                                          gap_limit=2,
                                          path='if_this_exists_mocking_failed_648151893',
                                          config=self.config)['wallet']
        # bootstrap wallet
        funding_tx = Transaction('0200000001688b4db66baaae1dde4a59aaccc1282757db5b192033a8d41718cd9e3949f7d2050000006a47304402203f8fca0aa5ef38d20e275d3c7cf191ce56e5f12e351ffa12f0a667440374ef7a0220206ef46cf234a35b7f4e3f062c99a118966403f9e788ec870d93114dd20081fa01210211db4efc20880c5b57cfa947550a7f337c99adf5c11999de380e2e4e196eebcefeffffff02ac150700000000001976a914eb9fad52a0664d10798fdcc0c4776ef07d910d7788acbc2b0800000000001976a914a9262375de5f7a2c81e0d28f3c6ab42e594627e888acea0e0800')
        funding_txid = funding_tx.txid()
        self.assertEqual('2304741a3b690d5c52bac443792e9ec6af535b527c562899b36e72e8c4e3bf4f', funding_txid)
        wallet.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED)

        cmds = Commands(config=self.config)
        tx_str = cmds._run(
            'payto', (),
            destination="yR41Y7aXsoYCSugFhXJ2DU5asRtW1rpzV3",
            amount="0.00123456",
            feerate=1000,
            locktime=1972344,
            wallet=wallet)

        tx = tx_from_any(tx_str)
        self.assertEqual(2, len(tx.outputs()))
        txout = TxOutput.from_address_and_value("yR41Y7aXsoYCSugFhXJ2DU5asRtW1rpzV3", 123456)
        self.assertTrue(txout in tx.outputs())
        self.assertEqual("02000000014fbfe3c4e8726eb39928567c525b53afc69e2e7943c4ba525c0d693b1a740423000000006a4730440220234aa5fe38e0d99013fb1427a0998560f513b26c37a1e53540da5b9b7859c0540220316735a04e115941b3f62e54f7f30473bf44c483eef335e702d542b8d6e81f3e0121025837acda77e6b2295e03c50c356057e3f2ec8d6c498ba9351618ee913510daa3feffffff0240e20100000000001976a91433ed429c95e392a27f1194b400b07cff5167284588ac8a320500000000001976a9144ee5b85791f50a4270ad7277ff307fd66f7254e188ac78181e00",
                         tx_str)
        assert  tx_from_any(tx_str).is_complete()
 def input_script(self, txin, estimate_size=False):
     if txin['type'] == 'p2pkh':
         return Transaction.get_preimage_script(txin)
     if txin['type'] == 'p2sh':
         # Multisig verification has partial support, but is disabled. This is the
         # expected serialization though, so we leave it here until we activate it.
         return '00' + push_script(Transaction.get_preimage_script(txin))
     raise Exception("unsupported type %s" % txin['type'])
Beispiel #3
0
 def input_script(self, txin, estimate_size=False):
     if txin['type'] == 'p2pkh':
         return Transaction.get_preimage_script(txin)
     if txin['type'] == 'p2sh':
         # Multisig verification has partial support, but is disabled. This is the
         # expected serialization though, so we leave it here until we activate it.
         return '00' + push_script(Transaction.get_preimage_script(txin))
     raise Exception("unsupported type %s" % txin['type'])
Beispiel #4
0
 def test_restoring_wallet_without_manual_delete(self, mock_write):
     w = restore_wallet_from_text("hint shock chair puzzle shock traffic drastic note dinosaur mention suggest sweet",
                                  path='if_this_exists_mocking_failed_648151893',
                                  gap_limit=5)['wallet']
     for txid in self.transactions:
         tx = Transaction(self.transactions[txid])
         w.add_transaction(tx.txid(), tx)
     # txn A is an external incoming txn funding the wallet
     # txn B is an outgoing payment to an external address
     # txn C is double-spending txn B, to a wallet address
     self.assertEqual(83500163, sum(w.get_balance()))
Beispiel #5
0
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return
        if not self.check_proper_device():
            give_error('Wrong device or password')
        # previous transactions used as inputs
        prev_tx = {}
        # path of the xpubs that are involved
        xpub_path = {}
        for txin in tx.inputs:
            tx_hash = txin['prevout_hash']

            ptx = self.transactions.get(tx_hash)
            if ptx is None:
                ptx = self.network.synchronous_get([
                    ('blockchain.transaction.get', [tx_hash])
                ])[0]
                ptx = Transaction(ptx)
            prev_tx[tx_hash] = ptx

            for x_pubkey in txin['x_pubkeys']:
                if not is_extended_pubkey(x_pubkey):
                    continue
                xpub = x_to_xpub(x_pubkey)
                for k, v in self.master_public_keys.items():
                    if v == xpub:
                        account_id = re.match("x/(\d+)'", k).group(1)
                        account_derivation = "44'/5'/%s'" % account_id
                xpub_path[xpub] = account_derivation

        self.plugin.sign_transaction(tx, prev_tx, xpub_path)
Beispiel #6
0
 def test_dsa_msg(self):
     msg = DashDsaMsg.from_hex(DSA_MSG)
     assert msg.nDenom == 2
     assert type(msg.txCollateral) == str
     tx = Transaction(msg.txCollateral)
     assert type(tx) == Transaction
     assert bh2u(msg.serialize()) == DSA_MSG
Beispiel #7
0
 def input_script(self,
                  txin: PartialTxInput,
                  *,
                  estimate_size=False):
     if txin.script_type == 'p2pkh':
         return Transaction.get_preimage_script(txin)
     raise Exception("unsupported type %s" % txin.script_type)
Beispiel #8
0
 def do_paste(self):
     data = self.app._clipboard.paste()
     if not data:
         self.app.show_info(_("Clipboard is empty"))
         return
     # try to decode as transaction
     try:
         raw_tx = tx_from_str(data)
         tx = Transaction(raw_tx)
         tx.deserialize()
     except:
         tx = None
     if tx:
         self.app.tx_dialog(tx)
         return
     # try to decode as URI/address
     self.set_URI(data)
    def export_to_file(self, *, tx: Transaction = None):
        if tx is None:
            tx = self.tx
        if isinstance(tx, PartialTransaction):
            tx.finalize_psbt()
        if tx.is_complete():
            name = 'signed_%s' % (tx.txid()[0:8])
            extension = 'txn'
            default_filter = TRANSACTION_FILE_EXTENSION_FILTER_ONLY_COMPLETE_TX
        else:
            name = self.wallet.basename() + time.strftime('-%Y%m%d-%H%M')
            extension = 'psbt'
            default_filter = TRANSACTION_FILE_EXTENSION_FILTER_ONLY_PARTIAL_TX
        name = f'{name}.{extension}'
        fileName = self.main_window.getSaveFileName(
            _("Select where to save your transaction"),
            name,
            TRANSACTION_FILE_EXTENSION_FILTER_SEPARATE,
            default_extension=extension,
            default_filter=default_filter)
        if not fileName:
            return
        if tx.is_complete():  # network tx hex
            with open(fileName, "w+") as f:
                network_tx_hex = tx.serialize_to_network()
                f.write(network_tx_hex + '\n')
        else:  # if partial: PSBT bytes
            assert isinstance(tx, PartialTransaction)
            with open(fileName, "wb+") as f:
                f.write(tx.serialize_as_bytes())

        self.show_message(_("Transaction exported successfully"))
        self.saved = True
Beispiel #10
0
def is_any_tx_output_on_change_branch(tx: Transaction):
    if not tx.output_info:
        return False
    for o in tx.outputs():
        info = tx.output_info.get(o.address)
        if info is not None:
            if info.address_index[0] == 1:
                return True
    return False
    def test_signtransaction_with_wallet(self, mock_save_db):
        wallet = restore_wallet_from_text('nest trophy glide lemon humor rose faint able keep squirrel major inform',
                                          gap_limit=2, path='if_this_exists_mocking_failed_648151893',
                                          config=self.config)['wallet']
        # bootstrap wallet1
        funding_tx = Transaction('0200000003912b2b205a528c5e875f9a64c1105217061135a9539e64c1953e40f9a7f9ec80000000006a473044022077d3ad93dc64e86cb7a3d754fc4fa7c5ffd8d86419f64b223939619e63dc0e0702202b6023914d57ea73c03a49af2512db6c2bf6f5280551f73c8da033128012a30f012102bc67dbfecc27341ee81a04029fb2e7c8e1280789cbe785bdab6e0673f1c785b9feffffff0e6c1fb9ced6f9595a6598b730d07a322461ec8e8556629be050129d5f95768b000000006a47304402204390383ecc05cd44d40c416c8bd748c7605636138d79c511f63563a989845ecd0220634d55c886988220bd57fe524c4ec152db9ee8f545350be6c74402c8151fa733012102bc67dbfecc27341ee81a04029fb2e7c8e1280789cbe785bdab6e0673f1c785b9feffffff688b4db66baaae1dde4a59aaccc1282757db5b192033a8d41718cd9e3949f7d2000000006a47304402206d9f25099d8a74ada78ce88b80ae5b6bdbfd563805d2cf7509ebdabaed8414ba02200ddff1fff3cf3d23684554097a7c85683f7bf93113833c5c78f6538141b3f4360121028bc7e29feff7fd705f2eec7820702ed9d62ef4f8edd32ac2d4094eee099fbb42feffffff022bd00200000000001976a914a9262375de5f7a2c81e0d28f3c6ab42e594627e888ac40420f00000000001976a914ebba561d2da1ed2a43b2cbbd45607a9d9c8e47de88ace80e0800')
        funding_txid = funding_tx.txid()
        funding_output_value = 1000000
        self.assertEqual('ebf85f1ef2573600e0038cfbb57b17b80965bccc95ece63e5cad81352493fd2f', funding_txid)
        wallet.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED)

        cmds = Commands(config=self.config)

        unsigned_tx = "cHNidP8BAFUCAAAAAW257E6UZwYN8f8oSrXTHHQhrK00vYMrFSVIFaLNuBzvAQAAAAD+////AYBBDwAAAAAAGXapFIEDYGhr7BAsosv+fSX+OJesHBTliKzoDggAAAEA/QcCAgAAAAORKysgWlKMXodfmmTBEFIXBhE1qVOeZMGVPkD5p/nsgAAAAABqRzBEAiA/YGaD9myM7jsgAKGPTkZkhAR83JfJ8AgnPhogmwI5AwIgZjnryK4gKljX0J6zkaQ1Isz1MA/GbPWbefza/pN3wFEBIQK8Z9v+zCc0HugaBAKfsufI4SgHicvnhb2rbgZz8ceFuf7///8ObB+5ztb5WVplmLcw0HoyJGHsjoVWYpvgUBKdX5V2iwAAAABqRzBEAiBbdcP7jckAeGXZXHp46ZBH4U1bDq8Zp+RQpVitjDaKBgIgRQ4D0fNZSOhB4BH2PN9WyXUKoFoCks5w5iIeBsxNXYUBIQK8Z9v+zCc0HugaBAKfsufI4SgHicvnhb2rbgZz8ceFuf7///9oi022a6quHd5KWarMwSgnV9tbGSAzqNQXGM2eOUn30gMAAABqRzBEAiAyuysUoJnTDUDGk4/fmHYx0aKYU2bNrSYwXzDwNAZPKgIgBnE5zJCd/euIA+veCqKLyS5GhMcsFurnvYM172pmWjsBIQI1+Z+RoF3aiVvdC4tijoYUrgvwX+/3/opJHVizOvOetv7///8CK9ACAAAAAAAZdqkUqSYjdd5feiyB4NKPPGq0LllGJ+iIrEBCDwAAAAAAGXapFOu6Vh0toe0qQ7LLvUVgep2cjkfeiKzoDggAIgYCtmt/3e46deXJByeDz2ClAftD16M6V+F+707JwW33iI8MUH3lsAAAAAAAAAAAACICAgtxqKxniaqjNXAhaSoUrgiutogL+DmPN+ilU/46YWm6DFB95bAAAAAAAQAAAAA="

        tx_str = cmds._run('signtransaction', (), tx=unsigned_tx, wallet=wallet)
        self.assertEqual("02000000016db9ec4e9467060df1ff284ab5d31c7421acad34bd832b15254815a2cdb81cef010000006a47304402204be923230cfe88dc76a140f68c99f1df62b3567619279f5ba042123a0ce53a0b02204c5fe44e2395896b15db968c07937c7b7c1bfc7243540a4079a675eea0085579012102b66b7fddee3a75e5c9072783cf60a501fb43d7a33a57e17eef4ec9c16df7888ffeffffff0180410f00000000001976a914810360686bec102ca2cbfe7d25fe3897ac1c14e588ace80e0800",
                         tx_str)
        assert  tx_from_any(tx_str).is_complete()
Beispiel #12
0
 def show_qr(self, *, tx: Transaction = None):
     if tx is None:
         tx = self.tx
     qr_data = tx.to_qr_data()
     try:
         self.main_window.show_qrcode(qr_data, 'Transaction', parent=self)
     except qrcode.exceptions.DataOverflowError:
         self.show_error(_('Failed to display QR code.') + '\n' +
                         _('Transaction is too large in size.'))
     except Exception as e:
         self.show_error(_('Failed to display QR code.') + '\n' + repr(e))
Beispiel #13
0
 def test_dsi_msg(self):
     msg = DashDsiMsg.from_hex(DSI_MSG)
     assert len(msg.vecTxDSIn) == 2
     for txin in msg.vecTxDSIn:
         assert type(txin) == CTxIn
     assert type(msg.txCollateral) == str
     tx = Transaction(msg.txCollateral)
     assert type(tx) == Transaction
     assert len(msg.vecTxDSOut) == 2
     for txout in msg.vecTxDSOut:
         assert type(txout) == CTxOut
     assert bh2u(msg.serialize()) == DSI_MSG
Beispiel #14
0
 def test_restoring_wallet_with_manual_delete(self, mock_write):
     w = restore_wallet_from_text("hint shock chair puzzle shock traffic drastic note dinosaur mention suggest sweet",
                                  path='if_this_exists_mocking_failed_648151893',
                                  gap_limit=5)['wallet']
     # txn A is an external incoming txn funding the wallet
     txA = Transaction(self.transactions["0cce62d61ec87ad3e391e8cd752df62e0c952ce45f52885d6d10988e02794060"])
     w.add_transaction(txA.txid(), txA)
     # txn B is an outgoing payment to an external address
     txB = Transaction(self.transactions["e7f4e47f41421e37a8600b6350befd586f30db60a88d0992d54df280498f0968"])
     w.add_transaction(txB.txid(), txB)
     # now the user manually deletes txn B to attempt the double spend
     # txn C is double-spending txn B, to a wallet address
     # rationale1: user might do this with opt-in RBF transactions
     # rationale2: this might be a local transaction, in which case the GUI even allows it
     w.remove_transaction(txB)
     txC = Transaction(self.transactions["a04328fbc9f28268378a8b9cf103db21ca7d673bf1cc7fa4d61b6a7265f07a6b"])
     w.add_transaction(txC.txid(), txC)
     self.assertEqual(83500163, sum(w.get_balance()))
 def on_qr(self, data):
     from electrum_dash.bitcoin import base_decode, is_address
     data = data.strip()
     if is_address(data):
         self.set_URI(data)
         return
     if data.startswith('dash:'):
         self.set_URI(data)
         return
     # try to decode transaction
     from electrum_dash.transaction import Transaction
     try:
         text = base_decode(data, None, base=43).encode('hex')
         tx = Transaction(text)
         tx.deserialize()
     except:
         tx = None
     if tx:
         self.tx_dialog(tx)
         return
     # show error
     self.show_error("Unable to decode QR data")
Beispiel #16
0
 def on_qr(self, data):
     from electrum_dash.bitcoin import base_decode, is_address
     data = data.strip()
     if is_address(data):
         self.set_URI(data)
         return
     if data.startswith('dash:'):
         self.set_URI(data)
         return
     # try to decode transaction
     from electrum_dash.transaction import Transaction
     from electrum_dash.util import bh2u
     try:
         text = bh2u(base_decode(data, None, base=43))
         tx = Transaction(text)
         tx.deserialize()
     except:
         tx = None
     if tx:
         self.tx_dialog(tx)
         return
     # show error
     self.show_error("Unable to decode QR data")
Beispiel #17
0
    def tx_inputs(self,
                  tx: Transaction,
                  *,
                  for_sig=False,
                  keystore: 'SafeTKeyStore' = None):
        inputs = []
        for txin in tx.inputs():
            txinputtype = self.types.TxInputType()
            if txin.is_coinbase_input():
                prev_hash = b"\x00" * 32
                prev_index = 0xffffffff  # signed int -1
            else:
                if for_sig:
                    assert isinstance(tx, PartialTransaction)
                    assert isinstance(txin, PartialTxInput)
                    assert keystore
                    if len(txin.pubkeys) > 1:
                        xpubs_and_deriv_suffixes = get_xpubs_and_der_suffixes_from_txinout(
                            tx, txin)
                        multisig = self._make_multisig(
                            txin.num_sig, xpubs_and_deriv_suffixes)
                    else:
                        multisig = None
                    script_type = self.get_safet_input_script_type(
                        txin.script_type)
                    txinputtype = self.types.TxInputType(
                        script_type=script_type, multisig=multisig)
                    my_pubkey, full_path = keystore.find_my_pubkey_in_txinout(
                        txin)
                    if full_path:
                        txinputtype._extend_address_n(full_path)

                prev_hash = txin.prevout.txid
                prev_index = txin.prevout.out_idx

            if txin.value_sats() is not None:
                txinputtype.amount = txin.value_sats()
            txinputtype.prev_hash = prev_hash
            txinputtype.prev_index = prev_index

            if txin.script_sig is not None:
                txinputtype.script_sig = txin.script_sig

            txinputtype.sequence = txin.nsequence

            inputs.append(txinputtype)

        return inputs
Beispiel #18
0
    def export_to_file(self, *, tx: Transaction = None):
        if tx is None:
            tx = self.tx
        if isinstance(tx, PartialTransaction):
            tx.finalize_psbt()
        txid = tx.txid()
        suffix = txid[0:8] if txid is not None else time.strftime(
            '%Y%m%d-%H%M')
        if tx.is_complete():
            extension = 'txn'
            default_filter = TRANSACTION_FILE_EXTENSION_FILTER_ONLY_COMPLETE_TX
        else:
            extension = 'psbt'
            default_filter = TRANSACTION_FILE_EXTENSION_FILTER_ONLY_PARTIAL_TX
        name = f'{self.wallet.basename()}-{suffix}.{extension}'
        fileName = getSaveFileName(
            parent=self,
            title=_("Select where to save your transaction"),
            filename=name,
            filter=TRANSACTION_FILE_EXTENSION_FILTER_SEPARATE,
            default_extension=extension,
            default_filter=default_filter,
            config=self.config,
        )
        if not fileName:
            return
        if tx.is_complete():  # network tx hex
            with open(fileName, "w+") as f:
                network_tx_hex = tx.serialize_to_network()
                f.write(network_tx_hex + '\n')
        else:  # if partial: PSBT bytes
            assert isinstance(tx, PartialTransaction)
            with open(fileName, "wb+") as f:
                f.write(tx.serialize_as_bytes())

        self.show_message(_("Transaction exported successfully"))
        self.saved = True
Beispiel #19
0
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return
        client = self.get_client()
        self.signing = True
        inputs = []
        inputsPaths = []
        pubKeys = []
        chipInputs = []
        redeemScripts = []
        signatures = []
        preparedTrustedInputs = []
        changePath = ""
        changeAmount = None
        output = None
        outputAmount = None
        p2shTransaction = False
        pin = ""
        self.get_client(
        )  # prompt for the PIN before displaying the dialog if necessary

        # Fetch inputs of the transaction to sign
        derivations = self.get_tx_derivations(tx)
        for txin in tx.inputs():
            if txin['type'] == 'coinbase':
                self.give_error(
                    "Coinbase not supported")  # should never happen

            if txin['type'] in ['p2sh']:
                p2shTransaction = True

            pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin)
            for i, x_pubkey in enumerate(x_pubkeys):
                if x_pubkey in derivations:
                    signingPos = i
                    s = derivations.get(x_pubkey)
                    hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], s[0],
                                              s[1])
                    break
            else:
                self.give_error("No matching x_key for sign_transaction"
                                )  # should never happen

            redeemScript = Transaction.get_preimage_script(txin)
            inputs.append([
                txin['prev_tx'].raw, txin['prevout_n'], redeemScript,
                txin['prevout_hash'], signingPos,
                txin.get('sequence', 0xffffffff - 1)
            ])
            inputsPaths.append(hwAddress)
            pubKeys.append(pubkeys)

        # Sanity check
        if p2shTransaction:
            for txin in tx.inputs():
                if txin['type'] != 'p2sh':
                    self.give_error(
                        "P2SH / regular input mixed in same transaction not supported"
                    )  # should never happen

        txOutput = var_int(len(tx.outputs()))
        for txout in tx.outputs():
            output_type, addr, amount = txout
            txOutput += int_to_hex(amount, 8)
            script = tx.pay_script(output_type, addr)
            txOutput += var_int(len(script) // 2)
            txOutput += script
        txOutput = bfh(txOutput)

        # Recognize outputs - only one output and one change is authorized
        if not p2shTransaction:
            if not self.get_client_electrum().supports_multi_output():
                if len(tx.outputs()) > 2:
                    self.give_error(
                        "Transaction with more than 2 outputs not supported")
            for _type, address, amount in tx.outputs():
                assert _type == TYPE_ADDRESS
                info = tx.output_info.get(address)
                if (info is not None) and (len(tx.outputs()) != 1):
                    index, xpubs, m = info
                    changePath = self.get_derivation()[2:] + "/%d/%d" % index
                    changeAmount = amount
                else:
                    output = address
                    if not self.get_client_electrum().canAlternateCoinVersions:
                        v, h = b58_address_to_hash160(address)
                        if v == NetworkConstants.ADDRTYPE_P2PKH:
                            output = hash160_to_b58_address(h, 0)
                    outputAmount = amount

        self.handler.show_message(
            _("Confirm Transaction on your Ledger device..."))
        try:
            # Get trusted inputs from the original transactions
            for utxo in inputs:
                sequence = int_to_hex(utxo[5], 4)
                if not p2shTransaction:
                    txtmp = bitcoinTransaction(bfh(utxo[0]))
                    trustedInput = self.get_client().getTrustedInput(
                        txtmp, utxo[1])
                    trustedInput['sequence'] = sequence
                    chipInputs.append(trustedInput)
                    redeemScripts.append(txtmp.outputs[utxo[1]].script)
                else:
                    tmp = bfh(utxo[3])[::-1]
                    tmp += bfh(int_to_hex(utxo[1], 4))
                    chipInputs.append({'value': tmp, 'sequence': sequence})
                    redeemScripts.append(bfh(utxo[2]))

            # Sign all inputs
            firstTransaction = True
            inputIndex = 0
            rawTx = tx.serialize()
            self.get_client().enableAlternate2fa(False)
            while inputIndex < len(inputs):
                self.get_client().startUntrustedTransaction(
                    firstTransaction, inputIndex, chipInputs,
                    redeemScripts[inputIndex])
                outputData = self.get_client().finalizeInputFull(txOutput)
                outputData['outputData'] = txOutput
                if firstTransaction:
                    transactionOutput = outputData['outputData']
                if outputData['confirmationNeeded']:
                    outputData['address'] = output
                    self.handler.finished()
                    pin = self.handler.get_auth(
                        outputData
                    )  # does the authenticate dialog and returns pin
                    if not pin:
                        raise UserWarning()
                    if pin != 'paired':
                        self.handler.show_message(
                            _("Confirmed. Signing Transaction..."))
                else:
                    # Sign input with the provided PIN
                    inputSignature = self.get_client().untrustedHashSign(
                        inputsPaths[inputIndex], pin, lockTime=tx.locktime)
                    inputSignature[0] = 0x30  # force for 1.4.9+
                    signatures.append(inputSignature)
                    inputIndex = inputIndex + 1
                if pin != 'paired':
                    firstTransaction = False
        except UserWarning:
            self.handler.show_error(_('Cancelled by user'))
            return
        except BaseException as e:
            traceback.print_exc(file=sys.stdout)
            self.give_error(e, True)
        finally:
            self.handler.finished()

        for i, txin in enumerate(tx.inputs()):
            signingPos = inputs[i][4]
            txin['signatures'][signingPos] = bh2u(signatures[i])
        tx.raw = tx.serialize()
        self.signing = False
Beispiel #20
0
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return
        client = self.get_client()
        inputs = []
        inputsPaths = []
        pubKeys = []
        chipInputs = []
        redeemScripts = []
        signatures = []
        changePath = ""
        output = None
        p2shTransaction = False
        pin = ""
        self.get_client(
        )  # prompt for the PIN before displaying the dialog if necessary

        # Fetch inputs of the transaction to sign
        derivations = self.get_tx_derivations(tx)
        for txin in tx.inputs():
            if txin['type'] == 'coinbase':
                self.give_error(
                    "Coinbase not supported")  # should never happen

            if txin['type'] in ['p2sh']:
                p2shTransaction = True

            pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin)
            for i, x_pubkey in enumerate(x_pubkeys):
                if x_pubkey in derivations:
                    signingPos = i
                    s = derivations.get(x_pubkey)
                    hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], s[0],
                                              s[1])
                    break
            else:
                self.give_error("No matching x_key for sign_transaction"
                                )  # should never happen

            redeemScript = Transaction.get_preimage_script(txin)
            txin_prev_tx = txin.get('prev_tx')
            if txin_prev_tx is None:
                raise UserFacingException(
                    _('Offline signing with {} is not supported for legacy inputs.'
                      ).format(self.device))
            txin_prev_tx_raw = txin_prev_tx.raw if txin_prev_tx else None
            txin_prev_tx.deserialize()
            tx_type = txin_prev_tx.tx_type
            extra_payload = txin_prev_tx.extra_payload
            extra_data = b''
            if tx_type and extra_payload:
                extra_payload = extra_payload.serialize()
                extra_data = bfh(var_int(len(extra_payload))) + extra_payload
            inputs.append([
                txin_prev_tx_raw, txin['prevout_n'], redeemScript,
                txin['prevout_hash'], signingPos,
                txin.get('sequence', 0xffffffff - 1),
                txin.get('value'), extra_data
            ])
            inputsPaths.append(hwAddress)
            pubKeys.append(pubkeys)

        # Sanity check
        if p2shTransaction:
            for txin in tx.inputs():
                if txin['type'] != 'p2sh':
                    self.give_error(
                        "P2SH / regular input mixed in same transaction not supported"
                    )  # should never happen

        txOutput = var_int(len(tx.outputs()))
        for o in tx.outputs():
            output_type, addr, amount = o.type, o.address, o.value
            txOutput += int_to_hex(amount, 8)
            script = tx.pay_script(output_type, addr)
            txOutput += var_int(len(script) // 2)
            txOutput += script
        txOutput = bfh(txOutput)

        # Recognize outputs
        # - only one output and one change is authorized (for hw.1 and nano)
        # - at most one output can bypass confirmation (~change) (for all)
        if not p2shTransaction:
            if not self.get_client_electrum().supports_multi_output():
                if len(tx.outputs()) > 2:
                    self.give_error(
                        "Transaction with more than 2 outputs not supported")
            has_change = False
            any_output_on_change_branch = is_any_tx_output_on_change_branch(tx)
            for o in tx.outputs():
                assert o.type == TYPE_ADDRESS
                info = tx.output_info.get(o.address)
                if (info is not None) and len(tx.outputs()) > 1 \
                        and not has_change:
                    index = info.address_index
                    on_change_branch = index[0] == 1
                    # prioritise hiding outputs on the 'change' branch from user
                    # because no more than one change address allowed
                    if on_change_branch == any_output_on_change_branch:
                        changePath = self.get_derivation(
                        )[2:] + "/%d/%d" % index
                        has_change = True
                    else:
                        output = o.address
                else:
                    output = o.address
                    if not self.get_client_electrum().canAlternateCoinVersions:
                        v, h = b58_address_to_hash160(output)
                        if v == constants.net.ADDRTYPE_P2PKH:
                            output = hash160_to_b58_address(h, 0)

        self.handler.show_message(
            _("Confirm Transaction on your Ledger device..."))
        try:
            # Get trusted inputs from the original transactions
            for utxo in inputs:
                sequence = int_to_hex(utxo[5], 4)
                if not p2shTransaction:
                    txtmp = bitcoinTransaction(bfh(utxo[0]))
                    txtmp.extra_data = utxo[7]
                    trustedInput = self.get_client().getTrustedInput(
                        txtmp, utxo[1])
                    trustedInput['sequence'] = sequence
                    chipInputs.append(trustedInput)
                    redeemScripts.append(txtmp.outputs[utxo[1]].script)
                else:
                    tmp = bfh(utxo[3])[::-1]
                    tmp += bfh(int_to_hex(utxo[1], 4))
                    chipInputs.append({'value': tmp, 'sequence': sequence})
                    redeemScripts.append(bfh(utxo[2]))

            # Sign all inputs
            firstTransaction = True
            inputIndex = 0
            rawTx = tx.serialize_to_network()
            self.get_client().enableAlternate2fa(False)
            while inputIndex < len(inputs):
                self.get_client().startUntrustedTransaction(
                    firstTransaction,
                    inputIndex,
                    chipInputs,
                    redeemScripts[inputIndex],
                    version=tx.version)
                # we don't set meaningful outputAddress, amount and fees
                # as we only care about the alternateEncoding==True branch
                outputData = self.get_client().finalizeInput(
                    b'', 0, 0, changePath, bfh(rawTx))
                outputData['outputData'] = txOutput
                if outputData['confirmationNeeded']:
                    outputData['address'] = output
                    self.handler.finished()
                    pin = self.handler.get_auth(
                        outputData
                    )  # does the authenticate dialog and returns pin
                    if not pin:
                        raise UserWarning()
                    if pin != 'paired':
                        self.handler.show_message(
                            _("Confirmed. Signing Transaction..."))
                else:
                    # Sign input with the provided PIN
                    inputSignature = self.get_client().untrustedHashSign(
                        inputsPaths[inputIndex], pin, lockTime=tx.locktime)
                    inputSignature[0] = 0x30  # force for 1.4.9+
                    signatures.append(inputSignature)
                    inputIndex = inputIndex + 1
                if pin != 'paired':
                    firstTransaction = False
        except UserWarning:
            self.handler.show_error(_('Cancelled by user'))
            return
        except BTChipException as e:
            if e.sw in (0x6985, 0x6d00):  # cancelled by user
                return
            elif e.sw == 0x6982:
                raise  # pin lock. decorator will catch it
            else:
                self.logger.exception('')
                self.give_error(e, True)
        except BaseException as e:
            self.logger.exception('')
            self.give_error(e, True)
        finally:
            self.handler.finished()

        for i, txin in enumerate(tx.inputs()):
            signingPos = inputs[i][4]
            tx.add_signature_to_txin(i, signingPos, bh2u(signatures[i]))
        tx.raw = tx.serialize()
Beispiel #21
0
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return
        inputs = []
        inputsPaths = []
        chipInputs = []
        redeemScripts = []
        changePath = ""
        output = None
        p2shTransaction = False
        pin = ""
        client_ledger = self.get_client() # prompt for the PIN before displaying the dialog if necessary
        client_electrum = self.get_client_electrum()
        assert client_electrum

        # Fetch inputs of the transaction to sign
        for txin in tx.inputs():
            if txin.is_coinbase_input():
                self.give_error("Coinbase not supported")     # should never happen

            if txin.script_type in ['p2sh']:
                p2shTransaction = True

            my_pubkey, full_path = self.find_my_pubkey_in_txinout(txin)
            if not full_path:
                self.give_error("No matching pubkey for sign_transaction")  # should never happen
            full_path = convert_bip32_intpath_to_strpath(full_path)[2:]

            redeemScript = Transaction.get_preimage_script(txin)
            txin_prev_tx = txin.utxo
            if txin_prev_tx is None:
                raise UserFacingException(_('Missing previous tx for legacy input.'))
            txin_prev_tx_raw = txin_prev_tx.serialize() if txin_prev_tx else None
            txin_prev_tx.deserialize()
            tx_type = txin_prev_tx.tx_type
            extra_payload = txin_prev_tx.extra_payload
            extra_data = b''
            if tx_type and extra_payload:
                extra_payload = extra_payload.serialize()
                extra_data = bfh(var_int(len(extra_payload))) + extra_payload
            inputs.append([txin_prev_tx_raw,
                           txin.prevout.out_idx,
                           redeemScript,
                           txin.prevout.txid.hex(),
                           my_pubkey,
                           txin.nsequence,
                           txin.value_sats(),
                           extra_data])
            inputsPaths.append(full_path)

        # Sanity check
        if p2shTransaction:
            for txin in tx.inputs():
                if txin.script_type != 'p2sh':
                    self.give_error("P2SH / regular input mixed in same transaction not supported") # should never happen

        txOutput = var_int(len(tx.outputs()))
        for o in tx.outputs():
            txOutput += int_to_hex(o.value, 8)
            script = o.scriptpubkey.hex()
            txOutput += var_int(len(script)//2)
            txOutput += script
        txOutput = bfh(txOutput)

        if not client_electrum.supports_multi_output():
            if len(tx.outputs()) > 2:
                self.give_error("Transaction with more than 2 outputs not supported")
        for txout in tx.outputs():
            if not txout.address:
                if client_electrum.is_hw1():
                    self.give_error(_("Only address outputs are supported by {}").format(self.device))
                # note: max_size based on https://github.com/LedgerHQ/ledger-app-btc/commit/3a78dee9c0484821df58975803e40d58fbfc2c38#diff-c61ccd96a6d8b54d48f54a3bc4dfa7e2R26
                validate_op_return_output(txout, max_size=190)

        # Output "change" detection
        # - only one output and one change is authorized (for hw.1 and nano)
        # - at most one output can bypass confirmation (~change) (for all)
        if not p2shTransaction:
            has_change = False
            any_output_on_change_branch = is_any_tx_output_on_change_branch(tx)
            for txout in tx.outputs():
                if txout.is_mine and len(tx.outputs()) > 1 \
                        and not has_change:
                    # prioritise hiding outputs on the 'change' branch from user
                    # because no more than one change address allowed
                    if txout.is_change == any_output_on_change_branch:
                        my_pubkey, changePath = self.find_my_pubkey_in_txinout(txout)
                        assert changePath
                        changePath = convert_bip32_intpath_to_strpath(changePath)[2:]
                        has_change = True
                    else:
                        output = txout.address
                else:
                    output = txout.address
                    if not self.get_client_electrum().canAlternateCoinVersions:
                        v, h = b58_address_to_hash160(output)
                        if v == constants.net.ADDRTYPE_P2PKH:
                            output = hash160_to_b58_address(h, 0)

        self.handler.show_message(_("Confirm Transaction on your Ledger device..."))
        try:
            # Get trusted inputs from the original transactions
            for utxo in inputs:
                sequence = int_to_hex(utxo[5], 4)
                if (not p2shTransaction) or client_electrum.supports_multi_output():
                    txtmp = bitcoinTransaction(bfh(utxo[0]))
                    txtmp.extra_data = utxo[7]
                    trustedInput = client_ledger.getTrustedInput(txtmp, utxo[1])
                    trustedInput['sequence'] = sequence
                    chipInputs.append(trustedInput)
                    if p2shTransaction:
                        redeemScripts.append(bfh(utxo[2]))
                    else:
                        redeemScripts.append(txtmp.outputs[utxo[1]].script)
                else:
                    tmp = bfh(utxo[3])[::-1]
                    tmp += bfh(int_to_hex(utxo[1], 4))
                    chipInputs.append({'value' : tmp, 'sequence' : sequence})
                    redeemScripts.append(bfh(utxo[2]))

            # Sign all inputs
            firstTransaction = True
            inputIndex = 0
            rawTx = tx.serialize_to_network()
            client_ledger.enableAlternate2fa(False)
            while inputIndex < len(inputs):
                client_ledger.startUntrustedTransaction(firstTransaction, inputIndex,
                                                            chipInputs, redeemScripts[inputIndex], version=tx.version)
                # we don't set meaningful outputAddress, amount and fees
                # as we only care about the alternateEncoding==True branch
                outputData = client_ledger.finalizeInput(b'', 0, 0, changePath, bfh(rawTx))
                outputData['outputData'] = txOutput
                if outputData['confirmationNeeded']:
                    outputData['address'] = output
                    self.handler.finished()
                    # do the authenticate dialog and get pin:
                    pin = self.handler.get_auth(outputData, client=client_electrum)
                    if not pin:
                        raise UserWarning()
                    self.handler.show_message(_("Confirmed. Signing Transaction..."))
                else:
                    # Sign input with the provided PIN
                    inputSignature = client_ledger.untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime)
                    inputSignature[0] = 0x30 # force for 1.4.9+
                    my_pubkey = inputs[inputIndex][4]
                    tx.add_signature_to_txin(txin_idx=inputIndex,
                                             signing_pubkey=my_pubkey.hex(),
                                             sig=inputSignature.hex())
                    inputIndex = inputIndex + 1
                firstTransaction = False
        except UserWarning:
            self.handler.show_error(_('Cancelled by user'))
            return
        except BTChipException as e:
            if e.sw in (0x6985, 0x6d00):  # cancelled by user
                return
            elif e.sw == 0x6982:
                raise  # pin lock. decorator will catch it
            else:
                self.logger.exception('')
                self.give_error(e, True)
        except BaseException as e:
            self.logger.exception('')
            self.give_error(e, True)
        finally:
            self.handler.finished()
Beispiel #22
0
from electrum_dash.transaction import Transaction
from electrum_dash import paymentrequest
from electrum_dash import paymentrequest_pb2 as pb2

chain_file = 'mychain.pem'
cert_file = 'mycert.pem'
amount = 1000000
address = "18U5kpCAU4s8weFF8Ps5n8HAfpdUjDVF64"
memo = "blah"
out_file = "payreq"


with open(chain_file, 'r') as f:
    chain = tlslite.X509CertChain()
    chain.parsePemList(f.read())

certificates = pb2.X509Certificates()
certificates.certificate.extend(map(lambda x: str(x.bytes), chain.x509List))

with open(cert_file, 'r') as f:
    rsakey = tlslite.utils.python_rsakey.Python_RSAKey.parsePEM(f.read())

script = Transaction.pay_script('address', address).decode('hex')

pr_string = paymentrequest.make_payment_request(amount, script, memo, rsakey)

with open(out_file,'wb') as f:
    f.write(pr_string)

print("Payment request was written to file '%s'"%out_file)
    def main(self):
        add_menu()
        welcome = 'Use the menu to scan a transaction.'
        droid.fullShow(qr_layout(welcome))
        while True:
            event = droid.eventWait().result
            if not event:
                continue
            elif event["name"] == "key":
                if event["data"]["key"] == '4':
                    if self.qr_data:
                        self.show_qr(None)
                        self.show_title(welcome)
                    else:
                        break

            elif event["name"] == "seed":
                password = self.get_password()
                if password is False:
                    modal_dialog('Error', 'incorrect password')
                    continue
                seed = wallet.get_mnemonic(password)
                modal_dialog('Your seed is', seed)

            elif event["name"] == "password":
                self.change_password_dialog()

            elif event["name"] == "xpub":
                mpk = wallet.get_master_public_key()
                self.show_qr(mpk)
                self.show_title('master public key')

            elif event["name"] == "scan":
                r = droid.scanBarcode()
                r = r.result
                if not r:
                    continue
                data = r['extras']['SCAN_RESULT']
                data = base_decode(data.encode('utf8'), None, base=43)
                data = ''.join(chr(ord(b)) for b in data).encode('hex')
                tx = Transaction(data)
                #except:
                #    modal_dialog('Error', 'Cannot parse transaction')
                #    continue
                if not wallet.can_sign(tx):
                    modal_dialog('Error', 'Cannot sign this transaction')
                    continue
                lines = map(
                    lambda x: x[0] + u'\t\t' + format_satoshis(x[1])
                    if x[1] else x[0], tx.get_outputs())
                if not modal_question('Sign?', '\n'.join(lines)):
                    continue
                password = self.get_password()
                if password is False:
                    modal_dialog('Error', 'incorrect password')
                    continue
                droid.dialogCreateSpinnerProgress("Signing")
                droid.dialogShow()
                wallet.sign_transaction(tx, password)
                droid.dialogDismiss()
                data = base_encode(str(tx).decode('hex'), base=43)
                self.show_qr(data)
                self.show_title('Signed Transaction')

        droid.makeToast("Bye!")
    def main(self):
        add_menu()
        welcome = 'Use the menu to scan a transaction.'
        droid.fullShow(qr_layout(welcome))
        while True:
            event = droid.eventWait().result
            if not event:
                continue
            elif event["name"] == "key":
                if event["data"]["key"] == '4':
                    if self.qr_data:
                        self.show_qr(None)
                        self.show_title(welcome)
                    else:
                        break

            elif event["name"] == "seed":
                password = self.get_password()
                if password is False:
                    modal_dialog('Error','incorrect password')
                    continue
                seed = wallet.get_mnemonic(password)
                modal_dialog('Your seed is', seed)

            elif event["name"] == "password":
                self.change_password_dialog()

            elif event["name"] == "xpub":
                mpk = wallet.get_master_public_key()
                self.show_qr(mpk)
                self.show_title('master public key')

            elif event["name"] == "scan":
                r = droid.scanBarcode()
                r = r.result
                if not r:
                    continue
                data = r['extras']['SCAN_RESULT']
                data = base_decode(data.encode('utf8'), None, base=43)
                data = ''.join(chr(ord(b)) for b in data).encode('hex')
                tx = Transaction(data)
                #except:
                #    modal_dialog('Error', 'Cannot parse transaction')
                #    continue
                if not wallet.can_sign(tx):
                    modal_dialog('Error', 'Cannot sign this transaction')
                    continue
                lines = map(lambda x: x[0] + u'\t\t' + format_satoshis(x[1]) if x[1] else x[0], tx.get_outputs())
                if not modal_question('Sign?', '\n'.join(lines)):
                    continue
                password = self.get_password()
                if password is False:
                    modal_dialog('Error','incorrect password')
                    continue
                droid.dialogCreateSpinnerProgress("Signing")
                droid.dialogShow()
                wallet.sign_transaction(tx, password)
                droid.dialogDismiss()
                data = base_encode(str(tx).decode('hex'), base=43)
                self.show_qr(data)
                self.show_title('Signed Transaction')

        droid.makeToast("Bye!")
Beispiel #25
0
from electrum_dash.transaction import Transaction
from electrum_dash import paymentrequest
from electrum_dash import paymentrequest_pb2 as pb2

chain_file = 'mychain.pem'
cert_file = 'mycert.pem'
amount = 1000000
address = "18U5kpCAU4s8weFF8Ps5n8HAfpdUjDVF64"
memo = "blah"
out_file = "payreq"

with open(chain_file, 'r') as f:
    chain = tlslite.X509CertChain()
    chain.parsePemList(f.read())

certificates = pb2.X509Certificates()
certificates.certificate.extend(map(lambda x: str(x.bytes), chain.x509List))

with open(cert_file, 'r') as f:
    rsakey = tlslite.utils.python_rsakey.Python_RSAKey.parsePEM(f.read())

script = Transaction.pay_script('address', address).decode('hex')

pr_string = paymentrequest.make_payment_request(amount, script, memo, rsakey)

with open(out_file, 'wb') as f:
    f.write(pr_string)

print("Payment request was written to file '%s'" % out_file)
Beispiel #26
0
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return
        client = self.get_client()
        inputs = []
        inputsPaths = []
        pubKeys = []
        chipInputs = []
        redeemScripts = []
        signatures = []
        preparedTrustedInputs = []
        changePath = ""
        output = None
        p2shTransaction = False
        pin = ""
        self.get_client() # prompt for the PIN before displaying the dialog if necessary

        # Fetch inputs of the transaction to sign
        derivations = self.get_tx_derivations(tx)
        for txin in tx.inputs():
            if txin['type'] == 'coinbase':
                self.give_error("Coinbase not supported")     # should never happen

            if txin['type'] in ['p2sh']:
                p2shTransaction = True

            pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin)
            for i, x_pubkey in enumerate(x_pubkeys):
                if x_pubkey in derivations:
                    signingPos = i
                    s = derivations.get(x_pubkey)
                    hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], s[0], s[1])
                    break
            else:
                self.give_error("No matching x_key for sign_transaction") # should never happen

            redeemScript = Transaction.get_preimage_script(txin)
            txin_prev_tx = txin.get('prev_tx')
            if txin_prev_tx is None:
                raise Exception(_('Offline signing with {} is not supported for legacy inputs.').format(self.device))
            txin_prev_tx_raw = txin_prev_tx.raw if txin_prev_tx else None
            inputs.append([txin_prev_tx_raw,
                           txin['prevout_n'],
                           redeemScript,
                           txin['prevout_hash'],
                           signingPos,
                           txin.get('sequence', 0xffffffff - 1),
                           txin.get('value')])
            inputsPaths.append(hwAddress)
            pubKeys.append(pubkeys)

        # Sanity check
        if p2shTransaction:
            for txin in tx.inputs():
                if txin['type'] != 'p2sh':
                    self.give_error("P2SH / regular input mixed in same transaction not supported") # should never happen

        txOutput = var_int(len(tx.outputs()))
        for txout in tx.outputs():
            output_type, addr, amount = txout
            txOutput += int_to_hex(amount, 8)
            script = tx.pay_script(output_type, addr)
            txOutput += var_int(len(script)//2)
            txOutput += script
        txOutput = bfh(txOutput)

        # Recognize outputs
        # - only one output and one change is authorized (for hw.1 and nano)
        # - at most one output can bypass confirmation (~change) (for all)
        if not p2shTransaction:
            if not self.get_client_electrum().supports_multi_output():
                if len(tx.outputs()) > 2:
                    self.give_error("Transaction with more than 2 outputs not supported")
            has_change = False
            any_output_on_change_branch = is_any_tx_output_on_change_branch(tx)
            for o in tx.outputs():
                assert o.type == TYPE_ADDRESS
                info = tx.output_info.get(o.address)
                if (info is not None) and len(tx.outputs()) > 1 \
                        and not has_change:
                    index = info.address_index
                    on_change_branch = index[0] == 1
                    # prioritise hiding outputs on the 'change' branch from user
                    # because no more than one change address allowed
                    if on_change_branch == any_output_on_change_branch:
                        changePath = self.get_derivation()[2:] + "/%d/%d"%index
                        has_change = True
                    else:
                        output = o.address
                else:
                    output = o.address
                    if not self.get_client_electrum().canAlternateCoinVersions:
                        v, h = b58_address_to_hash160(address)
                        if v == constants.net.ADDRTYPE_P2PKH:
                            output = hash160_to_b58_address(h, 0)

        self.handler.show_message(_("Confirm Transaction on your Ledger device..."))
        try:
            # Get trusted inputs from the original transactions
            for utxo in inputs:
                sequence = int_to_hex(utxo[5], 4)
                if not p2shTransaction:
                    txtmp = bitcoinTransaction(bfh(utxo[0]))
                    trustedInput = self.get_client().getTrustedInput(txtmp, utxo[1])
                    trustedInput['sequence'] = sequence
                    chipInputs.append(trustedInput)
                    redeemScripts.append(txtmp.outputs[utxo[1]].script)
                else:
                    tmp = bfh(utxo[3])[::-1]
                    tmp += bfh(int_to_hex(utxo[1], 4))
                    chipInputs.append({'value' : tmp, 'sequence' : sequence})
                    redeemScripts.append(bfh(utxo[2]))

            # Sign all inputs
            firstTransaction = True
            inputIndex = 0
            rawTx = tx.serialize_to_network()
            self.get_client().enableAlternate2fa(False)
            while inputIndex < len(inputs):
                self.get_client().startUntrustedTransaction(firstTransaction, inputIndex,
                                                        chipInputs, redeemScripts[inputIndex])
                if changePath:
                    # we don't set meaningful outputAddress, amount and fees
                    # as we only care about the alternateEncoding==True branch
                    outputData = self.get_client().finalizeInput(b'', 0, 0, changePath, bfh(rawTx))
                else:
                    outputData = self.get_client().finalizeInputFull(txOutput)
                outputData['outputData'] = txOutput
                if firstTransaction:
                    transactionOutput = outputData['outputData']
                if outputData['confirmationNeeded']:
                    outputData['address'] = output
                    self.handler.finished()
                    pin = self.handler.get_auth( outputData ) # does the authenticate dialog and returns pin
                    if not pin:
                        raise UserWarning()
                    if pin != 'paired':
                        self.handler.show_message(_("Confirmed. Signing Transaction..."))
                else:
                    # Sign input with the provided PIN
                    inputSignature = self.get_client().untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime)
                    inputSignature[0] = 0x30 # force for 1.4.9+
                    signatures.append(inputSignature)
                    inputIndex = inputIndex + 1
                if pin != 'paired':
                    firstTransaction = False
        except UserWarning:
            self.handler.show_error(_('Cancelled by user'))
            return
        except BTChipException as e:
            if e.sw == 0x6985:  # cancelled by user
                return
            elif e.sw == 0x6982:
                raise  # pin lock. decorator will catch it
            else:
                traceback.print_exc(file=sys.stderr)
                self.give_error(e, True)
        except BaseException as e:
            traceback.print_exc(file=sys.stdout)
            self.give_error(e, True)
        finally:
            self.handler.finished()

        for i, txin in enumerate(tx.inputs()):
            signingPos = inputs[i][4]
            tx.add_signature_to_txin(i, signingPos, bh2u(signatures[i]))
        tx.raw = tx.serialize()