ranaroussi / pywallet

Dead-simple BIP32 (HD) wallet creation for BTC, BTG, BCH, LTC, DASH, USDT, QTUM and DOGE
MIT License
454 stars 180 forks source link

Suport for BIP49 ypub for wallet.create_address #4

Open mfbrj opened 6 years ago

mfbrj commented 6 years ago

Can you add support for BIP49 segwit addresses?

It uses a new BIP32 Extended Public Key format.

For example, the Extended Public Key ypub6ZNNVLvwe6gJsPyNiukiYEgVWvdeP3M5xx1qGzTo67FiEFJvcCB6ApXZTLBiuMiKhvNfmdcssJ3MbLMQfWjgbJ9dHHMrWxx6Vkb93r7Zb3y generates these address:

m/49'/0'/0'/0/0 39kb8ZPfyj2QsbdEGSCUuAZxXsJpC6sx4c
m/49'/0'/0'/0/1 32yn1GcQpYLdGtFCTKSNiXdhHgGyQPQKSx
m/49'/0'/0'/0/2 3FLXaYJfn5iozDtWvCmwwPRkViMBgRsZ8P
m/49'/0'/0'/0/3 38qQ1Mhi6BDQEGQR4n4jwH93uRbTy19CNe
m/49'/0'/0'/0/4 37oJY4zyjd7h34gsdDGR9vN1aLBYDEhmSh
m/49'/0'/0'/0/5 35etreLmK43naK9kqkMJp1iJFEUnxHfdRG
m/49'/0'/0'/0/6 3Ft5hWpSPChT8EFaFdW4FDzxEJ9YkxDDRq
m/49'/0'/0'/0/7 39uXxCT6kGxPYwtKyiXx1jPYxJX8RUTgFS
m/49'/0'/0'/0/8 3NGKHXYN7CP9ZzPkz1pnWZmbNUhiKy8vfB
m/49'/0'/0'/0/9 342ywv1E7VoQH9PHfNK2VCZh1VBoKfxGWC
iteratelance commented 5 years ago

See also #38

I was able to make this work for my purposes but modifying bip32.py, please note that this implementation will return a bad value for bip32_path and will only work for BIP49, I thought this might be helpful to someone. I think the right way to go about this is to add a new network config to network.py. Maybe I'll get the courage and time one day to go about doing that.

bip32.py

line 485 in bip32.py

    def to_address(self):
        """Create a public address from this Wallet.

        Public addresses can accept payments.

        https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses
        """
        key = unhexlify(self.get_public_key_hex())
        # First get the hash160 of the key
        hash160_bytes = hash160(key)
        # Prepend the network address byte

        # if BIP32 - comment this out for testing
        #network_hash160_bytes = \
            #chr_py2(self.network.PUBKEY_ADDRESS) + hash160_bytes

        # if BIP49
        script_sig = bytes.fromhex('0014') + hash160_bytes
        address_bytes = hash160(script_sig)
        network_hash160_bytes = \
            chr_py2(self.network.SCRIPT_ADDRESS) + address_bytes
        # print(self.network.PUBKEY_ADDRESS)

        # Return a base58 encoded address with a checksum

        return ensure_str(base58.b58encode_check(network_hash160_bytes))

line 567 in bip32.py - comment out the network check for testing

        elif point_type in [2, 3, 4]:
            # Compressed public coordinates
            # if version_long != network.EXT_PUBLIC_KEY:
            #     raise incompatible_network_exception_factory(
            #         network.NAME, network.EXT_PUBLIC_KEY,
            #         version)
            pubkey = PublicKey.from_hex_key(key_data, network=network)
            # Even though this was generated from a compressed pubkey, we
            # want to store it as an uncompressed pubkey
            pubkey.compressed = False