abi.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. from collections import (
  2. abc,
  3. )
  4. import copy
  5. import itertools
  6. import re
  7. from typing import (
  8. Any,
  9. Dict,
  10. Iterable,
  11. List,
  12. Literal,
  13. Mapping,
  14. Optional,
  15. Sequence,
  16. Tuple,
  17. Union,
  18. cast,
  19. overload,
  20. )
  21. from eth_typing import (
  22. ABI,
  23. ABIComponent,
  24. ABIConstructor,
  25. ABIElement,
  26. ABIError,
  27. ABIEvent,
  28. ABIFallback,
  29. ABIFunction,
  30. ABIReceive,
  31. )
  32. from eth_utils.types import (
  33. is_list_like,
  34. )
  35. from .crypto import (
  36. keccak,
  37. )
  38. def _align_abi_input(
  39. arg_abi: ABIComponent, normalized_arg: Any
  40. ) -> Union[Any, Tuple[Any, ...]]:
  41. """
  42. Aligns the values of any mapping at any level of nesting in ``normalized_arg``
  43. according to the layout of the corresponding abi spec.
  44. """
  45. tuple_parts = _get_tuple_type_str_and_dims(arg_abi.get("type", ""))
  46. if tuple_parts is None:
  47. # normalized_arg is non-tuple. Just return value.
  48. return normalized_arg
  49. tuple_prefix, tuple_dims = tuple_parts
  50. if tuple_dims is None:
  51. # normalized_arg is non-list tuple. Each sub arg in `normalized_arg` will be
  52. # aligned according to its corresponding abi.
  53. sub_abis = cast(Iterable[ABIComponent], arg_abi.get("components", []))
  54. else:
  55. num_dims = tuple_dims.count("[")
  56. # normalized_arg is list tuple. A non-list version of its abi will be used to
  57. # align each element in `normalized_arg`.
  58. new_abi = copy.copy(arg_abi)
  59. new_abi["type"] = tuple_prefix + "[]" * (num_dims - 1)
  60. sub_abis = itertools.repeat(new_abi)
  61. if isinstance(normalized_arg, abc.Mapping):
  62. # normalized_arg is mapping. Align values according to abi order.
  63. aligned_arg = tuple(normalized_arg[abi["name"]] for abi in sub_abis)
  64. else:
  65. aligned_arg = normalized_arg
  66. if not is_list_like(aligned_arg):
  67. raise TypeError(
  68. f'Expected non-string sequence for "{arg_abi.get("type")}" '
  69. f"component type: got {aligned_arg}"
  70. )
  71. # convert NamedTuple to regular tuple
  72. typing = tuple if isinstance(aligned_arg, tuple) else type(aligned_arg)
  73. return typing(
  74. _align_abi_input(sub_abi, sub_arg)
  75. for sub_abi, sub_arg in zip(sub_abis, aligned_arg)
  76. )
  77. def _get_tuple_type_str_and_dims(s: str) -> Optional[Tuple[str, Optional[str]]]:
  78. """
  79. Takes a JSON ABI type string. For tuple type strings, returns the separated
  80. prefix and array dimension parts. For all other strings, returns ``None``.
  81. """
  82. tuple_type_str_re = "^(tuple)((\\[([1-9]\\d*\b)?])*)??$"
  83. match = re.compile(tuple_type_str_re).match(s)
  84. if match is not None:
  85. tuple_prefix = match.group(1)
  86. tuple_dims = match.group(2)
  87. return tuple_prefix, tuple_dims
  88. return None
  89. def _raise_if_not_function_abi(abi_element: ABIElement) -> None:
  90. if abi_element["type"] != "function":
  91. raise ValueError(
  92. f"Outputs only supported for ABI type `function`. Provided"
  93. f" ABI type was `{abi_element.get('type')}` and outputs were "
  94. f"`{abi_element.get('outputs')}`."
  95. )
  96. def _raise_if_fallback_or_receive_abi(abi_element: ABIElement) -> None:
  97. if abi_element["type"] == "fallback" or abi_element["type"] == "receive":
  98. raise ValueError(
  99. f"Inputs not supported for function types `fallback` or `receive`. Provided"
  100. f" ABI type was `{abi_element.get('type')}` with inputs "
  101. f"`{abi_element.get('inputs')}`."
  102. )
  103. def collapse_if_tuple(abi: Union[ABIComponent, Dict[str, Any], str]) -> str:
  104. """
  105. Extract argument types from a function or event ABI parameter.
  106. With tuple argument types, return a Tuple of each type.
  107. Returns the param if `abi` is an instance of str or another non-tuple
  108. type.
  109. :param abi: A Function or Event ABI component or a string with type info.
  110. :type abi: `Union[ABIComponent, Dict[str, Any], str]`
  111. :return: Type(s) for the function or event ABI param.
  112. :rtype: `str`
  113. .. doctest::
  114. >>> from eth_utils.abi import collapse_if_tuple
  115. >>> abi = {
  116. ... 'components': [
  117. ... {'name': 'anAddress', 'type': 'address'},
  118. ... {'name': 'anInt', 'type': 'uint256'},
  119. ... {'name': 'someBytes', 'type': 'bytes'},
  120. ... ],
  121. ... 'type': 'tuple',
  122. ... }
  123. >>> collapse_if_tuple(abi)
  124. '(address,uint256,bytes)'
  125. """
  126. if isinstance(abi, str):
  127. return abi
  128. element_type = abi.get("type")
  129. if not isinstance(element_type, str):
  130. raise TypeError(
  131. f"The 'type' must be a string, but got {repr(element_type)} of type "
  132. f"{type(element_type)}"
  133. )
  134. elif not element_type.startswith("tuple"):
  135. return element_type
  136. delimited = ",".join(collapse_if_tuple(c) for c in abi["components"])
  137. # Whatever comes after "tuple" is the array dims. The ABI spec states that
  138. # this will have the form "", "[]", or "[k]".
  139. array_dim = element_type[5:]
  140. collapsed = f"({delimited}){array_dim}"
  141. return collapsed
  142. def abi_to_signature(abi_element: ABIElement) -> str:
  143. """
  144. Returns a string signature representation of the function or event ABI
  145. and arguments.
  146. Signatures consist of the name followed by a list of arguments.
  147. :param abi_element: ABI element.
  148. :type abi_element: `ABIElement`
  149. :return: Stringified ABI signature
  150. :rtype: `str`
  151. .. doctest::
  152. >>> from eth_utils import abi_to_signature
  153. >>> abi_element = {
  154. ... 'constant': False,
  155. ... 'inputs': [
  156. ... {
  157. ... 'name': 's',
  158. ... 'type': 'uint256'
  159. ... }
  160. ... ],
  161. ... 'name': 'f',
  162. ... 'outputs': [],
  163. ... 'payable': False,
  164. ... 'stateMutability': 'nonpayable',
  165. ... 'type': 'function'
  166. ... }
  167. >>> abi_to_signature(abi_element)
  168. 'f(uint256)'
  169. """
  170. signature = "{name}({input_types})"
  171. abi_type = str(abi_element.get("type", ""))
  172. if abi_type == "fallback" or abi_type == "receive":
  173. return signature.format(name=abi_type, input_types="")
  174. if abi_type == "constructor":
  175. fn_name = abi_type
  176. else:
  177. fn_name = str(abi_element.get("name", abi_type))
  178. return signature.format(
  179. name=fn_name, input_types=",".join(get_abi_input_types(abi_element))
  180. )
  181. def filter_abi_by_name(abi_name: str, contract_abi: ABI) -> Sequence[ABIElement]:
  182. """
  183. Get one or more function and event ABIs by name.
  184. :param abi_name: Name of the function, event or error.
  185. :type abi_name: `str`
  186. :param contract_abi: Contract ABI.
  187. :type contract_abi: `ABI`
  188. :return: Function or event ABIs with matching name.
  189. :rtype: `Sequence[ABIElement]`
  190. .. doctest::
  191. >>> from eth_utils.abi import filter_abi_by_name
  192. >>> abi = [
  193. ... {
  194. ... "constant": False,
  195. ... "inputs": [],
  196. ... "name": "func_1",
  197. ... "outputs": [],
  198. ... "type": "function",
  199. ... },
  200. ... {
  201. ... "constant": False,
  202. ... "inputs": [
  203. ... {"name": "a", "type": "uint256"},
  204. ... ],
  205. ... "name": "func_2",
  206. ... "outputs": [],
  207. ... "type": "function",
  208. ... },
  209. ... {
  210. ... "constant": False,
  211. ... "inputs": [
  212. ... {"name": "a", "type": "uint256"},
  213. ... {"name": "b", "type": "uint256"},
  214. ... ],
  215. ... "name": "func_3",
  216. ... "outputs": [],
  217. ... "type": "function",
  218. ... },
  219. ... {
  220. ... "constant": False,
  221. ... "inputs": [
  222. ... {"name": "a", "type": "uint256"},
  223. ... {"name": "b", "type": "uint256"},
  224. ... {"name": "c", "type": "uint256"},
  225. ... ],
  226. ... "name": "func_4",
  227. ... "outputs": [],
  228. ... "type": "function",
  229. ... },
  230. ... ]
  231. >>> filter_abi_by_name("func_1", abi)
  232. [{'constant': False, 'inputs': [], 'name': 'func_1', 'outputs': [], \
  233. 'type': 'function'}]
  234. """
  235. return [
  236. abi
  237. for abi in contract_abi
  238. if (
  239. (
  240. abi["type"] == "function"
  241. or abi["type"] == "event"
  242. or abi["type"] == "error"
  243. )
  244. and abi["name"] == abi_name
  245. )
  246. ]
  247. @overload
  248. def filter_abi_by_type(
  249. abi_type: Literal["function"],
  250. contract_abi: ABI,
  251. ) -> Sequence[ABIFunction]:
  252. pass
  253. @overload
  254. def filter_abi_by_type(
  255. abi_type: Literal["constructor"],
  256. contract_abi: ABI,
  257. ) -> Sequence[ABIConstructor]:
  258. pass
  259. @overload
  260. def filter_abi_by_type(
  261. abi_type: Literal["fallback"],
  262. contract_abi: ABI,
  263. ) -> Sequence[ABIFallback]:
  264. pass
  265. @overload
  266. def filter_abi_by_type(
  267. abi_type: Literal["receive"],
  268. contract_abi: ABI,
  269. ) -> Sequence[ABIReceive]:
  270. pass
  271. @overload
  272. def filter_abi_by_type(
  273. abi_type: Literal["event"],
  274. contract_abi: ABI,
  275. ) -> Sequence[ABIEvent]:
  276. pass
  277. @overload
  278. def filter_abi_by_type(
  279. abi_type: Literal["error"],
  280. contract_abi: ABI,
  281. ) -> Sequence[ABIError]:
  282. pass
  283. def filter_abi_by_type(
  284. abi_type: Literal[
  285. "function", "constructor", "fallback", "receive", "event", "error"
  286. ],
  287. contract_abi: ABI,
  288. ) -> Sequence[
  289. Union[ABIFunction, ABIConstructor, ABIFallback, ABIReceive, ABIEvent, ABIError]
  290. ]:
  291. """
  292. Return a list of each ``ABIElement`` that is of type ``abi_type``.
  293. For mypy, function overloads ensures the correct type is returned based on the
  294. ``abi_type``. For example, if ``abi_type`` is "function", the return type will be
  295. ``Sequence[ABIFunction]``.
  296. :param abi_type: Type of ABI element to filter by.
  297. :type abi_type: `str`
  298. :param contract_abi: Contract ABI.
  299. :type contract_abi: `ABI`
  300. :return: List of ABI elements of the specified type.
  301. :rtype: `Sequence[Union[ABIFunction, ABIConstructor, ABIFallback, ABIReceive, \
  302. ABIEvent, ABIError]]`
  303. .. doctest::
  304. >>> from eth_utils import filter_abi_by_type
  305. >>> abi = [
  306. ... {"type": "function", "name": "myFunction", "inputs": [], "outputs": []},
  307. ... {"type": "function", "name": "myFunction2", "inputs": [], "outputs": []},
  308. ... {"type": "event", "name": "MyEvent", "inputs": []}
  309. ... ]
  310. >>> filter_abi_by_type("function", abi)
  311. [{'type': 'function', 'name': 'myFunction', 'inputs': [], 'outputs': []}, \
  312. {'type': 'function', 'name': 'myFunction2', 'inputs': [], 'outputs': []}]
  313. """
  314. if abi_type == Literal["function"] or abi_type == "function":
  315. return [abi for abi in contract_abi if abi["type"] == "function"]
  316. elif abi_type == Literal["constructor"] or abi_type == "constructor":
  317. return [abi for abi in contract_abi if abi["type"] == "constructor"]
  318. elif abi_type == Literal["fallback"] or abi_type == "fallback":
  319. return [abi for abi in contract_abi if abi["type"] == "fallback"]
  320. elif abi_type == Literal["receive"] or abi_type == "receive":
  321. return [abi for abi in contract_abi if abi["type"] == "receive"]
  322. elif abi_type == Literal["event"] or abi_type == "event":
  323. return [abi for abi in contract_abi if abi["type"] == "event"]
  324. elif abi_type == Literal["error"] or abi_type == "error":
  325. return [abi for abi in contract_abi if abi["type"] == "error"]
  326. else:
  327. raise ValueError(f"Unsupported ABI type: {abi_type}")
  328. def get_all_function_abis(contract_abi: ABI) -> Sequence[ABIFunction]:
  329. """
  330. Return interfaces for each function in the contract ABI.
  331. :param contract_abi: Contract ABI.
  332. :type contract_abi: `ABI`
  333. :return: List of ABIs for each function interface.
  334. :rtype: `Sequence[ABIFunction]`
  335. .. doctest::
  336. >>> from eth_utils import get_all_function_abis
  337. >>> contract_abi = [
  338. ... {"type": "function", "name": "myFunction", "inputs": [], "outputs": []},
  339. ... {"type": "function", "name": "myFunction2", "inputs": [], "outputs": []},
  340. ... {"type": "event", "name": "MyEvent", "inputs": []}
  341. ... ]
  342. >>> get_all_function_abis(contract_abi)
  343. [{'type': 'function', 'name': 'myFunction', 'inputs': [], 'outputs': []}, \
  344. {'type': 'function', 'name': 'myFunction2', 'inputs': [], 'outputs': []}]
  345. """
  346. return filter_abi_by_type("function", contract_abi)
  347. def get_all_event_abis(contract_abi: ABI) -> Sequence[ABIEvent]:
  348. """
  349. Return interfaces for each event in the contract ABI.
  350. :param contract_abi: Contract ABI.
  351. :type contract_abi: `ABI`
  352. :return: List of ABIs for each event interface.
  353. :rtype: `Sequence[ABIEvent]`
  354. .. doctest::
  355. >>> from eth_utils import get_all_event_abis
  356. >>> contract_abi = [
  357. ... {"type": "function", "name": "myFunction", "inputs": [], "outputs": []},
  358. ... {"type": "function", "name": "myFunction2", "inputs": [], "outputs": []},
  359. ... {"type": "event", "name": "MyEvent", "inputs": []}
  360. ... ]
  361. >>> get_all_event_abis(contract_abi)
  362. [{'type': 'event', 'name': 'MyEvent', 'inputs': []}]
  363. """
  364. return filter_abi_by_type("event", contract_abi)
  365. def get_normalized_abi_inputs(
  366. abi_element: ABIElement,
  367. *args: Optional[Sequence[Any]],
  368. **kwargs: Optional[Dict[str, Any]],
  369. ) -> Tuple[Any, ...]:
  370. r"""
  371. Flattens positional args (``args``) and keyword args (``kwargs``) into a Tuple and
  372. uses the ``abi_element`` for validation.
  373. Checks to ensure that the correct number of args were given, no duplicate args were
  374. given, and no unknown args were given. Returns a list of argument values aligned
  375. to the order of inputs defined in ``abi_element``.
  376. :param abi_element: ABI element.
  377. :type abi_element: `ABIElement`
  378. :param args: Positional arguments for the function.
  379. :type args: `Optional[Sequence[Any]]`
  380. :param kwargs: Keyword arguments for the function.
  381. :type kwargs: `Optional[Dict[str, Any]]`
  382. :return: Arguments list.
  383. :rtype: `Tuple[Any, ...]`
  384. .. doctest::
  385. >>> from eth_utils import get_normalized_abi_inputs
  386. >>> abi = {
  387. ... 'constant': False,
  388. ... 'inputs': [
  389. ... {
  390. ... 'name': 'name',
  391. ... 'type': 'string'
  392. ... },
  393. ... {
  394. ... 'name': 's',
  395. ... 'type': 'uint256'
  396. ... },
  397. ... {
  398. ... 'name': 't',
  399. ... 'components': [
  400. ... {'name': 'anAddress', 'type': 'address'},
  401. ... {'name': 'anInt', 'type': 'uint256'},
  402. ... {'name': 'someBytes', 'type': 'bytes'},
  403. ... ],
  404. ... 'type': 'tuple'
  405. ... }
  406. ... ],
  407. ... 'name': 'f',
  408. ... 'outputs': [],
  409. ... 'payable': False,
  410. ... 'stateMutability': 'nonpayable',
  411. ... 'type': 'function'
  412. ... }
  413. >>> get_normalized_abi_inputs(
  414. ... abi, *('myName', 123), **{'t': ('0x1', 1, b'\x01')}
  415. ... )
  416. ('myName', 123, ('0x1', 1, b'\x01'))
  417. """
  418. _raise_if_fallback_or_receive_abi(abi_element)
  419. function_inputs = cast(Sequence[ABIComponent], abi_element.get("inputs", []))
  420. if len(args) + len(kwargs) != len(function_inputs):
  421. raise TypeError(
  422. f"Incorrect argument count. Expected '{len(function_inputs)}'"
  423. f", got '{len(args) + len(kwargs)}'."
  424. )
  425. # If no keyword args were given, we don't need to align them
  426. if not kwargs:
  427. return cast(Tuple[Any, ...], args)
  428. kwarg_names = set(kwargs.keys())
  429. sorted_arg_names = tuple(arg_abi["name"] for arg_abi in function_inputs)
  430. args_as_kwargs = dict(zip(sorted_arg_names, args))
  431. # Check for duplicate args
  432. duplicate_args = kwarg_names.intersection(args_as_kwargs.keys())
  433. if duplicate_args:
  434. raise TypeError(
  435. f"{abi_element.get('name')}() got multiple values for argument(s) "
  436. f"'{', '.join(duplicate_args)}'."
  437. )
  438. # Check for unknown args
  439. # Arg names sorted to raise consistent error messages
  440. unknown_args = tuple(sorted(kwarg_names.difference(sorted_arg_names)))
  441. if unknown_args:
  442. message = "{} got unexpected keyword argument(s) '{}'."
  443. if abi_element.get("name"):
  444. raise TypeError(
  445. message.format(f"{abi_element.get('name')}()", ", ".join(unknown_args))
  446. )
  447. raise TypeError(
  448. message.format(
  449. f"Type: '{abi_element.get('type')}'", ", ".join(unknown_args)
  450. )
  451. )
  452. # Sort args according to their position in the ABI and unzip them from their
  453. # names
  454. sorted_args = tuple(
  455. zip(
  456. *sorted(
  457. itertools.chain(kwargs.items(), args_as_kwargs.items()),
  458. key=lambda kv: sorted_arg_names.index(kv[0]),
  459. )
  460. )
  461. )
  462. if len(sorted_args) > 0:
  463. return tuple(sorted_args[1])
  464. else:
  465. return tuple()
  466. def get_aligned_abi_inputs(
  467. abi_element: ABIElement,
  468. normalized_args: Union[Tuple[Any, ...], Mapping[Any, Any]],
  469. ) -> Tuple[Tuple[str, ...], Tuple[Any, ...]]:
  470. """
  471. Returns a pair of nested Tuples containing a list of types and a list of input
  472. values sorted by the order specified by the ``abi``.
  473. ``normalized_args`` can be obtained by using
  474. :py:meth:`eth_utils.abi.get_normalized_abi_inputs`, which returns nested mappings
  475. or sequences corresponding to tuple-encoded values in ``abi``.
  476. :param abi_element: ABI element.
  477. :type abi_element: `ABIElement`
  478. :param normalized_args: Normalized arguments for the function.
  479. :type normalized_args: `Union[Tuple[Any, ...], Mapping[Any, Any]]`
  480. :return: Tuple of types and aligned arguments.
  481. :rtype: `Tuple[Tuple[str, ...], Tuple[Any, ...]]`
  482. .. doctest::
  483. >>> from eth_utils import get_aligned_abi_inputs
  484. >>> abi = {
  485. ... 'constant': False,
  486. ... 'inputs': [
  487. ... {
  488. ... 'name': 'name',
  489. ... 'type': 'string'
  490. ... },
  491. ... {
  492. ... 'name': 's',
  493. ... 'type': 'uint256'
  494. ... }
  495. ... ],
  496. ... 'name': 'f',
  497. ... 'outputs': [],
  498. ... 'payable': False,
  499. ... 'stateMutability': 'nonpayable',
  500. ... 'type': 'function'
  501. ... }
  502. >>> get_aligned_abi_inputs(abi, ('myName', 123))
  503. (('string', 'uint256'), ('myName', 123))
  504. """
  505. _raise_if_fallback_or_receive_abi(abi_element)
  506. abi_element_inputs = cast(Sequence[ABIComponent], abi_element.get("inputs", []))
  507. if isinstance(normalized_args, abc.Mapping):
  508. # `args` is mapping. Align values according to abi order.
  509. normalized_args = tuple(
  510. normalized_args[abi["name"]] for abi in abi_element_inputs
  511. )
  512. return (
  513. tuple(collapse_if_tuple(abi) for abi in abi_element_inputs),
  514. type(normalized_args)(
  515. _align_abi_input(abi, arg)
  516. for abi, arg in zip(abi_element_inputs, normalized_args)
  517. ),
  518. )
  519. def get_abi_input_names(abi_element: ABIElement) -> List[Optional[str]]:
  520. """
  521. Return names for each input from the function or event ABI.
  522. :param abi_element: ABI element.
  523. :type abi_element: `ABIElement`
  524. :return: Names for each input in the function or event ABI.
  525. :rtype: `List[Optional[str]]`
  526. .. doctest::
  527. >>> from eth_utils import get_abi_input_names
  528. >>> abi = {
  529. ... 'constant': False,
  530. ... 'inputs': [
  531. ... {
  532. ... 'name': 's',
  533. ... 'type': 'uint256'
  534. ... }
  535. ... ],
  536. ... 'name': 'f',
  537. ... 'outputs': [],
  538. ... 'payable': False,
  539. ... 'stateMutability': 'nonpayable',
  540. ... 'type': 'function'
  541. ... }
  542. >>> get_abi_input_names(abi)
  543. ['s']
  544. """
  545. _raise_if_fallback_or_receive_abi(abi_element)
  546. return [
  547. arg.get("name", None)
  548. for arg in cast(Sequence[ABIComponent], abi_element.get("inputs", []))
  549. ]
  550. def get_abi_input_types(abi_element: ABIElement) -> List[str]:
  551. """
  552. Return types for each input from the function or event ABI.
  553. :param abi_element: ABI element.
  554. :type abi_element: `ABIElement`
  555. :return: Types for each input in the function or event ABI.
  556. :rtype: `List[str]`
  557. .. doctest::
  558. >>> from eth_utils import get_abi_input_types
  559. >>> abi = {
  560. ... 'constant': False,
  561. ... 'inputs': [
  562. ... {
  563. ... 'name': 's',
  564. ... 'type': 'uint256'
  565. ... }
  566. ... ],
  567. ... 'name': 'f',
  568. ... 'outputs': [],
  569. ... 'payable': False,
  570. ... 'stateMutability': 'nonpayable',
  571. ... 'type': 'function'
  572. ... }
  573. >>> get_abi_input_types(abi)
  574. ['uint256']
  575. """
  576. _raise_if_fallback_or_receive_abi(abi_element)
  577. return [
  578. collapse_if_tuple(arg)
  579. for arg in cast(Sequence[ABIComponent], abi_element.get("inputs", []))
  580. ]
  581. def get_abi_output_names(abi_element: ABIElement) -> List[Optional[str]]:
  582. """
  583. Return names for each output from the ABI element.
  584. :param abi_element: ABI element.
  585. :type abi_element: `ABIElement`
  586. :return: Names for each function output in the function ABI.
  587. :rtype: `List[Optional[str]]`
  588. .. doctest::
  589. >>> from eth_utils import get_abi_output_names
  590. >>> abi = {
  591. ... 'constant': False,
  592. ... 'inputs': [
  593. ... {
  594. ... 'name': 's',
  595. ... 'type': 'uint256'
  596. ... }
  597. ... ],
  598. ... 'name': 'f',
  599. ... 'outputs': [
  600. ... {
  601. ... 'name': 'name',
  602. ... 'type': 'string'
  603. ... },
  604. ... {
  605. ... 'name': 's',
  606. ... 'type': 'uint256'
  607. ... }
  608. ... ],
  609. ... 'payable': False,
  610. ... 'stateMutability': 'nonpayable',
  611. ... 'type': 'function'
  612. ... }
  613. >>> get_abi_output_names(abi)
  614. ['name', 's']
  615. """
  616. _raise_if_not_function_abi(abi_element)
  617. return [
  618. arg.get("name", None)
  619. for arg in cast(Sequence[ABIComponent], abi_element.get("outputs", []))
  620. ]
  621. def get_abi_output_types(abi_element: ABIElement) -> List[str]:
  622. """
  623. Return types for each output from the function ABI.
  624. :param abi_element: ABI element.
  625. :type abi_element: `ABIElement`
  626. :return: Types for each function output in the function ABI.
  627. :rtype: `List[str]`
  628. .. doctest::
  629. >>> from eth_utils import get_abi_output_types
  630. >>> abi = {
  631. ... 'constant': False,
  632. ... 'inputs': [
  633. ... {
  634. ... 'name': 's',
  635. ... 'type': 'uint256'
  636. ... }
  637. ... ],
  638. ... 'name': 'f',
  639. ... 'outputs': [
  640. ... {
  641. ... 'name': 'name',
  642. ... 'type': 'string'
  643. ... },
  644. ... {
  645. ... 'name': 's',
  646. ... 'type': 'uint256'
  647. ... }
  648. ... ],
  649. ... 'payable': False,
  650. ... 'stateMutability': 'nonpayable',
  651. ... 'type': 'function'
  652. ... }
  653. >>> get_abi_output_types(abi)
  654. ['string', 'uint256']
  655. """
  656. _raise_if_not_function_abi(abi_element)
  657. return [
  658. collapse_if_tuple(arg)
  659. for arg in cast(Sequence[ABIComponent], abi_element.get("outputs", []))
  660. ]
  661. def function_signature_to_4byte_selector(function_signature: str) -> bytes:
  662. r"""
  663. Return the 4-byte function selector from a function signature string.
  664. :param function_signature: String representation of the function name and arguments.
  665. :type function_signature: `str`
  666. :return: 4-byte function selector.
  667. :rtype: `bytes`
  668. .. doctest::
  669. >>> from eth_utils import function_signature_to_4byte_selector
  670. >>> function_signature_to_4byte_selector('myFunction()')
  671. b'\xc3x\n:'
  672. """
  673. return keccak(text=function_signature.replace(" ", ""))[:4]
  674. def function_abi_to_4byte_selector(abi_element: ABIElement) -> bytes:
  675. r"""
  676. Return the 4-byte function signature of the provided function ABI.
  677. :param abi_element: ABI element.
  678. :type abi_element: `ABIElement`
  679. :return: 4-byte function signature.
  680. :rtype: `bytes`
  681. .. doctest::
  682. >>> from eth_utils import function_abi_to_4byte_selector
  683. >>> abi_element = {
  684. ... 'type': 'function',
  685. ... 'name': 'myFunction',
  686. ... 'inputs': [],
  687. ... 'outputs': []
  688. ... }
  689. >>> function_abi_to_4byte_selector(abi_element)
  690. b'\xc3x\n:'
  691. """
  692. function_signature = abi_to_signature(abi_element)
  693. return function_signature_to_4byte_selector(function_signature)
  694. def event_signature_to_log_topic(event_signature: str) -> bytes:
  695. r"""
  696. Return the 32-byte keccak signature of the log topic for an event signature.
  697. :param event_signature: String representation of the event name and arguments.
  698. :type event_signature: `str`
  699. :return: Log topic bytes.
  700. :rtype: `bytes`
  701. .. doctest::
  702. >>> from eth_utils import event_signature_to_log_topic
  703. >>> event_signature_to_log_topic('MyEvent()')
  704. b'M\xbf\xb6\x8bC\xdd\xdf\xa1+Q\xeb\xe9\x9a\xb8\xfd\xedb\x0f\x9a\n\xc21B\x87\x9aO\x19*\x1byR\xd2'
  705. """
  706. return keccak(text=event_signature.replace(" ", ""))
  707. def event_abi_to_log_topic(event_abi: ABIEvent) -> bytes:
  708. r"""
  709. Return the 32-byte keccak signature of the log topic from an event ABI.
  710. :param event_abi: Event ABI.
  711. :type event_abi: `ABIEvent`
  712. :return: Log topic bytes.
  713. :rtype: `bytes`
  714. .. doctest::
  715. >>> from eth_utils import event_abi_to_log_topic
  716. >>> abi = {
  717. ... 'type': 'event',
  718. ... 'anonymous': False,
  719. ... 'name': 'MyEvent',
  720. ... 'inputs': []
  721. ... }
  722. >>> event_abi_to_log_topic(abi)
  723. b'M\xbf\xb6\x8bC\xdd\xdf\xa1+Q\xeb\xe9\x9a\xb8\xfd\xedb\x0f\x9a\n\xc21B\x87\x9aO\x19*\x1byR\xd2'
  724. """
  725. event_signature = abi_to_signature(event_abi)
  726. return event_signature_to_log_topic(event_signature)