Exemplo n.º 1
0
 async def sign_psbt(self, stream, show_screen):
     data = a2b_base64(stream.read())
     psbt = PSBT.parse(data)
     wallets, meta = self.parse_psbt(psbt=psbt)
     spends = []
     for w, amount in wallets:
         if w is None:
             name = "Unkown wallet"
         else:
             name = w.name
         spends.append("%.8f BTC\nfrom \"%s\"" % (amount / 1e8, name))
     title = "Spending:\n" + "\n".join(spends)
     res = await show_screen(TransactionScreen(title, meta))
     if res:
         for w, _ in wallets:
             if w is None:
                 continue
             # fill derivation paths from proprietary fields
             w.update_gaps(psbt=psbt)
             w.save(self.keystore)
             psbt = w.fill_psbt(psbt, self.keystore.fingerprint)
         self.keystore.sign_psbt(psbt)
         # remove unnecessary stuff:
         out_psbt = PSBT(psbt.tx)
         for i, inp in enumerate(psbt.inputs):
             out_psbt.inputs[i].partial_sigs = inp.partial_sigs
         txt = b2a_base64(out_psbt.serialize()).decode().strip()
         return BytesIO(txt)
Exemplo n.º 2
0
 async def confirm_transaction_final(self, wallets, meta, show_screen):
     # build title for the tx screen
     spends = []
     unit = "BTC" if self.network == "main" else "tBTC"
     for w in wallets:
         if w is None:
             name = "Unknown wallet"
         else:
             name = w.name
         amount = wallets[w].get("amount", 0)
         spends.append('%.8f %s\nfrom "%s"' % (amount / 1e8, unit, name))
     title = "Inputs:\n" + "\n".join(spends)
     return await show_screen(TransactionScreen(title, meta))
Exemplo n.º 3
0
 async def sign_psbt(self, stream, show_screen):
     data = a2b_base64(stream.read())
     psbt = PSBT.parse(data)
     wallet, meta = self.parse_psbt(psbt=psbt)
     res = await show_screen(TransactionScreen(wallet.name, meta))
     if res:
         # fill derivation paths from proprietary fields
         wallet.update_gaps(psbt=psbt)
         wallet.save(self.keystore)
         psbt = wallet.fill_psbt(psbt, self.keystore.fingerprint)
         self.keystore.sign_psbt(psbt)
         # remove unnecessary stuff:
         out_psbt = PSBT(psbt.tx)
         for i, inp in enumerate(psbt.inputs):
             out_psbt.inputs[i].partial_sigs = inp.partial_sigs
         txt = b2a_base64(out_psbt.serialize()).decode().strip()
         return BytesIO(txt)
Exemplo n.º 4
0
    async def sign_psbt(self, stream, show_screen, encoding=BASE64_STREAM):
        if encoding == BASE64_STREAM:
            data = a2b_base64(stream.read())
            psbt = PSBT.parse(data)
        else:
            psbt = PSBT.read_from(stream)
        # check if all utxos are there and if there are custom sighashes
        sighash = SIGHASH.ALL
        custom_sighashes = []
        for i, inp in enumerate(psbt.inputs):
            if inp.witness_utxo is None:
                if inp.non_witness_utxo is None:
                    raise WalletError(
                        "Invalid PSBT - missing previous transaction")
            if inp.sighash_type and inp.sighash_type != SIGHASH.ALL:
                custom_sighashes.append((i, inp.sighash_type))

        if len(custom_sighashes) > 0:
            txt = [("Input %d: " % i) + SIGHASH_NAMES[sh]
                   for (i, sh) in custom_sighashes]
            canceltxt = "Only sign ALL" if len(custom_sighashes) != len(
                psbt.inputs) else "Cancel"
            confirm = await show_screen(
                Prompt("Warning!",
                       "\nCustom SIGHASH flags are used!\n\n" + "\n".join(txt),
                       confirm_text="Sign anyway",
                       cancel_text=canceltxt))
            if confirm:
                sighash = None
            else:
                if len(custom_sighashes) == len(psbt.inputs):
                    # nothing to sign
                    return
        wallets, meta = self.parse_psbt(psbt=psbt)
        # there is an unknown wallet
        # wallet is a list of tuples: (wallet, amount)
        if None in [w[0] for w in wallets]:
            scr = Prompt(
                "Warning!",
                "\nUnknown wallet in inputs!\n\n\n"
                "Wallet for some inpunts is unknown! This means we can't verify change addresses.\n\n\n"
                "Hint:\nYou can cancel this transaction and import the wallet by scanning it's descriptor.\n\n\n"
                "Proceed to the transaction confirmation?",
            )
            proceed = await show_screen(scr)
            if not proceed:
                return None
        spends = []
        for w, amount in wallets:
            if w is None:
                name = "Unknown wallet"
            else:
                name = w.name
            spends.append('%.8f BTC\nfrom "%s"' % (amount / 1e8, name))
        title = "Spending:\n" + "\n".join(spends)
        res = await show_screen(TransactionScreen(title, meta))
        if res:
            self.show_loader(title="Signing transaction...")
            sigsStart = 0
            for i, inp in enumerate(psbt.inputs):
                sigsStart += len(list(inp.partial_sigs.keys()))
            for w, _ in wallets:
                if w is None:
                    continue
                # fill derivation paths from proprietary fields
                w.update_gaps(psbt=psbt)
                w.save(self.keystore)
                w.fill_psbt(psbt, self.keystore.fingerprint)
                if w.has_private_keys:
                    w.sign_psbt(psbt, sighash)
            self.keystore.sign_psbt(psbt, sighash)
            # remove unnecessary stuff:
            out_psbt = PSBT(psbt.tx)
            sigsEnd = 0
            for i, inp in enumerate(psbt.inputs):
                sigsEnd += len(list(inp.partial_sigs.keys()))
                out_psbt.inputs[i].partial_sigs = inp.partial_sigs
            del psbt
            gc.collect()
            if sigsEnd == sigsStart:
                raise WalletError(
                    "We didn't add any signatures!\n\nMaybe you forgot to import the wallet?\n\nScan the wallet descriptor to import it."
                )
            if encoding == BASE64_STREAM:
                txt = b2a_base64(out_psbt.serialize()).decode().strip()
            else:
                txt = out_psbt.serialize()
            return BytesIO(txt)