ethereum / web3.py

A python interface for interacting with the Ethereum blockchain and ecosystem.
http://web3py.readthedocs.io
MIT License
4.97k stars 1.69k forks source link

Function ABI Utilities #3408

Closed reedsa closed 2 months ago

reedsa commented 4 months ago

What was wrong?

Function ABI utilties are needed for some use cases, so exposing them as public methods will allow people to work with ABIs and encode/decode function arguments.

Related to Issue #3036, #1596

Dependent upon https://github.com/ethereum/eth-utils/pull/271.

How was it fixed?

Implement functions for parsing and validating contract data using the ABI spec.

Public ABI methods in web3.utils.abi: check_if_arguments_can_be_encoded, get_abi_element_info, get_abi_element, get_event_abi, get_event_log_topics, log_topic_to_bytes,

Additionally, all eth_utils.abi functions are included as part of the web3.utils module.

Todo:

Cute Animal Picture

Put a link to a cute animal picture inside the parenthesis-->

reedsa commented 2 months ago

@kclowes @fselmo @pacrob

I haven't come across a way to return specific ABI types from those functions, so casting to the types makes mypy happy. The problem is the type is based on the value of the TypedDict at runtime. There might be a way to pass a separate parameter and create overrides that return the expected type, then it would require logic to branch each of those wherever those functions are used.

Maybe something like this would work?

@override
def get_abi_element(
    abi: ABI,
    function_identifier: FunctionIdentifier,
    *args: Optional[Sequence[Any]],
    abi_codec: Optional[Any] = None,
    **kwargs: Optional[Dict[str, Any]],
    abi_type: Literal['function']
): ABIFunction

def get_abi_element(
    abi: ABI,
    function_identifier: FunctionIdentifier,
    *args: Optional[Sequence[Any]],
    abi_codec: Optional[Any] = None,
    **kwargs: Optional[Dict[str, Any]],
    abi_type: str
) -> ABIElement:
  ...

def some_func():
  if(abi["type"] == "function"):
    abi = get_abi_element(abi, ..., "function")
  if(abi["type"] == "constructor"):
    abi = get_abi_element(abi, ..., "constructor")

I think the types of abi would then follow the overrides to make mypy happy. Havent tried that yet though. Let me know if there are other ideas or feedback on the changes I've made thus far!

reedsa commented 2 months ago

@pacrob @fselmo @kclowes I've merged changes that include functions for event ABIs and added some polish. I am ready for another pass on this now that it's functioning with the latest version of eth-utils.