from typing import ( Any, Dict, ) from .conversions import ( to_bytes ) from ...keccak import ( SHA3 as keccak, ) def collapse_if_tuple(abi: Dict[str, Any]) -> str: """ Converts a tuple from a dict to a parenthesized list of its types. >>> from eth_utils.abi import collapse_if_tuple >>> collapse_if_tuple( ... { ... 'components': [ ... {'name': 'anAddress', 'type': 'address'}, ... {'name': 'anInt', 'type': 'uint256'}, ... {'name': 'someBytes', 'type': 'bytes'}, ... ], ... 'type': 'tuple', ... } ... ) '(address,uint256,bytes)' """ typ = abi["type"] if not isinstance(typ, str): raise TypeError( f"The 'type' must be a string, but got {repr(typ)} of type {type(typ)}" ) elif not typ.startswith("tuple"): return typ delimited = ",".join(collapse_if_tuple(c) for c in abi["components"]) # Whatever comes after "tuple" is the array dims. The ABI spec states that # this will have the form "", "[]", or "[k]". array_dim = typ[5:] collapsed = f"({delimited}){array_dim}" return collapsed def _abi_to_signature(abi: Dict[str, Any]) -> str: fn_input_types = ",".join( [collapse_if_tuple(abi_input) for abi_input in abi.get("inputs", [])] ) function_signature = f"{abi['name']}({fn_input_types})" return function_signature def function_signature_to_4byte_selector(event_signature: str) -> bytes: return keccak(to_bytes(text=event_signature.replace(" ", "")))[:4] def function_abi_to_4byte_selector(function_abi: Dict[str, Any]) -> bytes: function_signature = _abi_to_signature(function_abi) return function_signature_to_4byte_selector(function_signature) def event_signature_to_log_topic(event_signature: str) -> bytes: return keccak(to_bytes(text=event_signature.replace(" ", ""))) def event_abi_to_log_topic(event_abi: Dict[str, Any]) -> bytes: event_signature = _abi_to_signature(event_abi) return event_signature_to_log_topic(event_signature)