Beispiel #1
0
def main():
    # generate 16 bytes of entropy and
    # convert to a mnemonic phrase (12 words)
    entropy = bytes([random.getrandbits(8) for i in range(16)])
    mnemonic = bip39.mnemonic_from_bytes(entropy)
    # or just define hardcoded:
    mnemonic = "alien visual jealous source coral memory embark certain radar capable clip edit"
    print(mnemonic)
    # convert to seed, empty password
    seed = bip39.mnemonic_to_seed(mnemonic)
    # convert to the root key
    # you can define the version - x/y/zprv for desired network
    root = bip32.HDKey.from_seed(seed, version=NETWORKS["test"]["xprv"])
    print(root.to_base58())

    print("\nBIP-44 - legacy")
    # derive account according to bip44
    bip44_xprv = root.derive("m/44h/1h/0h")
    print(bip44_xprv.to_base58())
    # corresponding master public key:
    bip44_xpub = bip44_xprv.to_public()
    print(bip44_xpub.to_base58())
    # first 5 receiving addresses
    for i in range(5):
        # .key member is a public key for HD public keys
        #            and a private key for HD private keys
        pub = bip44_xpub.derive("m/0/%d" % i).key
        sc = script.p2pkh(pub)
        print(sc.address(NETWORKS["test"]))

    print("\nBIP-84 - native segwit")
    # derive account according to bip84
    bip84_xprv = root.derive("m/84h/1h/0h")
    # you can also change version of the key to get zpub (vpub on testnet)
    bip84_xprv.version = NETWORKS["test"]["zprv"]
    print(bip84_xprv.to_base58())
    # corresponding master public key:
    bip84_xpub = bip84_xprv.to_public()
    print(bip84_xpub.to_base58())
    # first 5 receiving addresses
    for i in range(5):
        pub = bip84_xpub.derive("m/0/%d" % i).key
        sc = script.p2wpkh(pub)
        print(sc.address(NETWORKS["test"]))

    print("\nBIP-49 - nested segwit")
    # derive account according to bip49
    bip49_xprv = root.derive("m/49h/1h/0h")
    # you can also change version of the key to get ypub (upub on testnet)
    bip49_xprv.version = NETWORKS["test"]["yprv"]
    print(bip49_xprv.to_base58())
    # corresponding master public key:
    bip49_xpub = bip49_xprv.to_public()
    print(bip49_xpub.to_base58())
    # first 5 receiving addresses
    for i in range(5):
        pub = bip49_xpub.derive("m/0/%d" % i).key
        # use p2sh(p2wpkh(pubkey)) to get nested segwit scriptpubkey
        sc = script.p2sh(script.p2wpkh(pub))
        print(sc.address(NETWORKS["test"]))
Beispiel #2
0
def main():
    # all from the same private key
    prv = ec.PrivateKey.from_wif(
        "L2e5y14ZD3U1J7Yr62t331RtYe2hRW2TBBP8qNQHB8nSPBNgt6dM")
    pub = prv.get_public_key()
    print("Public key:")
    print(hexlify(pub.serialize()))

    # we will generate regtest addresses
    network = NETWORKS["regtest"]

    print("Legacy (pay to pubkey hash):")
    sc = script.p2pkh(pub)
    # default network is main
    print(sc.address(network))

    print("Segwit (pay to witness pubkey hash):")
    sc = script.p2wpkh(pub)
    print(sc.address(network))

    print("Nested segwit (p2sh-p2wpkh):")
    sc = script.p2sh(script.p2wpkh(pub))
    print(sc.address(network))

    print("\nMultisig address (2 of 3):")
    # unsorted
    pubs = [
        ec.PublicKey.parse(
            unhexlify(
                "02edd7a58d2ff1e483d35f92a32e53607423f936b29bf95613cab24b0b7f92e0f1"
            )),
        ec.PublicKey.parse(
            unhexlify(
                "03a4a6d360acc45cb281e0022b03218fad6ee93881643488ae39d22b854d9fa261"
            )),
        ec.PublicKey.parse(
            unhexlify(
                "02e1fdc3b011effbba4b0771eb0f7193dee24cfe101ab7e8b64516d83f7116a615"
            )),
    ]
    # 2 of 3 multisig script
    sc = script.multisig(2, pubs)
    print("Legacy, unsorted (p2sh):")
    redeem_sc = script.p2sh(sc)
    print(redeem_sc.address(network))

    print("Native segwit, sorted (p2wsh):")
    sc = script.multisig(2, sorted(pubs))
    witness_sc = script.p2wsh(sc)
    print(witness_sc.address(network))

    print("Nested segwit, sorted (p2sh-p2wsh):")
    sc = script.multisig(2, sorted(pubs))
    witness_sc = script.p2wsh(sc)
    redeem_sc = script.p2sh(witness_sc)
    print(redeem_sc.address(network))
