address.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import re
  2. from typing import (
  3. Any,
  4. Union,
  5. cast,
  6. )
  7. from eth_typing import (
  8. Address,
  9. AnyAddress,
  10. ChecksumAddress,
  11. HexAddress,
  12. HexStr,
  13. )
  14. from .conversions import (
  15. hexstr_if_str,
  16. to_hex,
  17. )
  18. from .crypto import (
  19. keccak,
  20. )
  21. from .hexadecimal import (
  22. add_0x_prefix,
  23. decode_hex,
  24. encode_hex,
  25. remove_0x_prefix,
  26. )
  27. from .types import (
  28. is_bytes,
  29. is_text,
  30. )
  31. _HEX_ADDRESS_REGEXP = re.compile("(0x)?[0-9a-f]{40}", re.IGNORECASE | re.ASCII)
  32. def is_hex_address(value: Any) -> bool:
  33. """
  34. Checks if the given string of text type is an address in hexadecimal encoded form.
  35. """
  36. if not is_text(value):
  37. return False
  38. return _HEX_ADDRESS_REGEXP.fullmatch(value) is not None
  39. def is_binary_address(value: Any) -> bool:
  40. """
  41. Checks if the given string is an address in raw bytes form.
  42. """
  43. if not is_bytes(value):
  44. return False
  45. elif len(value) != 20:
  46. return False
  47. else:
  48. return True
  49. def is_address(value: Any) -> bool:
  50. """
  51. Is the given string an address in any of the known formats?
  52. """
  53. if is_hex_address(value) or is_binary_address(value):
  54. return True
  55. return False
  56. def to_normalized_address(value: Union[AnyAddress, str, bytes]) -> HexAddress:
  57. """
  58. Converts an address to its normalized hexadecimal representation.
  59. """
  60. try:
  61. hex_address = hexstr_if_str(to_hex, value).lower()
  62. except AttributeError:
  63. raise TypeError(f"Value must be any string, instead got type {type(value)}")
  64. if is_address(hex_address):
  65. return HexAddress(HexStr(hex_address))
  66. else:
  67. raise ValueError(
  68. f"Unknown format {repr(value)}, attempted to normalize to "
  69. f"{repr(hex_address)}"
  70. )
  71. def is_normalized_address(value: Any) -> bool:
  72. """
  73. Returns whether the provided value is an address in its normalized form.
  74. """
  75. if not is_address(value):
  76. return False
  77. else:
  78. is_equal = value == to_normalized_address(value)
  79. return cast(bool, is_equal)
  80. def to_canonical_address(address: Union[AnyAddress, str, bytes]) -> Address:
  81. """
  82. Convert a valid address to its canonical form (20-length bytes).
  83. """
  84. return Address(decode_hex(to_normalized_address(address)))
  85. def is_canonical_address(address: Any) -> bool:
  86. """
  87. Returns `True` if the `value` is an address in its canonical form.
  88. """
  89. if not is_bytes(address) or len(address) != 20:
  90. return False
  91. is_equal = address == to_canonical_address(address)
  92. return cast(bool, is_equal)
  93. def is_same_address(
  94. left: Union[AnyAddress, str, bytes], right: Union[AnyAddress, str, bytes]
  95. ) -> bool:
  96. """
  97. Checks if both addresses are same or not.
  98. """
  99. if not is_address(left) or not is_address(right):
  100. raise ValueError("Both values must be valid addresses")
  101. else:
  102. return bool(to_normalized_address(left) == to_normalized_address(right))
  103. def to_checksum_address(value: Union[AnyAddress, str, bytes]) -> ChecksumAddress:
  104. """
  105. Makes a checksum address given a supported format.
  106. """
  107. norm_address = to_normalized_address(value)
  108. address_hash = encode_hex(keccak(text=remove_0x_prefix(HexStr(norm_address))))
  109. checksum_address = add_0x_prefix(
  110. HexStr(
  111. "".join(
  112. (
  113. norm_address[i].upper()
  114. if int(address_hash[i], 16) > 7
  115. else norm_address[i]
  116. )
  117. for i in range(2, 42)
  118. )
  119. )
  120. )
  121. return ChecksumAddress(HexAddress(checksum_address))
  122. def is_checksum_address(value: Any) -> bool:
  123. if not is_text(value):
  124. return False
  125. if not is_hex_address(value):
  126. return False
  127. is_equal = value == to_checksum_address(value)
  128. return cast(bool, is_equal)
  129. def _is_checksum_formatted(value: Any) -> bool:
  130. unprefixed_value = remove_0x_prefix(value)
  131. return (
  132. not unprefixed_value.islower()
  133. and not unprefixed_value.isupper()
  134. and not unprefixed_value.isnumeric()
  135. )
  136. def is_checksum_formatted_address(value: Any) -> bool:
  137. return is_hex_address(value) and _is_checksum_formatted(value)