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