Beispiel #3
0
 def scriptpubkey(self, idx=None):
     if idx is None and "*" in self.serialize():
         raise RuntimeError("Index is required")
     if self.is_multisig:
         keys = []
         for i, key in enumerate(self.base_key):
             keys.append(derive_pubkey(key, self.path_suffix[i], idx))
         if self.sort_keys:
             keys = sorted(keys)
         sc = script.multisig(int(self.multisig_M), keys)
         if self.sh:
             return script.p2sh(sc)
         elif self.sh_wsh:
             return script.p2sh(script.p2wsh(sc))
         elif self.wsh:
             return script.p2wsh(sc)
     else:
         key = derive_pubkey(self.base_key, self.path_suffix, idx)
         if self.wpkh:
             return script.p2wpkh(key)
         elif self.sh_wpkh:
             return script.p2sh(script.p2wpkh(key))
         else:
             return script.p2pkh(key)
Beispiel #4
0
def main():    
    #Extended public key string to an address, tested against https://iancoleman.io/bip39/
    #Mnemonic used: february deposit cram leopard ripple turtle impulse history accident noodle love crazy limit pond tourist 

    #bip44, first address "124d7o3DmtXqvn1dJLxj9TQYA7v9Cmcyes" 
    key = "xpub6D2VGgnY7WJ8H3SKBPhqbarfA6uZbcUSLnuwgzE5qvmXyq23yNg42GKJgDXMJ27Q3NBeFjQDyz8Za27sYUfmWs7PNow8i3FUNwHufbyyWQK"
    
    #bip49, first address "3CntmFG5nBG9sCCr2b6MWhTAk9RLEicERn" 
    #key = "ypub6YFkZihjEjQdftpu4NwwNobdTB7eRHQjcTjyDj4hhANcj3KqXVTQuEuz1rL49NtzFLCxvnSAd4gnCG1yfWdDv1evXSrMKZfCcYQ3yR6eyP2"

    #bip84, first address "bc1qv5rgjspu3kljw8kczdvyl4x0gkk09jp7ddmrp8" 
    #key = "zpub6riY8dgyiTYHfTE3xqKscWYjZrKtwWwtc4LBfvnkqPHH9gUAC4HJrydyphFihghnGnEw5cyDDgq5iZULuheBJqJW825Cv5LCgUh7VJTTLhw"

    k = bip32.HDKey.from_base58(key)
    child = k.derive([0, 0])
    
    if key[0:4] == "xpub":
        address = script.p2pkh(child).address()
    elif key[0:4] == "zpub":
        address = script.p2wpkh(child).address()
    elif key[0:4] == "ypub":
        address = script.p2sh(script.p2wpkh(child)).address()

    print(address)
