Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions hdwallet/addresses/bitcoincash.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@
from .iaddress import IAddress


from enum import IntEnum

class BitcoinCashAddressType(IntEnum):
P2PKH = 0b0000
P2SH = 0b0001
P2PKH_WITH_TOKENS = 0b0010
P2SH_WITH_TOKENS = 0b0011

@property
def label(self):
mapping = {
BitcoinCashAddressType.P2PKH: "P2PKH",
BitcoinCashAddressType.P2SH: "P2SH",
BitcoinCashAddressType.P2PKH_WITH_TOKENS: "P2PKH_WITH_TOKENS",
BitcoinCashAddressType.P2SH_WITH_TOKENS: "P2SH_WITH_TOKENS"
}
return mapping.get(self, "Unknown Type")

class BitcoinCashAddress(IAddress):

hrp: str = BitcoinCash.NETWORKS.MAINNET.HRP
Expand Down Expand Up @@ -55,7 +73,7 @@ def encode(cls, public_key: Union[bytes, str, IPublicKey], **kwargs: Any) -> str
:return: The encoded CashAddr address.
:rtype: str
"""
hrp = kwargs.get("hrp", cls.hrp)
hrp = kwargs.get("prefix") or kwargs.get("hrp", cls.hrp)
public_key_address_prefix = kwargs.get("public_key_address_prefix", cls.public_key_address_prefix)

public_key: IPublicKey = validate_and_get_public_key(
Expand All @@ -69,7 +87,8 @@ def encode(cls, public_key: Union[bytes, str, IPublicKey], **kwargs: Any) -> str

# CashAddr version byte: 0 for P2PKH, 1 for P2SH
version_byte = 0x00 # P2PKH with 160-bit hash

if kwargs.get('token_support'):
version_byte = 0x10
# Pack version and hash
payload = bytes([version_byte]) + public_key_hash

Expand Down Expand Up @@ -97,7 +116,7 @@ def encode(cls, public_key: Union[bytes, str, IPublicKey], **kwargs: Any) -> str
return ensure_string(hrp + ':' + ''.join([CHARSET[d] for d in combined]))

@classmethod
def decode(cls, address: str, **kwargs: Any) -> str:
def decode(cls, address: str, **kwargs: Any) -> str or dict:
"""
Decode a Bitcoin Cash CashAddr address.

Expand All @@ -110,7 +129,7 @@ def decode(cls, address: str, **kwargs: Any) -> str:
:return: The decoded address as a string.
:rtype: str
"""
hrp_expected = kwargs.get("hrp", cls.hrp)
hrp_expected = [BitcoinCash.NETWORKS.MAINNET.HRP, BitcoinCash.NETWORKS.TESTNET.HRP, BitcoinCash.NETWORKS.REGTEST.HRP]

# Parse address
if ':' in address:
Expand Down Expand Up @@ -142,7 +161,7 @@ def decode(cls, address: str, **kwargs: Any) -> str:
if polymod != 0:
raise ValueError("Invalid CashAddr checksum")

if hrp and hrp != hrp_expected:
if hrp and hrp not in hrp_expected:
raise ValueError(f"Invalid HRP (expected: {hrp_expected}, got: {hrp})")

# Remove 8-byte checksum
Expand All @@ -156,5 +175,11 @@ def decode(cls, address: str, **kwargs: Any) -> str:
# First byte is version, rest is hash
version = decoded[0]
address_hash = bytes(decoded[1:])

return bytes_to_string(address_hash)
if kwargs.get('decode_type'):
type_bits = (version & 0b01111000) >> 3
address_type = BitcoinCashAddressType(type_bits)
return {
'payload': bytes_to_string(address_hash),
'type': address_type.label
}
return bytes_to_string(address_hash)