| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861 |
- from collections import (
- abc,
- )
- import copy
- import itertools
- import re
- from typing import (
- Any,
- Dict,
- Iterable,
- List,
- Literal,
- Mapping,
- Optional,
- Sequence,
- Tuple,
- Union,
- cast,
- overload,
- )
- from eth_typing import (
- ABI,
- ABIComponent,
- ABIConstructor,
- ABIElement,
- ABIError,
- ABIEvent,
- ABIFallback,
- ABIFunction,
- ABIReceive,
- )
- from eth_utils.types import (
- is_list_like,
- )
- from .crypto import (
- keccak,
- )
- def _align_abi_input(
- arg_abi: ABIComponent, normalized_arg: Any
- ) -> Union[Any, Tuple[Any, ...]]:
- """
- Aligns the values of any mapping at any level of nesting in ``normalized_arg``
- according to the layout of the corresponding abi spec.
- """
- tuple_parts = _get_tuple_type_str_and_dims(arg_abi.get("type", ""))
- if tuple_parts is None:
- # normalized_arg is non-tuple. Just return value.
- return normalized_arg
- tuple_prefix, tuple_dims = tuple_parts
- if tuple_dims is None:
- # normalized_arg is non-list tuple. Each sub arg in `normalized_arg` will be
- # aligned according to its corresponding abi.
- sub_abis = cast(Iterable[ABIComponent], arg_abi.get("components", []))
- else:
- num_dims = tuple_dims.count("[")
- # normalized_arg is list tuple. A non-list version of its abi will be used to
- # align each element in `normalized_arg`.
- new_abi = copy.copy(arg_abi)
- new_abi["type"] = tuple_prefix + "[]" * (num_dims - 1)
- sub_abis = itertools.repeat(new_abi)
- if isinstance(normalized_arg, abc.Mapping):
- # normalized_arg is mapping. Align values according to abi order.
- aligned_arg = tuple(normalized_arg[abi["name"]] for abi in sub_abis)
- else:
- aligned_arg = normalized_arg
- if not is_list_like(aligned_arg):
- raise TypeError(
- f'Expected non-string sequence for "{arg_abi.get("type")}" '
- f"component type: got {aligned_arg}"
- )
- # convert NamedTuple to regular tuple
- typing = tuple if isinstance(aligned_arg, tuple) else type(aligned_arg)
- return typing(
- _align_abi_input(sub_abi, sub_arg)
- for sub_abi, sub_arg in zip(sub_abis, aligned_arg)
- )
- def _get_tuple_type_str_and_dims(s: str) -> Optional[Tuple[str, Optional[str]]]:
- """
- Takes a JSON ABI type string. For tuple type strings, returns the separated
- prefix and array dimension parts. For all other strings, returns ``None``.
- """
- tuple_type_str_re = "^(tuple)((\\[([1-9]\\d*\b)?])*)??$"
- match = re.compile(tuple_type_str_re).match(s)
- if match is not None:
- tuple_prefix = match.group(1)
- tuple_dims = match.group(2)
- return tuple_prefix, tuple_dims
- return None
- def _raise_if_not_function_abi(abi_element: ABIElement) -> None:
- if abi_element["type"] != "function":
- raise ValueError(
- f"Outputs only supported for ABI type `function`. Provided"
- f" ABI type was `{abi_element.get('type')}` and outputs were "
- f"`{abi_element.get('outputs')}`."
- )
- def _raise_if_fallback_or_receive_abi(abi_element: ABIElement) -> None:
- if abi_element["type"] == "fallback" or abi_element["type"] == "receive":
- raise ValueError(
- f"Inputs not supported for function types `fallback` or `receive`. Provided"
- f" ABI type was `{abi_element.get('type')}` with inputs "
- f"`{abi_element.get('inputs')}`."
- )
- def collapse_if_tuple(abi: Union[ABIComponent, Dict[str, Any], str]) -> str:
- """
- Extract argument types from a function or event ABI parameter.
- With tuple argument types, return a Tuple of each type.
- Returns the param if `abi` is an instance of str or another non-tuple
- type.
- :param abi: A Function or Event ABI component or a string with type info.
- :type abi: `Union[ABIComponent, Dict[str, Any], str]`
- :return: Type(s) for the function or event ABI param.
- :rtype: `str`
- .. doctest::
- >>> from eth_utils.abi import collapse_if_tuple
- >>> abi = {
- ... 'components': [
- ... {'name': 'anAddress', 'type': 'address'},
- ... {'name': 'anInt', 'type': 'uint256'},
- ... {'name': 'someBytes', 'type': 'bytes'},
- ... ],
- ... 'type': 'tuple',
- ... }
- >>> collapse_if_tuple(abi)
- '(address,uint256,bytes)'
- """
- if isinstance(abi, str):
- return abi
- element_type = abi.get("type")
- if not isinstance(element_type, str):
- raise TypeError(
- f"The 'type' must be a string, but got {repr(element_type)} of type "
- f"{type(element_type)}"
- )
- elif not element_type.startswith("tuple"):
- return element_type
- 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 = element_type[5:]
- collapsed = f"({delimited}){array_dim}"
- return collapsed
- def abi_to_signature(abi_element: ABIElement) -> str:
- """
- Returns a string signature representation of the function or event ABI
- and arguments.
- Signatures consist of the name followed by a list of arguments.
- :param abi_element: ABI element.
- :type abi_element: `ABIElement`
- :return: Stringified ABI signature
- :rtype: `str`
- .. doctest::
- >>> from eth_utils import abi_to_signature
- >>> abi_element = {
- ... 'constant': False,
- ... 'inputs': [
- ... {
- ... 'name': 's',
- ... 'type': 'uint256'
- ... }
- ... ],
- ... 'name': 'f',
- ... 'outputs': [],
- ... 'payable': False,
- ... 'stateMutability': 'nonpayable',
- ... 'type': 'function'
- ... }
- >>> abi_to_signature(abi_element)
- 'f(uint256)'
- """
- signature = "{name}({input_types})"
- abi_type = str(abi_element.get("type", ""))
- if abi_type == "fallback" or abi_type == "receive":
- return signature.format(name=abi_type, input_types="")
- if abi_type == "constructor":
- fn_name = abi_type
- else:
- fn_name = str(abi_element.get("name", abi_type))
- return signature.format(
- name=fn_name, input_types=",".join(get_abi_input_types(abi_element))
- )
- def filter_abi_by_name(abi_name: str, contract_abi: ABI) -> Sequence[ABIElement]:
- """
- Get one or more function and event ABIs by name.
- :param abi_name: Name of the function, event or error.
- :type abi_name: `str`
- :param contract_abi: Contract ABI.
- :type contract_abi: `ABI`
- :return: Function or event ABIs with matching name.
- :rtype: `Sequence[ABIElement]`
- .. doctest::
- >>> from eth_utils.abi import filter_abi_by_name
- >>> abi = [
- ... {
- ... "constant": False,
- ... "inputs": [],
- ... "name": "func_1",
- ... "outputs": [],
- ... "type": "function",
- ... },
- ... {
- ... "constant": False,
- ... "inputs": [
- ... {"name": "a", "type": "uint256"},
- ... ],
- ... "name": "func_2",
- ... "outputs": [],
- ... "type": "function",
- ... },
- ... {
- ... "constant": False,
- ... "inputs": [
- ... {"name": "a", "type": "uint256"},
- ... {"name": "b", "type": "uint256"},
- ... ],
- ... "name": "func_3",
- ... "outputs": [],
- ... "type": "function",
- ... },
- ... {
- ... "constant": False,
- ... "inputs": [
- ... {"name": "a", "type": "uint256"},
- ... {"name": "b", "type": "uint256"},
- ... {"name": "c", "type": "uint256"},
- ... ],
- ... "name": "func_4",
- ... "outputs": [],
- ... "type": "function",
- ... },
- ... ]
- >>> filter_abi_by_name("func_1", abi)
- [{'constant': False, 'inputs': [], 'name': 'func_1', 'outputs': [], \
- 'type': 'function'}]
- """
- return [
- abi
- for abi in contract_abi
- if (
- (
- abi["type"] == "function"
- or abi["type"] == "event"
- or abi["type"] == "error"
- )
- and abi["name"] == abi_name
- )
- ]
- @overload
- def filter_abi_by_type(
- abi_type: Literal["function"],
- contract_abi: ABI,
- ) -> Sequence[ABIFunction]:
- pass
- @overload
- def filter_abi_by_type(
- abi_type: Literal["constructor"],
- contract_abi: ABI,
- ) -> Sequence[ABIConstructor]:
- pass
- @overload
- def filter_abi_by_type(
- abi_type: Literal["fallback"],
- contract_abi: ABI,
- ) -> Sequence[ABIFallback]:
- pass
- @overload
- def filter_abi_by_type(
- abi_type: Literal["receive"],
- contract_abi: ABI,
- ) -> Sequence[ABIReceive]:
- pass
- @overload
- def filter_abi_by_type(
- abi_type: Literal["event"],
- contract_abi: ABI,
- ) -> Sequence[ABIEvent]:
- pass
- @overload
- def filter_abi_by_type(
- abi_type: Literal["error"],
- contract_abi: ABI,
- ) -> Sequence[ABIError]:
- pass
- def filter_abi_by_type(
- abi_type: Literal[
- "function", "constructor", "fallback", "receive", "event", "error"
- ],
- contract_abi: ABI,
- ) -> Sequence[
- Union[ABIFunction, ABIConstructor, ABIFallback, ABIReceive, ABIEvent, ABIError]
- ]:
- """
- Return a list of each ``ABIElement`` that is of type ``abi_type``.
- For mypy, function overloads ensures the correct type is returned based on the
- ``abi_type``. For example, if ``abi_type`` is "function", the return type will be
- ``Sequence[ABIFunction]``.
- :param abi_type: Type of ABI element to filter by.
- :type abi_type: `str`
- :param contract_abi: Contract ABI.
- :type contract_abi: `ABI`
- :return: List of ABI elements of the specified type.
- :rtype: `Sequence[Union[ABIFunction, ABIConstructor, ABIFallback, ABIReceive, \
- ABIEvent, ABIError]]`
- .. doctest::
- >>> from eth_utils import filter_abi_by_type
- >>> abi = [
- ... {"type": "function", "name": "myFunction", "inputs": [], "outputs": []},
- ... {"type": "function", "name": "myFunction2", "inputs": [], "outputs": []},
- ... {"type": "event", "name": "MyEvent", "inputs": []}
- ... ]
- >>> filter_abi_by_type("function", abi)
- [{'type': 'function', 'name': 'myFunction', 'inputs': [], 'outputs': []}, \
- {'type': 'function', 'name': 'myFunction2', 'inputs': [], 'outputs': []}]
- """
- if abi_type == Literal["function"] or abi_type == "function":
- return [abi for abi in contract_abi if abi["type"] == "function"]
- elif abi_type == Literal["constructor"] or abi_type == "constructor":
- return [abi for abi in contract_abi if abi["type"] == "constructor"]
- elif abi_type == Literal["fallback"] or abi_type == "fallback":
- return [abi for abi in contract_abi if abi["type"] == "fallback"]
- elif abi_type == Literal["receive"] or abi_type == "receive":
- return [abi for abi in contract_abi if abi["type"] == "receive"]
- elif abi_type == Literal["event"] or abi_type == "event":
- return [abi for abi in contract_abi if abi["type"] == "event"]
- elif abi_type == Literal["error"] or abi_type == "error":
- return [abi for abi in contract_abi if abi["type"] == "error"]
- else:
- raise ValueError(f"Unsupported ABI type: {abi_type}")
- def get_all_function_abis(contract_abi: ABI) -> Sequence[ABIFunction]:
- """
- Return interfaces for each function in the contract ABI.
- :param contract_abi: Contract ABI.
- :type contract_abi: `ABI`
- :return: List of ABIs for each function interface.
- :rtype: `Sequence[ABIFunction]`
- .. doctest::
- >>> from eth_utils import get_all_function_abis
- >>> contract_abi = [
- ... {"type": "function", "name": "myFunction", "inputs": [], "outputs": []},
- ... {"type": "function", "name": "myFunction2", "inputs": [], "outputs": []},
- ... {"type": "event", "name": "MyEvent", "inputs": []}
- ... ]
- >>> get_all_function_abis(contract_abi)
- [{'type': 'function', 'name': 'myFunction', 'inputs': [], 'outputs': []}, \
- {'type': 'function', 'name': 'myFunction2', 'inputs': [], 'outputs': []}]
- """
- return filter_abi_by_type("function", contract_abi)
- def get_all_event_abis(contract_abi: ABI) -> Sequence[ABIEvent]:
- """
- Return interfaces for each event in the contract ABI.
- :param contract_abi: Contract ABI.
- :type contract_abi: `ABI`
- :return: List of ABIs for each event interface.
- :rtype: `Sequence[ABIEvent]`
- .. doctest::
- >>> from eth_utils import get_all_event_abis
- >>> contract_abi = [
- ... {"type": "function", "name": "myFunction", "inputs": [], "outputs": []},
- ... {"type": "function", "name": "myFunction2", "inputs": [], "outputs": []},
- ... {"type": "event", "name": "MyEvent", "inputs": []}
- ... ]
- >>> get_all_event_abis(contract_abi)
- [{'type': 'event', 'name': 'MyEvent', 'inputs': []}]
- """
- return filter_abi_by_type("event", contract_abi)
- def get_normalized_abi_inputs(
- abi_element: ABIElement,
- *args: Optional[Sequence[Any]],
- **kwargs: Optional[Dict[str, Any]],
- ) -> Tuple[Any, ...]:
- r"""
- Flattens positional args (``args``) and keyword args (``kwargs``) into a Tuple and
- uses the ``abi_element`` for validation.
- Checks to ensure that the correct number of args were given, no duplicate args were
- given, and no unknown args were given. Returns a list of argument values aligned
- to the order of inputs defined in ``abi_element``.
- :param abi_element: ABI element.
- :type abi_element: `ABIElement`
- :param args: Positional arguments for the function.
- :type args: `Optional[Sequence[Any]]`
- :param kwargs: Keyword arguments for the function.
- :type kwargs: `Optional[Dict[str, Any]]`
- :return: Arguments list.
- :rtype: `Tuple[Any, ...]`
- .. doctest::
- >>> from eth_utils import get_normalized_abi_inputs
- >>> abi = {
- ... 'constant': False,
- ... 'inputs': [
- ... {
- ... 'name': 'name',
- ... 'type': 'string'
- ... },
- ... {
- ... 'name': 's',
- ... 'type': 'uint256'
- ... },
- ... {
- ... 'name': 't',
- ... 'components': [
- ... {'name': 'anAddress', 'type': 'address'},
- ... {'name': 'anInt', 'type': 'uint256'},
- ... {'name': 'someBytes', 'type': 'bytes'},
- ... ],
- ... 'type': 'tuple'
- ... }
- ... ],
- ... 'name': 'f',
- ... 'outputs': [],
- ... 'payable': False,
- ... 'stateMutability': 'nonpayable',
- ... 'type': 'function'
- ... }
- >>> get_normalized_abi_inputs(
- ... abi, *('myName', 123), **{'t': ('0x1', 1, b'\x01')}
- ... )
- ('myName', 123, ('0x1', 1, b'\x01'))
- """
- _raise_if_fallback_or_receive_abi(abi_element)
- function_inputs = cast(Sequence[ABIComponent], abi_element.get("inputs", []))
- if len(args) + len(kwargs) != len(function_inputs):
- raise TypeError(
- f"Incorrect argument count. Expected '{len(function_inputs)}'"
- f", got '{len(args) + len(kwargs)}'."
- )
- # If no keyword args were given, we don't need to align them
- if not kwargs:
- return cast(Tuple[Any, ...], args)
- kwarg_names = set(kwargs.keys())
- sorted_arg_names = tuple(arg_abi["name"] for arg_abi in function_inputs)
- args_as_kwargs = dict(zip(sorted_arg_names, args))
- # Check for duplicate args
- duplicate_args = kwarg_names.intersection(args_as_kwargs.keys())
- if duplicate_args:
- raise TypeError(
- f"{abi_element.get('name')}() got multiple values for argument(s) "
- f"'{', '.join(duplicate_args)}'."
- )
- # Check for unknown args
- # Arg names sorted to raise consistent error messages
- unknown_args = tuple(sorted(kwarg_names.difference(sorted_arg_names)))
- if unknown_args:
- message = "{} got unexpected keyword argument(s) '{}'."
- if abi_element.get("name"):
- raise TypeError(
- message.format(f"{abi_element.get('name')}()", ", ".join(unknown_args))
- )
- raise TypeError(
- message.format(
- f"Type: '{abi_element.get('type')}'", ", ".join(unknown_args)
- )
- )
- # Sort args according to their position in the ABI and unzip them from their
- # names
- sorted_args = tuple(
- zip(
- *sorted(
- itertools.chain(kwargs.items(), args_as_kwargs.items()),
- key=lambda kv: sorted_arg_names.index(kv[0]),
- )
- )
- )
- if len(sorted_args) > 0:
- return tuple(sorted_args[1])
- else:
- return tuple()
- def get_aligned_abi_inputs(
- abi_element: ABIElement,
- normalized_args: Union[Tuple[Any, ...], Mapping[Any, Any]],
- ) -> Tuple[Tuple[str, ...], Tuple[Any, ...]]:
- """
- Returns a pair of nested Tuples containing a list of types and a list of input
- values sorted by the order specified by the ``abi``.
- ``normalized_args`` can be obtained by using
- :py:meth:`eth_utils.abi.get_normalized_abi_inputs`, which returns nested mappings
- or sequences corresponding to tuple-encoded values in ``abi``.
- :param abi_element: ABI element.
- :type abi_element: `ABIElement`
- :param normalized_args: Normalized arguments for the function.
- :type normalized_args: `Union[Tuple[Any, ...], Mapping[Any, Any]]`
- :return: Tuple of types and aligned arguments.
- :rtype: `Tuple[Tuple[str, ...], Tuple[Any, ...]]`
- .. doctest::
- >>> from eth_utils import get_aligned_abi_inputs
- >>> abi = {
- ... 'constant': False,
- ... 'inputs': [
- ... {
- ... 'name': 'name',
- ... 'type': 'string'
- ... },
- ... {
- ... 'name': 's',
- ... 'type': 'uint256'
- ... }
- ... ],
- ... 'name': 'f',
- ... 'outputs': [],
- ... 'payable': False,
- ... 'stateMutability': 'nonpayable',
- ... 'type': 'function'
- ... }
- >>> get_aligned_abi_inputs(abi, ('myName', 123))
- (('string', 'uint256'), ('myName', 123))
- """
- _raise_if_fallback_or_receive_abi(abi_element)
- abi_element_inputs = cast(Sequence[ABIComponent], abi_element.get("inputs", []))
- if isinstance(normalized_args, abc.Mapping):
- # `args` is mapping. Align values according to abi order.
- normalized_args = tuple(
- normalized_args[abi["name"]] for abi in abi_element_inputs
- )
- return (
- tuple(collapse_if_tuple(abi) for abi in abi_element_inputs),
- type(normalized_args)(
- _align_abi_input(abi, arg)
- for abi, arg in zip(abi_element_inputs, normalized_args)
- ),
- )
- def get_abi_input_names(abi_element: ABIElement) -> List[Optional[str]]:
- """
- Return names for each input from the function or event ABI.
- :param abi_element: ABI element.
- :type abi_element: `ABIElement`
- :return: Names for each input in the function or event ABI.
- :rtype: `List[Optional[str]]`
- .. doctest::
- >>> from eth_utils import get_abi_input_names
- >>> abi = {
- ... 'constant': False,
- ... 'inputs': [
- ... {
- ... 'name': 's',
- ... 'type': 'uint256'
- ... }
- ... ],
- ... 'name': 'f',
- ... 'outputs': [],
- ... 'payable': False,
- ... 'stateMutability': 'nonpayable',
- ... 'type': 'function'
- ... }
- >>> get_abi_input_names(abi)
- ['s']
- """
- _raise_if_fallback_or_receive_abi(abi_element)
- return [
- arg.get("name", None)
- for arg in cast(Sequence[ABIComponent], abi_element.get("inputs", []))
- ]
- def get_abi_input_types(abi_element: ABIElement) -> List[str]:
- """
- Return types for each input from the function or event ABI.
- :param abi_element: ABI element.
- :type abi_element: `ABIElement`
- :return: Types for each input in the function or event ABI.
- :rtype: `List[str]`
- .. doctest::
- >>> from eth_utils import get_abi_input_types
- >>> abi = {
- ... 'constant': False,
- ... 'inputs': [
- ... {
- ... 'name': 's',
- ... 'type': 'uint256'
- ... }
- ... ],
- ... 'name': 'f',
- ... 'outputs': [],
- ... 'payable': False,
- ... 'stateMutability': 'nonpayable',
- ... 'type': 'function'
- ... }
- >>> get_abi_input_types(abi)
- ['uint256']
- """
- _raise_if_fallback_or_receive_abi(abi_element)
- return [
- collapse_if_tuple(arg)
- for arg in cast(Sequence[ABIComponent], abi_element.get("inputs", []))
- ]
- def get_abi_output_names(abi_element: ABIElement) -> List[Optional[str]]:
- """
- Return names for each output from the ABI element.
- :param abi_element: ABI element.
- :type abi_element: `ABIElement`
- :return: Names for each function output in the function ABI.
- :rtype: `List[Optional[str]]`
- .. doctest::
- >>> from eth_utils import get_abi_output_names
- >>> abi = {
- ... 'constant': False,
- ... 'inputs': [
- ... {
- ... 'name': 's',
- ... 'type': 'uint256'
- ... }
- ... ],
- ... 'name': 'f',
- ... 'outputs': [
- ... {
- ... 'name': 'name',
- ... 'type': 'string'
- ... },
- ... {
- ... 'name': 's',
- ... 'type': 'uint256'
- ... }
- ... ],
- ... 'payable': False,
- ... 'stateMutability': 'nonpayable',
- ... 'type': 'function'
- ... }
- >>> get_abi_output_names(abi)
- ['name', 's']
- """
- _raise_if_not_function_abi(abi_element)
- return [
- arg.get("name", None)
- for arg in cast(Sequence[ABIComponent], abi_element.get("outputs", []))
- ]
- def get_abi_output_types(abi_element: ABIElement) -> List[str]:
- """
- Return types for each output from the function ABI.
- :param abi_element: ABI element.
- :type abi_element: `ABIElement`
- :return: Types for each function output in the function ABI.
- :rtype: `List[str]`
- .. doctest::
- >>> from eth_utils import get_abi_output_types
- >>> abi = {
- ... 'constant': False,
- ... 'inputs': [
- ... {
- ... 'name': 's',
- ... 'type': 'uint256'
- ... }
- ... ],
- ... 'name': 'f',
- ... 'outputs': [
- ... {
- ... 'name': 'name',
- ... 'type': 'string'
- ... },
- ... {
- ... 'name': 's',
- ... 'type': 'uint256'
- ... }
- ... ],
- ... 'payable': False,
- ... 'stateMutability': 'nonpayable',
- ... 'type': 'function'
- ... }
- >>> get_abi_output_types(abi)
- ['string', 'uint256']
- """
- _raise_if_not_function_abi(abi_element)
- return [
- collapse_if_tuple(arg)
- for arg in cast(Sequence[ABIComponent], abi_element.get("outputs", []))
- ]
- def function_signature_to_4byte_selector(function_signature: str) -> bytes:
- r"""
- Return the 4-byte function selector from a function signature string.
- :param function_signature: String representation of the function name and arguments.
- :type function_signature: `str`
- :return: 4-byte function selector.
- :rtype: `bytes`
- .. doctest::
- >>> from eth_utils import function_signature_to_4byte_selector
- >>> function_signature_to_4byte_selector('myFunction()')
- b'\xc3x\n:'
- """
- return keccak(text=function_signature.replace(" ", ""))[:4]
- def function_abi_to_4byte_selector(abi_element: ABIElement) -> bytes:
- r"""
- Return the 4-byte function signature of the provided function ABI.
- :param abi_element: ABI element.
- :type abi_element: `ABIElement`
- :return: 4-byte function signature.
- :rtype: `bytes`
- .. doctest::
- >>> from eth_utils import function_abi_to_4byte_selector
- >>> abi_element = {
- ... 'type': 'function',
- ... 'name': 'myFunction',
- ... 'inputs': [],
- ... 'outputs': []
- ... }
- >>> function_abi_to_4byte_selector(abi_element)
- b'\xc3x\n:'
- """
- function_signature = abi_to_signature(abi_element)
- return function_signature_to_4byte_selector(function_signature)
- def event_signature_to_log_topic(event_signature: str) -> bytes:
- r"""
- Return the 32-byte keccak signature of the log topic for an event signature.
- :param event_signature: String representation of the event name and arguments.
- :type event_signature: `str`
- :return: Log topic bytes.
- :rtype: `bytes`
- .. doctest::
- >>> from eth_utils import event_signature_to_log_topic
- >>> event_signature_to_log_topic('MyEvent()')
- b'M\xbf\xb6\x8bC\xdd\xdf\xa1+Q\xeb\xe9\x9a\xb8\xfd\xedb\x0f\x9a\n\xc21B\x87\x9aO\x19*\x1byR\xd2'
- """
- return keccak(text=event_signature.replace(" ", ""))
- def event_abi_to_log_topic(event_abi: ABIEvent) -> bytes:
- r"""
- Return the 32-byte keccak signature of the log topic from an event ABI.
- :param event_abi: Event ABI.
- :type event_abi: `ABIEvent`
- :return: Log topic bytes.
- :rtype: `bytes`
- .. doctest::
- >>> from eth_utils import event_abi_to_log_topic
- >>> abi = {
- ... 'type': 'event',
- ... 'anonymous': False,
- ... 'name': 'MyEvent',
- ... 'inputs': []
- ... }
- >>> event_abi_to_log_topic(abi)
- b'M\xbf\xb6\x8bC\xdd\xdf\xa1+Q\xeb\xe9\x9a\xb8\xfd\xedb\x0f\x9a\n\xc21B\x87\x9aO\x19*\x1byR\xd2'
- """
- event_signature = abi_to_signature(event_abi)
- return event_signature_to_log_topic(event_signature)
|