Beispiel #5
0
def main():
    # get root key from the mnemonic
    mnemonic = "alien visual jealous source coral memory embark certain radar capable clip edit"
    seed = bip39.mnemonic_to_seed(mnemonic)
    root = bip32.HDKey.from_seed(seed, version=NETWORKS["test"]["xprv"])

    # get bip84-xpub to import to Bitcoin Core:
    # we will use the form [fingerprint/derivation]xpub
    # to import to Bitcoin Core with descriptors

    # first let's get the root fingerprint
    # we can get it from any child of the root key
    fingerprint = root.child(0).fingerprint
    hardened_derivation = "m/84h/1h/0h"
    # derive account according to bip84
    bip84_xprv = root.derive(hardened_derivation)
    # corresponding master public key:
    bip84_xpub = bip84_xprv.to_public()
    print("[%s%s]%s" % (hexlify(fingerprint).decode('utf-8'),
                        hardened_derivation[1:], bip84_xpub.to_base58()))

    # parse psbt transaction
    b64_psbt = "cHNidP8BAHICAAAAAY3LB6teEH6qJHluFYG3AQe8n0HDUcUSEuw2WIJ1ECDUAAAAAAD/////AoDDyQEAAAAAF6kU882+nVMDKGj4rKzjDB6NjyJqSBCHaPMhCgAAAAAWABQUbW8/trQg4d3PKL8WLi2kUa1BqAAAAAAAAQEfAMLrCwAAAAAWABTR6Cr4flM2A0LMGjGiaZ+fhod37SIGAhHf737H1jCUjkJ1K5DqFkaY0keihxeWBQpm1kDtVZyxGLMX7IZUAACAAQAAgAAAAIAAAAAAAAAAAAAAIgIDPtTTi27VFw59jdmWDV8b1YciQzhYGO7m8zB9CvD0brcYsxfshlQAAIABAACAAAAAgAEAAAAAAAAAAA=="
    # first convert it to binary
    raw = a2b_base64(b64_psbt)
    # then parse
    tx = psbt.PSBT.parse(raw)

    # print how much we are spending and where
    total_in = 0
    for inp in tx.inputs:
        total_in += inp.witness_utxo.value
    print("Inputs:", total_in, "satoshi")
    change_out = 0  # value that goes back to us
    send_outputs = []
    for i, out in enumerate(tx.outputs):
        # check if it is a change or not:
        change = False
        # should be one or zero for single-key addresses
        for pub in out.bip32_derivations:
            # check if it is our key
            if out.bip32_derivations[pub].fingerprint == fingerprint:
                hdkey = root.derive(out.bip32_derivations[pub].derivation)
                mypub = hdkey.key.get_public_key()
                if mypub != pub:
                    raise ValueError("Derivation path doesn't look right")
                # now check if provided scriptpubkey matches
                sc = script.p2wpkh(mypub)
                if sc == tx.tx.vout[i].script_pubkey:
                    change = True
                    continue
        if change:
            change_out += tx.tx.vout[i].value
        else:
            send_outputs.append(tx.tx.vout[i])
    print("Spending", total_in - change_out, "satoshi")
    fee = total_in - change_out
    for out in send_outputs:
        fee -= out.value
        print(out.value, "to", out.script_pubkey.address(NETWORKS["test"]))
    print("Fee:", fee, "satoshi")

    # sign the transaction
    tx.sign_with(root)
    raw = tx.serialize()
    # convert to base64
    b64_psbt = b2a_base64(raw)
    # somehow b2a ends with \n...
    if b64_psbt[-1:] == b"\n":
        b64_psbt = b64_psbt[:-1]
    # print
    print("\nSigned transaction:")
    print(b64_psbt.decode('utf-8'))
