web3 7.0.0b2__py3-none-any.whl → 7.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. ens/__init__.py +13 -2
  2. ens/_normalization.py +4 -4
  3. ens/async_ens.py +27 -15
  4. ens/base_ens.py +3 -1
  5. ens/contract_data.py +2 -2
  6. ens/ens.py +10 -7
  7. ens/exceptions.py +16 -29
  8. ens/specs/nf.json +1 -1
  9. ens/specs/normalization_spec.json +1 -1
  10. ens/utils.py +24 -32
  11. web3/__init__.py +23 -12
  12. web3/_utils/abi.py +157 -263
  13. web3/_utils/async_transactions.py +34 -20
  14. web3/_utils/batching.py +217 -0
  15. web3/_utils/blocks.py +6 -2
  16. web3/_utils/caching/__init__.py +12 -0
  17. web3/_utils/caching/caching_utils.py +433 -0
  18. web3/_utils/caching/request_caching_validation.py +287 -0
  19. web3/_utils/compat/__init__.py +2 -3
  20. web3/_utils/contract_sources/compile_contracts.py +1 -1
  21. web3/_utils/contract_sources/contract_data/ambiguous_function_contract.py +42 -0
  22. web3/_utils/contract_sources/contract_data/arrays_contract.py +3 -3
  23. web3/_utils/contract_sources/contract_data/bytes_contracts.py +5 -5
  24. web3/_utils/contract_sources/contract_data/constructor_contracts.py +7 -7
  25. web3/_utils/contract_sources/contract_data/contract_caller_tester.py +3 -3
  26. web3/_utils/contract_sources/contract_data/emitter_contract.py +3 -3
  27. web3/_utils/contract_sources/contract_data/event_contracts.py +50 -5
  28. web3/_utils/contract_sources/contract_data/extended_resolver.py +3 -3
  29. web3/_utils/contract_sources/contract_data/fallback_function_contract.py +3 -3
  30. web3/_utils/contract_sources/contract_data/function_name_tester_contract.py +3 -3
  31. web3/_utils/contract_sources/contract_data/math_contract.py +3 -3
  32. web3/_utils/contract_sources/contract_data/offchain_lookup.py +3 -3
  33. web3/_utils/contract_sources/contract_data/offchain_resolver.py +3 -3
  34. web3/_utils/contract_sources/contract_data/panic_errors_contract.py +3 -3
  35. web3/_utils/contract_sources/contract_data/payable_tester.py +3 -3
  36. web3/_utils/contract_sources/contract_data/receive_function_contracts.py +5 -5
  37. web3/_utils/contract_sources/contract_data/reflector_contracts.py +3 -3
  38. web3/_utils/contract_sources/contract_data/revert_contract.py +3 -3
  39. web3/_utils/contract_sources/contract_data/simple_resolver.py +3 -3
  40. web3/_utils/contract_sources/contract_data/storage_contract.py +3 -3
  41. web3/_utils/contract_sources/contract_data/string_contract.py +3 -3
  42. web3/_utils/contract_sources/contract_data/tuple_contracts.py +5 -5
  43. web3/_utils/contracts.py +172 -220
  44. web3/_utils/datatypes.py +5 -1
  45. web3/_utils/decorators.py +6 -1
  46. web3/_utils/empty.py +1 -1
  47. web3/_utils/encoding.py +16 -12
  48. web3/_utils/error_formatters_utils.py +5 -3
  49. web3/_utils/events.py +78 -72
  50. web3/_utils/fee_utils.py +1 -3
  51. web3/_utils/filters.py +24 -22
  52. web3/_utils/formatters.py +2 -2
  53. web3/_utils/http.py +8 -2
  54. web3/_utils/http_session_manager.py +314 -0
  55. web3/_utils/math.py +14 -15
  56. web3/_utils/method_formatters.py +161 -34
  57. web3/_utils/module.py +2 -1
  58. web3/_utils/module_testing/__init__.py +3 -2
  59. web3/_utils/module_testing/eth_module.py +736 -583
  60. web3/_utils/module_testing/go_ethereum_debug_module.py +128 -0
  61. web3/_utils/module_testing/module_testing_utils.py +81 -24
  62. web3/_utils/module_testing/persistent_connection_provider.py +702 -220
  63. web3/_utils/module_testing/utils.py +114 -33
  64. web3/_utils/module_testing/web3_module.py +438 -17
  65. web3/_utils/normalizers.py +13 -11
  66. web3/_utils/rpc_abi.py +10 -22
  67. web3/_utils/threads.py +8 -7
  68. web3/_utils/transactions.py +32 -25
  69. web3/_utils/type_conversion.py +5 -1
  70. web3/_utils/validation.py +20 -17
  71. web3/beacon/__init__.py +5 -0
  72. web3/beacon/api_endpoints.py +3 -0
  73. web3/beacon/async_beacon.py +29 -6
  74. web3/beacon/beacon.py +24 -6
  75. web3/contract/__init__.py +7 -0
  76. web3/contract/async_contract.py +285 -82
  77. web3/contract/base_contract.py +556 -258
  78. web3/contract/contract.py +295 -84
  79. web3/contract/utils.py +251 -55
  80. web3/datastructures.py +49 -34
  81. web3/eth/__init__.py +7 -0
  82. web3/eth/async_eth.py +89 -69
  83. web3/eth/base_eth.py +7 -3
  84. web3/eth/eth.py +43 -66
  85. web3/exceptions.py +158 -83
  86. web3/gas_strategies/time_based.py +8 -6
  87. web3/geth.py +53 -184
  88. web3/main.py +77 -17
  89. web3/manager.py +362 -95
  90. web3/method.py +43 -15
  91. web3/middleware/__init__.py +17 -0
  92. web3/middleware/attrdict.py +12 -22
  93. web3/middleware/base.py +55 -2
  94. web3/middleware/filter.py +45 -23
  95. web3/middleware/formatting.py +6 -3
  96. web3/middleware/names.py +4 -1
  97. web3/middleware/signing.py +15 -6
  98. web3/middleware/stalecheck.py +2 -1
  99. web3/module.py +61 -25
  100. web3/providers/__init__.py +21 -0
  101. web3/providers/async_base.py +87 -32
  102. web3/providers/base.py +77 -32
  103. web3/providers/eth_tester/__init__.py +5 -0
  104. web3/providers/eth_tester/defaults.py +2 -55
  105. web3/providers/eth_tester/main.py +41 -15
  106. web3/providers/eth_tester/middleware.py +16 -17
  107. web3/providers/ipc.py +41 -17
  108. web3/providers/legacy_websocket.py +26 -1
  109. web3/providers/persistent/__init__.py +7 -0
  110. web3/providers/persistent/async_ipc.py +61 -121
  111. web3/providers/persistent/persistent.py +323 -16
  112. web3/providers/persistent/persistent_connection.py +54 -5
  113. web3/providers/persistent/request_processor.py +136 -56
  114. web3/providers/persistent/subscription_container.py +56 -0
  115. web3/providers/persistent/subscription_manager.py +233 -0
  116. web3/providers/persistent/websocket.py +29 -92
  117. web3/providers/rpc/__init__.py +5 -0
  118. web3/providers/rpc/async_rpc.py +73 -18
  119. web3/providers/rpc/rpc.py +73 -30
  120. web3/providers/rpc/utils.py +1 -13
  121. web3/scripts/install_pre_releases.py +33 -0
  122. web3/scripts/parse_pygeth_version.py +16 -0
  123. web3/testing.py +4 -4
  124. web3/tracing.py +9 -5
  125. web3/types.py +141 -74
  126. web3/utils/__init__.py +64 -5
  127. web3/utils/abi.py +790 -10
  128. web3/utils/address.py +8 -0
  129. web3/utils/async_exception_handling.py +20 -11
  130. web3/utils/caching.py +34 -4
  131. web3/utils/exception_handling.py +9 -12
  132. web3/utils/subscriptions.py +285 -0
  133. {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/LICENSE +1 -1
  134. web3-7.7.0.dist-info/METADATA +130 -0
  135. web3-7.7.0.dist-info/RECORD +171 -0
  136. {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/WHEEL +1 -1
  137. web3/_utils/caching.py +0 -155
  138. web3/_utils/contract_sources/contract_data/address_reflector.py +0 -29
  139. web3/_utils/module_testing/go_ethereum_personal_module.py +0 -300
  140. web3/_utils/request.py +0 -265
  141. web3-7.0.0b2.dist-info/METADATA +0 -106
  142. web3-7.0.0b2.dist-info/RECORD +0 -163
  143. /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
  144. {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/top_level.txt +0 -0
web3/contract/utils.py CHANGED
@@ -9,21 +9,33 @@ from typing import (
9
9
  Tuple,
10
10
  Type,
11
11
  Union,
12
+ cast,
12
13
  )
13
14
 
14
15
  from eth_abi.exceptions import (
15
16
  DecodingError,
16
17
  )
17
18
  from eth_typing import (
19
+ ABI,
20
+ ABICallable,
21
+ ABIFunction,
18
22
  ChecksumAddress,
23
+ TypeStr,
24
+ )
25
+ from eth_utils.abi import (
26
+ abi_to_signature,
27
+ filter_abi_by_type,
28
+ get_abi_output_types,
29
+ )
30
+ from eth_utils.toolz import (
31
+ compose,
32
+ curry,
19
33
  )
20
34
  from hexbytes import (
21
35
  HexBytes,
22
36
  )
23
37
 
24
38
  from web3._utils.abi import (
25
- filter_by_type,
26
- get_abi_output_types,
27
39
  map_abi_data,
28
40
  named_tree,
29
41
  recursive_dict_to_namedtuple,
@@ -31,8 +43,10 @@ from web3._utils.abi import (
31
43
  from web3._utils.async_transactions import (
32
44
  async_fill_transaction_defaults,
33
45
  )
46
+ from web3._utils.compat import (
47
+ TypeAlias,
48
+ )
34
49
  from web3._utils.contracts import (
35
- find_matching_fn_abi,
36
50
  prepare_transaction,
37
51
  )
38
52
  from web3._utils.normalizers import (
@@ -43,35 +57,79 @@ from web3._utils.transactions import (
43
57
  )
44
58
  from web3.exceptions import (
45
59
  BadFunctionCallOutput,
60
+ Web3ValueError,
46
61
  )
47
62
  from web3.types import (
48
- ABI,
49
- ABIFunction,
63
+ ABIElementIdentifier,
50
64
  BlockIdentifier,
51
- FunctionIdentifier,
65
+ RPCEndpoint,
52
66
  StateOverride,
67
+ TContractEvent,
53
68
  TContractFn,
54
69
  TxParams,
55
70
  )
71
+ from web3.utils.abi import (
72
+ get_abi_element,
73
+ )
56
74
 
57
75
  if TYPE_CHECKING:
58
76
  from web3 import ( # noqa: F401
59
77
  AsyncWeb3,
60
78
  Web3,
61
79
  )
80
+ from web3.providers.persistent import ( # noqa: F401
81
+ PersistentConnectionProvider,
82
+ )
62
83
 
63
84
  ACCEPTABLE_EMPTY_STRINGS = ["0x", b"0x", "", b""]
64
85
 
65
86
 
87
+ @curry
88
+ def format_contract_call_return_data_curried(
89
+ async_w3: Union["AsyncWeb3", "Web3"],
90
+ decode_tuples: bool,
91
+ fn_abi: ABICallable,
92
+ abi_element_identifier: ABIElementIdentifier,
93
+ normalizers: Tuple[Callable[..., Any], ...],
94
+ output_types: Sequence[TypeStr],
95
+ return_data: Any,
96
+ ) -> Any:
97
+ """
98
+ Helper function for formatting contract call return data for batch requests. Curry
99
+ with all arguments except `return_data` and process `return_data` once it is
100
+ available.
101
+ """
102
+ try:
103
+ output_data = async_w3.codec.decode(output_types, return_data)
104
+ except DecodingError as e:
105
+ msg = (
106
+ f"Could not decode contract function call to {abi_element_identifier} "
107
+ f"with return data: {str(return_data)}, output_types: {output_types}"
108
+ )
109
+ raise BadFunctionCallOutput(msg) from e
110
+
111
+ _normalizers = itertools.chain(
112
+ BASE_RETURN_NORMALIZERS,
113
+ normalizers,
114
+ )
115
+ normalized_data = map_abi_data(_normalizers, output_types, output_data)
116
+
117
+ if decode_tuples and fn_abi["type"] == "function":
118
+ decoded = named_tree(fn_abi["outputs"], normalized_data)
119
+ normalized_data = recursive_dict_to_namedtuple(decoded)
120
+
121
+ return normalized_data[0] if len(normalized_data) == 1 else normalized_data
122
+
123
+
66
124
  def call_contract_function(
67
125
  w3: "Web3",
68
126
  address: ChecksumAddress,
69
127
  normalizers: Tuple[Callable[..., Any], ...],
70
- function_identifier: FunctionIdentifier,
128
+ abi_element_identifier: ABIElementIdentifier,
71
129
  transaction: TxParams,
72
130
  block_id: Optional[BlockIdentifier] = None,
73
131
  contract_abi: Optional[ABI] = None,
74
- fn_abi: Optional[ABIFunction] = None,
132
+ abi_callable: Optional[ABICallable] = None,
75
133
  state_override: Optional[StateOverride] = None,
76
134
  ccip_read_enabled: Optional[bool] = None,
77
135
  decode_tuples: Optional[bool] = False,
@@ -85,9 +143,9 @@ def call_contract_function(
85
143
  call_transaction = prepare_transaction(
86
144
  address,
87
145
  w3,
88
- fn_identifier=function_identifier,
146
+ abi_element_identifier=abi_element_identifier,
89
147
  contract_abi=contract_abi,
90
- fn_abi=fn_abi,
148
+ abi_callable=abi_callable,
91
149
  transaction=transaction,
92
150
  fn_args=args,
93
151
  fn_kwargs=kwargs,
@@ -100,12 +158,50 @@ def call_contract_function(
100
158
  ccip_read_enabled=ccip_read_enabled,
101
159
  )
102
160
 
103
- if fn_abi is None:
104
- fn_abi = find_matching_fn_abi(
105
- contract_abi, w3.codec, function_identifier, args, kwargs
161
+ if abi_callable is None:
162
+ abi_callable = cast(
163
+ ABIFunction,
164
+ get_abi_element(
165
+ contract_abi,
166
+ abi_element_identifier,
167
+ *args,
168
+ abi_codec=w3.codec,
169
+ **kwargs,
170
+ ),
106
171
  )
107
172
 
108
- output_types = get_abi_output_types(fn_abi)
173
+ # get the output types, which only exist for function types
174
+ output_types = []
175
+ if abi_callable["type"] == "function":
176
+ output_types = get_abi_output_types(abi_callable)
177
+
178
+ provider = w3.provider
179
+ if hasattr(provider, "_is_batching") and provider._is_batching:
180
+ BatchingReturnData: TypeAlias = Tuple[Tuple[RPCEndpoint, Any], Tuple[Any, ...]]
181
+ request_information = tuple(cast(BatchingReturnData, return_data))
182
+ method_and_params = request_information[0]
183
+
184
+ # append return data formatting to result formatters
185
+ current_response_formatters = request_information[1]
186
+ current_result_formatters = current_response_formatters[0]
187
+ updated_result_formatters = compose(
188
+ # contract call return data formatter
189
+ format_contract_call_return_data_curried(
190
+ w3,
191
+ decode_tuples,
192
+ abi_callable,
193
+ abi_element_identifier,
194
+ normalizers,
195
+ output_types,
196
+ ),
197
+ current_result_formatters,
198
+ )
199
+ response_formatters = (
200
+ updated_result_formatters, # result formatters
201
+ current_response_formatters[1], # error formatters
202
+ current_response_formatters[2], # null result formatters
203
+ )
204
+ return (method_and_params, response_formatters)
109
205
 
110
206
  try:
111
207
  output_data = w3.codec.decode(output_types, return_data)
@@ -123,7 +219,7 @@ def call_contract_function(
123
219
  )
124
220
  else:
125
221
  msg = (
126
- f"Could not decode contract function call to {function_identifier} "
222
+ f"Could not decode contract function call to {abi_element_identifier} "
127
223
  f"with return data: {str(return_data)}, output_types: {output_types}"
128
224
  )
129
225
  raise BadFunctionCallOutput(msg) from e
@@ -134,8 +230,8 @@ def call_contract_function(
134
230
  )
135
231
  normalized_data = map_abi_data(_normalizers, output_types, output_data)
136
232
 
137
- if decode_tuples:
138
- decoded = named_tree(fn_abi["outputs"], normalized_data)
233
+ if decode_tuples and abi_callable["type"] == "function":
234
+ decoded = named_tree(abi_callable["outputs"], normalized_data)
139
235
  normalized_data = recursive_dict_to_namedtuple(decoded)
140
236
 
141
237
  if len(normalized_data) == 1:
@@ -147,7 +243,7 @@ def call_contract_function(
147
243
  def transact_with_contract_function(
148
244
  address: ChecksumAddress,
149
245
  w3: "Web3",
150
- function_name: Optional[FunctionIdentifier] = None,
246
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
151
247
  transaction: Optional[TxParams] = None,
152
248
  contract_abi: Optional[ABI] = None,
153
249
  fn_abi: Optional[ABIFunction] = None,
@@ -161,10 +257,10 @@ def transact_with_contract_function(
161
257
  transact_transaction = prepare_transaction(
162
258
  address,
163
259
  w3,
164
- fn_identifier=function_name,
260
+ abi_element_identifier=abi_element_identifier,
165
261
  contract_abi=contract_abi,
166
262
  transaction=transaction,
167
- fn_abi=fn_abi,
263
+ abi_callable=fn_abi,
168
264
  fn_args=args,
169
265
  fn_kwargs=kwargs,
170
266
  )
@@ -176,7 +272,7 @@ def transact_with_contract_function(
176
272
  def estimate_gas_for_function(
177
273
  address: ChecksumAddress,
178
274
  w3: "Web3",
179
- fn_identifier: Optional[FunctionIdentifier] = None,
275
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
180
276
  transaction: Optional[TxParams] = None,
181
277
  contract_abi: Optional[ABI] = None,
182
278
  fn_abi: Optional[ABIFunction] = None,
@@ -185,7 +281,8 @@ def estimate_gas_for_function(
185
281
  *args: Any,
186
282
  **kwargs: Any,
187
283
  ) -> int:
188
- """Estimates gas cost a function call would take.
284
+ """
285
+ Estimates gas cost a function call would take.
189
286
 
190
287
  Don't call this directly, instead use :meth:`Contract.estimate_gas`
191
288
  on your contract instance.
@@ -193,9 +290,9 @@ def estimate_gas_for_function(
193
290
  estimate_transaction = prepare_transaction(
194
291
  address,
195
292
  w3,
196
- fn_identifier=fn_identifier,
293
+ abi_element_identifier=abi_element_identifier,
197
294
  contract_abi=contract_abi,
198
- fn_abi=fn_abi,
295
+ abi_callable=fn_abi,
199
296
  transaction=transaction,
200
297
  fn_args=args,
201
298
  fn_kwargs=kwargs,
@@ -207,14 +304,15 @@ def estimate_gas_for_function(
207
304
  def build_transaction_for_function(
208
305
  address: ChecksumAddress,
209
306
  w3: "Web3",
210
- function_name: Optional[FunctionIdentifier] = None,
307
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
211
308
  transaction: Optional[TxParams] = None,
212
309
  contract_abi: Optional[ABI] = None,
213
310
  fn_abi: Optional[ABIFunction] = None,
214
311
  *args: Any,
215
312
  **kwargs: Any,
216
313
  ) -> TxParams:
217
- """Builds a dictionary with the fields required to make the given transaction
314
+ """
315
+ Builds a dictionary with the fields required to make the given transaction
218
316
 
219
317
  Don't call this directly, instead use :meth:`Contract.build_transaction`
220
318
  on your contract instance.
@@ -222,9 +320,9 @@ def build_transaction_for_function(
222
320
  prepared_transaction = prepare_transaction(
223
321
  address,
224
322
  w3,
225
- fn_identifier=function_name,
323
+ abi_element_identifier=abi_element_identifier,
226
324
  contract_abi=contract_abi,
227
- fn_abi=fn_abi,
325
+ abi_callable=fn_abi,
228
326
  transaction=transaction,
229
327
  fn_args=args,
230
328
  fn_kwargs=kwargs,
@@ -242,14 +340,20 @@ def find_functions_by_identifier(
242
340
  callable_check: Callable[..., Any],
243
341
  function_type: Type[TContractFn],
244
342
  ) -> List[TContractFn]:
245
- fns_abi = filter_by_type("function", contract_abi)
343
+ """
344
+ Given a contract ABI, return a list of TContractFunction instances.
345
+ """
346
+ fns_abi = sorted(
347
+ filter_abi_by_type("function", contract_abi),
348
+ key=lambda fn: (fn["name"], len(fn.get("inputs", []))),
349
+ )
246
350
  return [
247
351
  function_type.factory(
248
- fn_abi["name"],
352
+ abi_to_signature(fn_abi),
249
353
  w3=w3,
250
354
  contract_abi=contract_abi,
251
355
  address=address,
252
- function_identifier=fn_abi["name"],
356
+ abi_element_identifier=abi_to_signature(fn_abi),
253
357
  abi=fn_abi,
254
358
  )
255
359
  for fn_abi in fns_abi
@@ -260,15 +364,59 @@ def find_functions_by_identifier(
260
364
  def get_function_by_identifier(
261
365
  fns: Sequence[TContractFn], identifier: str
262
366
  ) -> TContractFn:
367
+ """
368
+ Check that the provided list of TContractFunction instances contains one element and
369
+ return it.
370
+ """
263
371
  if len(fns) > 1:
264
- raise ValueError(
372
+ raise Web3ValueError(
265
373
  f"Found multiple functions with matching {identifier}. " f"Found: {fns!r}"
266
374
  )
267
375
  elif len(fns) == 0:
268
- raise ValueError(f"Could not find any function with matching {identifier}")
376
+ raise Web3ValueError(f"Could not find any function with matching {identifier}")
269
377
  return fns[0]
270
378
 
271
379
 
380
+ def find_events_by_identifier(
381
+ contract_abi: ABI,
382
+ w3: Union["Web3", "AsyncWeb3"],
383
+ address: ChecksumAddress,
384
+ callable_check: Callable[..., Any],
385
+ event_type: Type[TContractEvent],
386
+ ) -> List[TContractEvent]:
387
+ """
388
+ Given a contract ABI, return a list of TContractEvent instances.
389
+ """
390
+ event_abis = filter_abi_by_type("event", contract_abi)
391
+ return [
392
+ event_type.factory(
393
+ event_abi["name"],
394
+ w3=w3,
395
+ contract_abi=contract_abi,
396
+ address=address,
397
+ abi=event_abi,
398
+ )
399
+ for event_abi in event_abis
400
+ if callable_check(event_abi)
401
+ ]
402
+
403
+
404
+ def get_event_by_identifier(
405
+ events: Sequence[TContractEvent], identifier: str
406
+ ) -> TContractEvent:
407
+ """
408
+ Check that the provided list of TContractEvent instances contains one element and
409
+ return it.
410
+ """
411
+ if len(events) > 1:
412
+ raise Web3ValueError(
413
+ f"Found multiple events with matching {identifier}. " f"Found: {events!r}"
414
+ )
415
+ elif len(events) == 0:
416
+ raise Web3ValueError(f"Could not find any event with matching {identifier}")
417
+ return events[0]
418
+
419
+
272
420
  # --- async --- #
273
421
 
274
422
 
@@ -276,7 +424,7 @@ async def async_call_contract_function(
276
424
  async_w3: "AsyncWeb3",
277
425
  address: ChecksumAddress,
278
426
  normalizers: Tuple[Callable[..., Any], ...],
279
- function_identifier: FunctionIdentifier,
427
+ abi_element_identifier: ABIElementIdentifier,
280
428
  transaction: TxParams,
281
429
  block_id: Optional[BlockIdentifier] = None,
282
430
  contract_abi: Optional[ABI] = None,
@@ -294,9 +442,9 @@ async def async_call_contract_function(
294
442
  call_transaction = prepare_transaction(
295
443
  address,
296
444
  async_w3,
297
- fn_identifier=function_identifier,
445
+ abi_element_identifier=abi_element_identifier,
298
446
  contract_abi=contract_abi,
299
- fn_abi=fn_abi,
447
+ abi_callable=fn_abi,
300
448
  transaction=transaction,
301
449
  fn_args=args,
302
450
  fn_kwargs=kwargs,
@@ -310,11 +458,60 @@ async def async_call_contract_function(
310
458
  )
311
459
 
312
460
  if fn_abi is None:
313
- fn_abi = find_matching_fn_abi(
314
- contract_abi, async_w3.codec, function_identifier, args, kwargs
461
+ fn_abi = cast(
462
+ ABIFunction,
463
+ get_abi_element(
464
+ contract_abi,
465
+ abi_element_identifier,
466
+ *args,
467
+ abi_codec=async_w3.codec,
468
+ **kwargs,
469
+ ),
315
470
  )
316
471
 
317
- output_types = get_abi_output_types(fn_abi)
472
+ # get the output types, which only exist for function types
473
+ output_types = []
474
+ if fn_abi["type"] == "function":
475
+ output_types = get_abi_output_types(fn_abi)
476
+
477
+ if async_w3.provider._is_batching:
478
+ contract_call_return_data_formatter = format_contract_call_return_data_curried(
479
+ async_w3,
480
+ decode_tuples,
481
+ fn_abi,
482
+ abi_element_identifier,
483
+ normalizers,
484
+ output_types,
485
+ )
486
+ if async_w3.provider.has_persistent_connection:
487
+ # get the current request id
488
+ provider = cast("PersistentConnectionProvider", async_w3.provider)
489
+ current_request_id = provider._batch_request_counter - 1
490
+ provider._request_processor.append_result_formatter_for_request(
491
+ current_request_id, contract_call_return_data_formatter
492
+ )
493
+ else:
494
+ BatchingReturnData: TypeAlias = Tuple[
495
+ Tuple[RPCEndpoint, Any], Tuple[Any, ...]
496
+ ]
497
+ request_information = tuple(cast(BatchingReturnData, return_data))
498
+ method_and_params = request_information[0]
499
+
500
+ # append return data formatter to result formatters
501
+ current_response_formatters = request_information[1]
502
+ current_result_formatters = current_response_formatters[0]
503
+ updated_result_formatters = compose(
504
+ contract_call_return_data_formatter,
505
+ current_result_formatters,
506
+ )
507
+ response_formatters = (
508
+ updated_result_formatters, # result formatters
509
+ current_response_formatters[1], # error formatters
510
+ current_response_formatters[2], # null result formatters
511
+ )
512
+ return (method_and_params, response_formatters)
513
+
514
+ return return_data
318
515
 
319
516
  try:
320
517
  output_data = async_w3.codec.decode(output_types, return_data)
@@ -332,7 +529,7 @@ async def async_call_contract_function(
332
529
  )
333
530
  else:
334
531
  msg = (
335
- f"Could not decode contract function call to {function_identifier} "
532
+ f"Could not decode contract function call to {abi_element_identifier} "
336
533
  f"with return data: {str(return_data)}, output_types: {output_types}"
337
534
  )
338
535
  raise BadFunctionCallOutput(msg) from e
@@ -347,16 +544,13 @@ async def async_call_contract_function(
347
544
  decoded = named_tree(fn_abi["outputs"], normalized_data)
348
545
  normalized_data = recursive_dict_to_namedtuple(decoded)
349
546
 
350
- if len(normalized_data) == 1:
351
- return normalized_data[0]
352
- else:
353
- return normalized_data
547
+ return normalized_data[0] if len(normalized_data) == 1 else normalized_data
354
548
 
355
549
 
356
550
  async def async_transact_with_contract_function(
357
551
  address: ChecksumAddress,
358
552
  async_w3: "AsyncWeb3",
359
- function_name: Optional[FunctionIdentifier] = None,
553
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
360
554
  transaction: Optional[TxParams] = None,
361
555
  contract_abi: Optional[ABI] = None,
362
556
  fn_abi: Optional[ABIFunction] = None,
@@ -370,10 +564,10 @@ async def async_transact_with_contract_function(
370
564
  transact_transaction = prepare_transaction(
371
565
  address,
372
566
  async_w3,
373
- fn_identifier=function_name,
567
+ abi_element_identifier=abi_element_identifier,
374
568
  contract_abi=contract_abi,
375
569
  transaction=transaction,
376
- fn_abi=fn_abi,
570
+ abi_callable=fn_abi,
377
571
  fn_args=args,
378
572
  fn_kwargs=kwargs,
379
573
  )
@@ -385,7 +579,7 @@ async def async_transact_with_contract_function(
385
579
  async def async_estimate_gas_for_function(
386
580
  address: ChecksumAddress,
387
581
  async_w3: "AsyncWeb3",
388
- fn_identifier: Optional[FunctionIdentifier] = None,
582
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
389
583
  transaction: Optional[TxParams] = None,
390
584
  contract_abi: Optional[ABI] = None,
391
585
  fn_abi: Optional[ABIFunction] = None,
@@ -394,7 +588,8 @@ async def async_estimate_gas_for_function(
394
588
  *args: Any,
395
589
  **kwargs: Any,
396
590
  ) -> int:
397
- """Estimates gas cost a function call would take.
591
+ """
592
+ Estimates gas cost a function call would take.
398
593
 
399
594
  Don't call this directly, instead use :meth:`Contract.estimate_gas`
400
595
  on your contract instance.
@@ -402,9 +597,9 @@ async def async_estimate_gas_for_function(
402
597
  estimate_transaction = prepare_transaction(
403
598
  address,
404
599
  async_w3,
405
- fn_identifier=fn_identifier,
600
+ abi_element_identifier=abi_element_identifier,
406
601
  contract_abi=contract_abi,
407
- fn_abi=fn_abi,
602
+ abi_callable=fn_abi,
408
603
  transaction=transaction,
409
604
  fn_args=args,
410
605
  fn_kwargs=kwargs,
@@ -418,14 +613,15 @@ async def async_estimate_gas_for_function(
418
613
  async def async_build_transaction_for_function(
419
614
  address: ChecksumAddress,
420
615
  async_w3: "AsyncWeb3",
421
- function_name: Optional[FunctionIdentifier] = None,
616
+ abi_element_identifier: Optional[ABIElementIdentifier] = None,
422
617
  transaction: Optional[TxParams] = None,
423
618
  contract_abi: Optional[ABI] = None,
424
619
  fn_abi: Optional[ABIFunction] = None,
425
620
  *args: Any,
426
621
  **kwargs: Any,
427
622
  ) -> TxParams:
428
- """Builds a dictionary with the fields required to make the given transaction
623
+ """
624
+ Builds a dictionary with the fields required to make the given transaction
429
625
 
430
626
  Don't call this directly, instead use :meth:`Contract.build_transaction`
431
627
  on your contract instance.
@@ -433,9 +629,9 @@ async def async_build_transaction_for_function(
433
629
  prepared_transaction = prepare_transaction(
434
630
  address,
435
631
  async_w3,
436
- fn_identifier=function_name,
632
+ abi_element_identifier=abi_element_identifier,
437
633
  contract_abi=contract_abi,
438
- fn_abi=fn_abi,
634
+ abi_callable=fn_abi,
439
635
  transaction=transaction,
440
636
  fn_args=args,
441
637
  fn_kwargs=kwargs,