ethereum / eth-utils

Utility functions for working with ethereum related codebases.
https://eth-utils.readthedocs.io/en/latest/
MIT License
312 stars 148 forks source link

Utilities for Contract ABIs #271

Closed reedsa closed 1 month ago

reedsa commented 5 months ago

What was wrong?

Contract ABI utilities are useful for encoding and decoding contract transactions. Many utilities are implemented in web3.py as private methods.

Related to https://github.com/ethereum/web3.py/issues/3036

Many of these functions were previously private in web3.py but these public utilities are used as of v7. See https://github.com/ethereum/web3.py/pull/3408

How was it fixed?

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

The following functions have been added to the eth_utils.abi module: abi_to_signature, collapse_if_tuple, filter_abi_by_name, filter_abi_by_type, get_abi_input_names, get_abi_input_types, get_abi_output_names, get_abi_output_types, get_aligned_abi_inputs, get_all_event_abis, get_all_function_abis, get_normalized_abi_inputs,

Todo:

Cute Animal Picture

Screen Shot 2024-04-12 at 3 16 35 PM
pacrob commented 4 months ago

Usage question - I pulled an ABI from web3 (extended_resolver.py), use get_all_function_abis to get function info, then take a name from that, say supportsInterface. From the description, I should be able to plug the abi and the function name into get_function_abi and get the same info back about that function, but I get:

MismatchedABI: 
Could not identify the intended function with name `supportsInterface`, positional arguments with type(s) `` and keyword arguments with type(s) `{}`.
Found 1 function(s) with the name `supportsInterface`: ['supportsInterface(bytes4)']
Function invocation failed due to improper number of arguments.

Same for get_function_info.

reedsa commented 4 months ago

Cleaned things up and addressed feedback, thanks!

reedsa commented 4 months ago

@kclowes @fselmo this is ready for another look.

reedsa commented 3 months ago

This is still a WIP. Keeping the ABI methods but codec utils will move into web3.utils.abi.

reedsa commented 3 months ago

Cleaning up a few more items on this and I will request reviews when it's good to go!

fselmo commented 2 months ago

I think all my concerns were addressed here. Will wait to approve once the eth-typing branch / version gets decided and updated rather than using the git commit hash for the branch.

reedsa commented 2 months ago

I'm inclined to publish a major version for this then, with hexbytes being the new dependency. @fselmo @kclowes @pacrob

reedsa commented 2 months ago

We can hold this until after eth-typing v5 is released and I can update the pin.

kclowes commented 2 months ago

I could change these to be real fixtures...

Does this mean something like:

@pytest.fixture
def fn_abi_a():
    return {"name": "tokenLaunched", "type": "function", "inputs": []}

If ^ is the way you were thinking, I wonder if we could just pass around the fixture sort of like you have it now, instead of the string of the fixture name. So something like:

def build_contract_abi(*abis):
    ...

Another thought that came to mind was reusing these fixtures across libs so that I can pull them in to tests in web3.py

I could see an eth-utils module that exported these ABIs. Although, if they're being tested here, does it add value to also test them in web3? The other thing to think about is that if they live in eth-utils, for example, to update the fixtures we'd have to make the change in eth-utils, release and then pull that release into web3.

reedsa commented 2 months ago

Coupled releases would not be ideal, that's a good point. The only motivation for reusing these elements is so that the utilities are run through a wide range of cases. I dont mind having some duplication of these cases across libs.

I did mean use the @pytest.fixture as you outlined but I think the constant variables are fine too. I am planning to put them in a separate file at least, maybe just something like abi_data.py in tests/core/abi-utils alongside the tests.

So this is likely what I'll end up with:

ABI_FUNCTION_TOKEN_LAUNCHED = ABIFunction({"name": "tokenLaunched", "type": "function", "inputs": []})

So basically I'll just clean up what I have, splitting out the constant vars into a new file and making sure the tests are covered. I'll still use that build_contract_abi function as well. 👍

kclowes commented 2 months ago

Cool, that sounds good to me!

reedsa commented 2 months ago

Had trouble with pytest importing the variables from another file, I guess fixtures are the only way to do that. Given these arent being shared across tests within the library, I'll just keep them in the test file itself after all. This is good for another look now! @kclowes @fselmo @pacrob

reedsa commented 1 month ago

@pacrob @fselmo @kclowes This is good for a final check, it's functioning as I'd expect with the ABI utils I added to web3.