Beispiel #6
0
def main():
    # all from the same private key
    prv = ec.PrivateKey.from_wif(
        "L2e5y14ZD3U1J7Yr62t331RtYe2hRW2TBBP8qNQHB8nSPBNgt6dM")
    pub = prv.get_public_key()
    inputs = [
        # legacy
        {
            "txid":
            unhexlify(
                "7f0c7538e898bbe5531fa47d4057b52c914ec45e20ae1a5572ea1005a8ba50f8"
            ),
            "vout":
            0,
            "value":
            int(1e8),
            "script":
            script.p2pkh(pub),
        },
        # native segwit
        {
            "txid":
            unhexlify(
                "f51e6fc2392558a70ae970e93538f368828ad2800a7370f372a652de463429fc"
            ),
            "vout":
            0,
            "value":
            int(2e8),
            "script":
            script.p2wpkh(pub),
        },
        # nested segwit
        {
            "txid":
            unhexlify(
                "2e4cb680ed008b6e529c4c83f00d55326a2e68b48ddf11267e3f5323006966a6"
            ),
            "vout":
            1,
            "value":
            int(3e8),
            "script":
            script.p2sh(script.p2wpkh(pub)),
            "redeem":
            script.p2wpkh(pub),
        },
    ]
    # sending back almost the same amount
    vin = [TransactionInput(inp["txid"], inp["vout"]) for inp in inputs]
    vout = [
        TransactionOutput(inp["value"] - 1500, inp["script"]) for inp in inputs
    ]
    tx = Transaction(vin=vin, vout=vout)
    print("Unsigned transaction:")
    print(hexlify(tx.serialize()).decode("utf-8"))

    for i in range(len(inputs)):
        inp = inputs[i]
        script_type = inp["script"].script_type()
        # legacy input
        if script_type == "p2pkh":
            h = tx.sighash_legacy(i, inp["script"])
            sig = prv.sign(h)
            tx.vin[i].script_sig = script.script_sig_p2pkh(sig, pub)
        # native segwit
        elif script_type == "p2wpkh":
            sc = script.p2pkh_from_p2wpkh(inp["script"])
            h = tx.sighash_segwit(i, sc, inp["value"])
            sig = prv.sign(h)
            tx.vin[i].witness = script.witness_p2wpkh(sig, pub)
        # nested segwit
        elif script_type == "p2sh":
            if "redeem" in inp and inp["redeem"].script_type() == "p2wpkh":
                sc = script.p2pkh_from_p2wpkh(inp["redeem"])
                h = tx.sighash_segwit(i, sc, inp["value"])
                sig = prv.sign(h)
                tx.vin[i].script_sig = script.script_sig_p2sh(inp["redeem"])
                tx.vin[i].witness = script.witness_p2wpkh(sig, pub)
            else:
                raise NotImplementedError("Script type is not supported")
        else:
            raise NotImplementedError("Script type is not supported")

    print("Signed transaction:")
    print(hexlify(tx.serialize()).decode("utf-8"))
Beispiel #7
0
    def __parseOutputs(self):
        self.spend_amount = 0
        self.change_amount = 0
        self.fee_amount = 0
        self.destination_addresses = []
        self.self_addresses = []
        for i, out in enumerate(self.psbt.outputs):
            out_policy = PSBTParser.__get_policy(
                out, self.psbt.tx.vout[i].script_pubkey, self.psbt.xpubs)
            is_change = False

            # if policy is the same - probably change
            if out_policy == self.policy:
                # double-check that it's change
                # we already checked in get_cosigners and parse_multisig
                # that pubkeys are generated from cosigners,
                # and witness script is corresponding multisig
                # so we only need to check that scriptpubkey is generated from
                # witness script

                # empty script by default
                sc = script.Script(b"")
                # multisig, we know witness script
                if self.policy["type"] == "p2wsh":
                    sc = script.p2wsh(out.witness_script)
                elif self.policy["type"] == "p2sh-p2wsh":
                    sc = script.p2sh(script.p2wsh(out.witness_script))

                # single-sig
                elif "pkh" in self.policy["type"]:
                    my_pubkey = None
                    # should be one or zero for single-key addresses
                    if len(out.bip32_derivations.values()) > 0:
                        der = list(
                            out.bip32_derivations.values())[0].derivation
                        my_pubkey = self.root.derive(der)
                    if self.policy[
                            "type"] == "p2wpkh" and my_pubkey is not None:
                        sc = script.p2wpkh(my_pubkey)
                    elif self.policy[
                            "type"] == "p2sh-p2wpkh" and my_pubkey is not None:
                        sc = script.p2sh(script.p2wpkh(my_pubkey))

                    if sc.data == self.psbt.tx.vout[i].script_pubkey.data:
                        is_change = True

                if sc.data == self.psbt.tx.vout[i].script_pubkey.data:
                    is_change = True
            if is_change:
                self.change_amount += self.psbt.tx.vout[i].value
                self.self_addresses.append(
                    self.psbt.tx.vout[i].script_pubkey.address(
                        NETWORKS[self.network]))
            else:
                self.spend_amount += self.psbt.tx.vout[i].value
                self.destination_addresses.append(
                    self.psbt.tx.vout[i].script_pubkey.address(
                        NETWORKS[self.network]))

        self.fee_amount = self.psbt.fee()
        return True
