diff --git a/cashaddress/convert.py b/cashaddress/convert.py index 12bb758..72879a4 100644 --- a/cashaddress/convert.py +++ b/cashaddress/convert.py @@ -43,12 +43,18 @@ def legacy_address(self): version_int = Address._address_type('legacy', self.version)[1] return b58encode_check(Address.code_list_to_string([version_int] + self.payload)) - def cash_address(self): + def cash_address(self, prefix=None): + prefix = prefix if prefix is not None else self.prefix + self._check_case(prefix) + is_uppercase = prefix == prefix.upper() version_int = Address._address_type('cash', self.version)[1] payload = [version_int] + self.payload payload = convertbits(payload, 8, 5) - checksum = calculate_checksum(self.prefix, payload) - return self.prefix + ':' + b32encode(payload + checksum) + checksum = calculate_checksum(prefix, payload) + address_string = prefix + ':' + b32encode(payload + checksum) + if is_uppercase: + return address_string.upper() + return address_string @staticmethod def code_list_to_string(code_list): @@ -94,8 +100,7 @@ def _legacy_string(address_string): @staticmethod def _cash_string(address_string): - if address_string.upper() != address_string and address_string.lower() != address_string: - raise InvalidAddress('Cash address contains uppercase and lowercase characters') + Address._check_case(address_string) address_string = address_string.lower() colon_count = address_string.count(':') if colon_count == 0: @@ -113,6 +118,11 @@ def _cash_string(address_string): payload = converted[1:-6] return Address(version, payload, prefix) + @staticmethod + def _check_case(text): + if text.upper() != text and text.lower() != text: + raise InvalidAddress('Cash address contains uppercase and lowercase characters') + def to_cash_address(address): return Address.from_string(address).cash_address() diff --git a/tests/test.py b/tests/test.py index a95efff..8dd05e4 100644 --- a/tests/test.py +++ b/tests/test.py @@ -1,6 +1,7 @@ import unittest from cashaddress import convert +from cashaddress.convert import Address, InvalidAddress class TestConversion(unittest.TestCase): @@ -61,5 +62,42 @@ def test_is_valid(self): self.assertFalse(convert.is_valid(False)) self.assertFalse(convert.is_valid('Hello World!')) + def test_prefixes(self): + """Test a few identical addresses with different CashAddr prefixes""" + legacy_address = "1NLcNpAaBBMekgBZk7NxwdxwtSUTfTV8Aq" + addr = Address.from_string(legacy_address) + default_prefix = addr.prefix + self.assertEqual(default_prefix, Address.MAINNET_PREFIX) + self.assertEqual(addr.cash_address(), + 'bitcoincash:qr4pqy6q4cy2d50zpaek57nnrja7289fkskz6jm7yf') + self.assertEqual(addr.cash_address(prefix='abc'), + 'abc:qr4pqy6q4cy2d50zpaek57nnrja7289fksqt4c50w9') + self.assertEqual(addr.cash_address(prefix='simpleledger'), + 'simpleledger:qr4pqy6q4cy2d50zpaek57nnrja7289fks6e3fw76h') + + regtest_address = 'regtest:qr4pqy6q4cy2d50zpaek57nnrja7289fksjm6es9se' + addr2 = Address.from_string(regtest_address) + self.assertEqual(addr2.legacy_address(), legacy_address) + # The prefix defaults to the one in the input string. + self.assertEqual(addr2.prefix, 'regtest') + self.assertEqual(addr2.cash_address(), regtest_address) + + def test_prefix_case(self): + with self.assertRaises(InvalidAddress): + Address.from_string( + 'rEgTeSt:qr4pqy6q4cy2d50zpaek57nnrja7289fksjm6es9se') + with self.assertRaises(InvalidAddress): + Address.from_string( + 'regtest:QR4PQY6Q4CY2D50ZPAEK57NNRJA7289FKSJM6ES9SE') + + addr = Address.from_string('regtest:qr4pqy6q4cy2d50zpaek57nnrja7289fksjm6es9se') + # The address should take the same case as the specified prefix + self.assertEqual(addr.cash_address(prefix="SLP"), + 'SLP:QR4PQY6Q4CY2D50ZPAEK57NNRJA7289FKSWF89PY2G') + # Do not allow mixed-case prefixes + with self.assertRaises(InvalidAddress): + addr.cash_address(prefix="sLp") + + if __name__ == '__main__': unittest.main()