Beispiel #8
0
    def change_fee_spend_amounts(
            self, tx, inp_amount, policy,
            currentnetwork) -> (float, float, float, str, float, float):
        spend = 0
        change = 0
        destinationaddress = ""
        dest_addr_cnt = 0
        outs = 0
        for i, out in enumerate(tx.outputs):
            outs += 1
            out_policy = self.get_policy(out, tx.tx.vout[i].script_pubkey,
                                         tx.xpubs)
            is_change = False
            # if policy is the same - probably change
            if out_policy == policy:
                # double-check that it's change
                # we already checked in get_cosigners and parse_multisig
                # that pubkeys are generated from cosigners,
                # and witness script is corresponding multisig
                # so we only need to check that scriptpubkey is generated from
                # witness script

                # empty script by default
                sc = script.Script(b"")
                # multisig, we know witness script
                if policy["type"] == "p2wsh":
                    sc = script.p2wsh(out.witness_script)
                elif policy["type"] == "p2sh-p2wsh":
                    sc = script.p2sh(script.p2wsh(out.witness_script))
                # single-sig native segwit
                elif "pkh" in policy["type"]:
                    for pub in out.bip32_derivations:
                        # check if it is our key
                        if out.bip32_derivations[
                                pub].fingerprint == self.fingerprint:
                            hdkey = self.root.derive(
                                out.bip32_derivations[pub].derivation)
                            mypub = hdkey.key.get_public_key()
                            if mypub != pub:
                                raise ValueError(
                                    "Derivation path doesn't look right")
                            # now check if provided scriptpubkey matches
                            sc = script.p2wpkh(mypub)
                            if sc == tx.tx.vout[i].script_pubkey:
                                is_change = True
                if sc.data == tx.tx.vout[i].script_pubkey.data:
                    is_change = True
            if is_change:
                change += tx.tx.vout[i].value
                print("Change %d sats" % tx.tx.vout[i].value)
            else:
                spend += tx.tx.vout[i].value
                print(
                    "Spending %d sats to %s" %
                    (tx.tx.vout[i].value, tx.tx.vout[i].script_pubkey.address(
                        NETWORKS[currentnetwork])))
                destinationaddress = tx.tx.vout[i].script_pubkey.address(
                    NETWORKS[currentnetwork])
                dest_addr_cnt += 1

        fee = inp_amount - change - spend

        return (change, fee, spend, destinationaddress, outs, dest_addr_cnt)
Beispiel #9
0
def main():
    # mnemonic we use
    mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
    seed = bip39.mnemonic_to_seed(mnemonic)
    root = bip32.HDKey.from_seed(seed)

    # A few transactions
    b64psbts = [
        # p2wsh, 2 inputs
        "cHNidP8BALICAAAAAq1DhxRK+mUH4T6uUNob8bUaZ7MP+44MW4+Y9bOxpjhZAAAAAAD9////aWclWQ+45HKrI07r878E2UrAupT2paT4QurbmtNjYNQBAAAAAP3///8CQEIPAAAAAAAiACCpkDPDhmIzPlkJrjw9A71xjbIUWf3VUB7ooFJhTVm04tjSIQEAAAAAIgAgjQKFDauIXsV5u23LBdYgOwX1FwGGrLiQfWzBtFKZ7dIAAAAATwEENYfPBD5i336AAAACQStJhNVJul7vHKbo83VdmuAW2m0WaXLKDlFANn7dUNoCNbhLMdw4Knz7Q7o6exdL6UFhQegW9nJb0SUStbLEpawUAgjLdzAAAIABAACAAAAAgAIAAIBPAQQ1h88EnbHQAIAAAAI/2Nc7x7iMpJNapTe/OJTV4oifqzQcYY9KV2+PGRjCdQJoww1WnSNqfcxXGyux0q1PqfmzUqgJNqKJCpmqI9t47BQmu4PEMAAAgAEAAIAAAACAAgAAgE8BBDWHzwS6wUg5gAAAAh1Pvr3ZZ+GvcUwJl9OPz2cLXOnTAcBEC7zDtqIOt3IcA1aOofNgUZFu0baQw54SqOcGA7KAvTDOXygfKRilU2OqFHPF2gowAACAAQAAgAAAAIACAACAAAEBK4CWmAAAAAAAIgAgiYAxcG7dnrEiZ4VHFVHOo18XCalvhZYuMqBr9n7HESQBBWlSIQJOjQgMfX26XEf+trHIEk3rYkEX5Y2NfrFKQARPcd2X8iEDBWHUgq25PfHvE+hlcBryJG7wo2y8jKUSPY7sd85OOMchA2iVcuKLD+2p1pgcAjfZ5d7b/sFt5xQ/aAoC7V0Vn3WHU64iBgJOjQgMfX26XEf+trHIEk3rYkEX5Y2NfrFKQARPcd2X8hwmu4PEMAAAgAEAAIAAAACAAgAAgAAAAAABAAAAIgYDBWHUgq25PfHvE+hlcBryJG7wo2y8jKUSPY7sd85OOMccAgjLdzAAAIABAACAAAAAgAIAAIAAAAAAAQAAACIGA2iVcuKLD+2p1pgcAjfZ5d7b/sFt5xQ/aAoC7V0Vn3WHHHPF2gowAACAAQAAgAAAAIACAACAAAAAAAEAAAAAAQErgJaYAAAAAAAiACAzd60wM9EFnPHSNbsSJfyipL8myVLVP2/vwzotVUSNxQEFaVIhAiKCMRLlzIhLkRbLIUIMx5KYJM0v6LcjW/mS6K7eFGwiIQKDzUflU23LeecRgzDo5IBCEvaWGfHW7JkNxzXvuc7FdCEDC5DtLoa61/Kk/pdpu0F9e6nKoRJIB9v7Ni377rZefgFTriIGAiKCMRLlzIhLkRbLIUIMx5KYJM0v6LcjW/mS6K7eFGwiHAIIy3cwAACAAQAAgAAAAIACAACAAAAAAAAAAAAiBgKDzUflU23LeecRgzDo5IBCEvaWGfHW7JkNxzXvuc7FdBwmu4PEMAAAgAEAAIAAAACAAgAAgAAAAAAAAAAAIgYDC5DtLoa61/Kk/pdpu0F9e6nKoRJIB9v7Ni377rZefgEcc8XaCjAAAIABAACAAAAAgAIAAIAAAAAAAAAAAAABAWlSIQKtIdmtKKuZrH7f2R4iIU8RWVOrCdHVWBCS+0e9pZJy/iEDoH074LrWPIA10hyXtBCJDT06GdLkA6+z/PxoJqomPHYhA6GoQ/otQdk71nUpYZFfbkSKdBkkSj4CuPTPYrzGp6JrU64iAgKtIdmtKKuZrH7f2R4iIU8RWVOrCdHVWBCS+0e9pZJy/hwCCMt3MAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgIDoH074LrWPIA10hyXtBCJDT06GdLkA6+z/PxoJqomPHYcc8XaCjAAAIABAACAAAAAgAIAAIABAAAAAAAAACICA6GoQ/otQdk71nUpYZFfbkSKdBkkSj4CuPTPYrzGp6JrHCa7g8QwAACAAQAAgAAAAIACAACAAQAAAAAAAAAAAA==",
        # p2sh-p2wsh
        "cHNidP8BAHICAAAAAR30J629i3Y/R8woRpLQ9JUa31rKxyM+Ny4NEsme48GWAAAAAAD9////Atw5XQUAAAAAF6kUdSESczdYagEyToVUSXyT8VTNz+OHgJaYAAAAAAAWABTmav7/w4OOcfCiewfjsA7eaujhYAAAAABPAQQ1h88EPmLffoAAAAHdXEj2dn8EYJ+rRdXEYu5laq6lJI5Mp+3t63ckwty05QKrJBNPewhwQaGPYRif6+XaxozFXvTXn7pU24H6fRy1FxQCCMt3MAAAgAEAAIAAAACAAQAAgE8BBDWHzwSdsdAAgAAAAeeOv56oeaaFTrNonMKDHk1C8brbWGFvdlecVue+v0/RAn/g4yI3oYsyen7OOcT7caYl4Mn7nQbyonHcusUR+GhzFCa7g8QwAACAAQAAgAAAAIABAACATwEENYfPBLrBSDmAAAABpzrb4oeEh2NNy/w/fr3osfyZTx7AaGDPAcP+LqeR3bYC5ioqmXPuazp69HwimlvecLylm9BLuyl/VpPXqiVrl20Uc8XaCjAAAIABAACAAAAAgAEAAIAAAQEgAOH1BQAAAAAXqRSv3gkn8731qcPbSDu4TJOlJJZ/PocBBCIAIOeiFBX5x0vX6CacrAUVovrs1DDCcKJS5qptFS3sjpDpAQVpUiECZ+pFYkOTVjB+eG+vQFA3MNjZWiA6DjRcs1Wl36A/zgMhA2Ygckuwjah29wiVRgA6wFx51+6ayrzeCIQ2eE4zfxPtIQOnUlBn22cn2CPCZkMSI6cDaZK2SlLV20rT6pqMoQCJsFOuIgYCZ+pFYkOTVjB+eG+vQFA3MNjZWiA6DjRcs1Wl36A/zgMcc8XaCjAAAIABAACAAAAAgAEAAIAAAAAAAAAAACIGA2Ygckuwjah29wiVRgA6wFx51+6ayrzeCIQ2eE4zfxPtHCa7g8QwAACAAQAAgAAAAIABAACAAAAAAAAAAAAiBgOnUlBn22cn2CPCZkMSI6cDaZK2SlLV20rT6pqMoQCJsBwCCMt3MAAAgAEAAIAAAACAAQAAgAAAAAAAAAAAAAEAIgAgZBwTq05RkpqKv6FV6LQjuM07Qv0/bYfWVc9NUQOFvwQBAWlSIQI32jVSdTgeu7+YZKrWfgOZ2J/LV36c5rBoApTzhrNlDCEC+hEqm3XmRt862AFFeyJ7p1m8A+V7czj6OajUNgCfg4EhA/MUVfxGh4k3Po3LB8CmMRsvIHcGNO0elUgETaITZA3UU64iAgI32jVSdTgeu7+YZKrWfgOZ2J/LV36c5rBoApTzhrNlDBwCCMt3MAAAgAEAAIAAAACAAQAAgAEAAAAAAAAAIgIC+hEqm3XmRt862AFFeyJ7p1m8A+V7czj6OajUNgCfg4EcJruDxDAAAIABAACAAAAAgAEAAIABAAAAAAAAACICA/MUVfxGh4k3Po3LB8CmMRsvIHcGNO0elUgETaITZA3UHHPF2gowAACAAQAAgAAAAIABAACAAQAAAAAAAAAAAA==",
        # p2wpkh
        "cHNidP8BAHECAAAAAc88WMMpgq4gUIjZvUnrmwKs3009rnalFsazBrFd46FOAAAAAAD9////Anw/XQUAAAAAFgAULzSqHPAKU7BVopGgOn1F8KaYi1KAlpgAAAAAABYAFOZq/v/Dg45x8KJ7B+OwDt5q6OFgAAAAAAABAR8A4fUFAAAAABYAFNDEo+8J6Ze26Z45flGP4+QaEYyhIgYC56slN7XUnpcDCargbp5J82zhyf671E7I4NHMoLT5wxkYc8XaClQAAIABAACAAAAAgAAAAAAAAAAAACICA11J7M1U0AmeQ2did8em1GJdYR2oil30m/lReneRp3elGHPF2gpUAACAAQAAgAAAAIABAAAAAAAAAAAA",
        # p2sh-p2wpkh
        "cHNidP8BAHICAAAAAXbva/K90EDzwdg6zLl0OfGrsaVWrR0PUpaB/6foypSKAQAAAAD9////Apw9XQUAAAAAF6kUJR3RFFeiWcO6R+XMo3F/5CFOApiHgJaYAAAAAAAWABTmav7/w4OOcfCiewfjsA7eaujhYAAAAAAAAQEgAOH1BQAAAAAXqRQzbKoT4IuWCAoytdgY1ZtKs7NnQocBBBYAFDiXH3OTD2wUHZd6xP1KcnyFSTWzIgYDoa+ASsEIqKUXghmMLQNLKL+QyIA/WlP3Ynb6aaTq538Yc8XaCjEAAIABAACAAAAAgAAAAAAAAAAAAAEAFgAUcL6x4EpQCUDp86uqZuGkmsVbjzUiAgKi/ImWxSYiSLXa78Wk0M3NAMEwR9DLEwKBNupjDYdahxhzxdoKMQAAgAEAAIAAAACAAQAAAAAAAAAAAA==",
    ]
    for i, b64psbt in enumerate(b64psbts):
        print("\nTransaction #%d" % (i + 1))
        raw = a2b_base64(b64psbt)
        tx = psbt.PSBT.parse(raw)

        # Check inputs of the transaction and check that they use the same script type
        # For multisig parsed policy will look like this:
        # { script_type: p2wsh, cosigners: [xpubs strings], m: 2, n: 3}
        policy = None
        inp_amount = 0
        for inp in tx.inputs:
            inp_amount += inp.witness_utxo.value
            # get policy of the input
            inp_policy = get_policy(inp, inp.witness_utxo.script_pubkey,
                                    tx.xpubs)
            # if policy is None - assign current
            if policy is None:
                policy = inp_policy
            # otherwise check that everything in the policy is the same
            else:
                # check policy is the same
                if policy != inp_policy:
                    raise RuntimeError("Mixed inputs in the transaction")

        wallet = "Native Segwit "
        if "p2sh-" in policy["type"]:
            wallet = "Nested Segwit "
        if "m" in policy:
            wallet += "Multisig (%d of %d)" % (policy["m"], policy["n"])
        else:
            wallet += "Single sig"
        print("Spending from: %s" % wallet)
        print("Input amount: %d sat" % inp_amount)
        # now go through outputs and check if they are change
        spending = 0
        change = 0
        for i, out in enumerate(tx.outputs):
            out_policy = get_policy(out, tx.tx.vout[i].script_pubkey, tx.xpubs)
            is_change = False
            # if policy is the same - probably change
            if out_policy == policy:
                # double-check that it's change
                # we already checked in get_cosigners and parse_multisig
                # that pubkeys are generated from cosigners,
                # and witness script is corresponding multisig
                # so we only need to check that scriptpubkey is generated from
                # witness script

                # empty script by default
                sc = script.Script(b"")
                # multisig, we know witness script
                if policy["type"] == "p2wsh":
                    sc = script.p2wsh(out.witness_script)
                elif policy["type"] == "p2sh-p2wsh":
                    sc = script.p2sh(script.p2wsh(out.witness_script))
                # single-sig
                elif "pkh" in policy["type"]:
                    if len(out.bip32_derivations.values()) > 0:
                        der = list(
                            out.bip32_derivations.values())[0].derivation
                        my_pubkey = root.derive(der)
                    if policy["type"] == "p2wpkh":
                        sc = script.p2wpkh(my_pubkey)
                    elif policy["type"] == "p2sh-p2wpkh":
                        sc = script.p2sh(script.p2wpkh(my_pubkey))
                if sc.data == tx.tx.vout[i].script_pubkey.data:
                    is_change = True
            if is_change:
                change += tx.tx.vout[i].value
                print("Change %d sats" % tx.tx.vout[i].value)
            else:
                spending += tx.tx.vout[i].value
                print("Spending %d sats to %s" %
                      (tx.tx.vout[i].value,
                       tx.tx.vout[i].script_pubkey.address()))

        fee = inp_amount - change - spending
        print("Fee: %d sats" % fee)