web3 7.5.0__py3-none-any.whl → 7.6.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.
@@ -1,4 +1,3 @@
1
- import copy
2
1
  from typing import (
3
2
  TYPE_CHECKING,
4
3
  Any,
@@ -15,14 +14,15 @@ from typing import (
15
14
 
16
15
  from eth_typing import (
17
16
  ABI,
18
- ABIEvent,
19
17
  ChecksumAddress,
20
18
  )
21
19
  from eth_utils import (
22
20
  combomethod,
23
21
  )
24
22
  from eth_utils.abi import (
23
+ abi_to_signature,
25
24
  get_abi_input_names,
25
+ get_abi_input_types,
26
26
  get_all_function_abis,
27
27
  )
28
28
  from eth_utils.toolz import (
@@ -34,6 +34,9 @@ from hexbytes import (
34
34
 
35
35
  from web3._utils.abi import (
36
36
  fallback_func_abi_exists,
37
+ filter_by_types,
38
+ get_abi_element_signature,
39
+ get_name_from_abi_element_identifier,
37
40
  receive_func_abi_exists,
38
41
  )
39
42
  from web3._utils.abi_element_identifiers import (
@@ -48,6 +51,8 @@ from web3._utils.compat import (
48
51
  )
49
52
  from web3._utils.contracts import (
50
53
  async_parse_block_identifier,
54
+ copy_contract_event,
55
+ copy_contract_function,
51
56
  )
52
57
  from web3._utils.datatypes import (
53
58
  PropertyCheckingFactory,
@@ -86,7 +91,9 @@ from web3.contract.utils import (
86
91
  get_function_by_identifier,
87
92
  )
88
93
  from web3.exceptions import (
94
+ ABIEventNotFound,
89
95
  ABIFunctionNotFound,
96
+ NoABIEventsFound,
90
97
  NoABIFound,
91
98
  NoABIFunctionsFound,
92
99
  Web3AttributeError,
@@ -101,6 +108,8 @@ from web3.types import (
101
108
  TxParams,
102
109
  )
103
110
  from web3.utils.abi import (
111
+ _get_any_abi_signature_with_name,
112
+ filter_abi_by_type,
104
113
  get_abi_element,
105
114
  )
106
115
 
@@ -113,16 +122,27 @@ class AsyncContractEvent(BaseContractEvent):
113
122
  # mypy types
114
123
  w3: "AsyncWeb3"
115
124
 
116
- def __call__(self) -> "AsyncContractEvent":
117
- clone = copy.copy(self)
118
-
119
- if not self.abi:
120
- self.abi = cast(
121
- ABIEvent,
122
- get_abi_element(self.contract_abi, self.event_name),
123
- )
125
+ def __call__(self, *args: Any, **kwargs: Any) -> "AsyncContractEvent":
126
+ event_abi = get_abi_element(
127
+ filter_abi_by_type("event", self.contract_abi),
128
+ self.name,
129
+ *args,
130
+ abi_codec=self.w3.codec,
131
+ **kwargs,
132
+ )
133
+ argument_types = get_abi_input_types(event_abi)
134
+ event_signature = str(
135
+ get_abi_element_signature(self.abi_element_identifier, argument_types)
136
+ )
137
+ contract_event = AsyncContractEvent.factory(
138
+ event_signature,
139
+ w3=self.w3,
140
+ contract_abi=self.contract_abi,
141
+ address=self.address,
142
+ abi_element_identifier=event_signature,
143
+ )
124
144
 
125
- return clone
145
+ return copy_contract_event(contract_event, *args, **kwargs)
126
146
 
127
147
  @combomethod
128
148
  async def get_logs(
@@ -188,11 +208,9 @@ class AsyncContractEvent(BaseContractEvent):
188
208
  same time as ``from_block`` or ``to_block``
189
209
  :yield: Tuple of :class:`AttributeDict` instances
190
210
  """
191
- event_abi = self._get_event_abi()
192
-
193
211
  # validate ``argument_filters`` if present
194
212
  if argument_filters is not None:
195
- event_arg_names = get_abi_input_names(event_abi)
213
+ event_arg_names = get_abi_input_names(self.abi)
196
214
  if not all(arg in event_arg_names for arg in argument_filters.keys()):
197
215
  raise Web3ValidationError(
198
216
  "When filtering by argument names, all argument names must be "
@@ -200,17 +218,17 @@ class AsyncContractEvent(BaseContractEvent):
200
218
  )
201
219
 
202
220
  _filter_params = self._get_event_filter_params(
203
- event_abi, argument_filters, from_block, to_block, block_hash
221
+ self.abi, argument_filters, from_block, to_block, block_hash
204
222
  )
205
223
  # call JSON-RPC API
206
224
  logs = await self.w3.eth.get_logs(_filter_params)
207
225
 
208
226
  # convert raw binary data to Python proxy objects as described by ABI:
209
227
  all_event_logs = tuple(
210
- get_event_data(self.w3.codec, event_abi, entry) for entry in logs
228
+ get_event_data(self.w3.codec, self.abi, entry) for entry in logs
211
229
  )
212
230
  filtered_logs = self._process_get_logs_argument_filters(
213
- event_abi,
231
+ self.abi,
214
232
  all_event_logs,
215
233
  argument_filters,
216
234
  )
@@ -231,7 +249,7 @@ class AsyncContractEvent(BaseContractEvent):
231
249
  """
232
250
  Create filter object that tracks logs emitted by this contract event.
233
251
  """
234
- filter_builder = AsyncEventFilterBuilder(self._get_event_abi(), self.w3.codec)
252
+ filter_builder = AsyncEventFilterBuilder(self.abi, self.w3.codec)
235
253
  self._set_up_filter_builder(
236
254
  argument_filters,
237
255
  from_block,
@@ -241,9 +259,7 @@ class AsyncContractEvent(BaseContractEvent):
241
259
  filter_builder,
242
260
  )
243
261
  log_filter = await filter_builder.deploy(self.w3)
244
- log_filter.log_entry_formatter = get_event_data(
245
- self.w3.codec, self._get_event_abi()
246
- )
262
+ log_filter.log_entry_formatter = get_event_data(self.w3.codec, self.abi)
247
263
  log_filter.builder = filter_builder
248
264
 
249
265
  return log_filter
@@ -251,18 +267,16 @@ class AsyncContractEvent(BaseContractEvent):
251
267
  @combomethod
252
268
  def build_filter(self) -> AsyncEventFilterBuilder:
253
269
  builder = AsyncEventFilterBuilder(
254
- self._get_event_abi(),
270
+ self.abi,
255
271
  self.w3.codec,
256
- formatter=get_event_data(self.w3.codec, self._get_event_abi()),
272
+ formatter=get_event_data(self.w3.codec, self.abi),
257
273
  )
258
274
  builder.address = self.address
259
275
  return builder
260
276
 
261
277
  @classmethod
262
278
  def factory(cls, class_name: str, **kwargs: Any) -> Self:
263
- return PropertyCheckingFactory(class_name, (cls,), kwargs)(
264
- abi=kwargs.get("abi")
265
- )
279
+ return PropertyCheckingFactory(class_name, (cls,), kwargs)()
266
280
 
267
281
 
268
282
  class AsyncContractEvents(BaseContractEvents):
@@ -271,28 +285,84 @@ class AsyncContractEvents(BaseContractEvents):
271
285
  ) -> None:
272
286
  super().__init__(abi, w3, AsyncContractEvent, address)
273
287
 
288
+ def __iter__(self) -> Iterable["AsyncContractEvent"]:
289
+ if not hasattr(self, "_events") or not self._events:
290
+ return
291
+
292
+ for event in self._events:
293
+ yield self[abi_to_signature(event)]
294
+
295
+ def __getattr__(self, event_name: str) -> "AsyncContractEvent":
296
+ if super().__getattribute__("abi") is None:
297
+ raise NoABIFound(
298
+ "There is no ABI found for this contract.",
299
+ )
300
+ if "_events" not in self.__dict__ or len(self._events) == 0:
301
+ raise NoABIEventsFound(
302
+ "The abi for this contract contains no event definitions. ",
303
+ "Are you sure you provided the correct contract abi?",
304
+ )
305
+ elif get_name_from_abi_element_identifier(event_name) not in [
306
+ get_name_from_abi_element_identifier(event["name"])
307
+ for event in self._events
308
+ ]:
309
+ raise ABIEventNotFound(
310
+ f"The event '{event_name}' was not found in this contract's abi. ",
311
+ "Are you sure you provided the correct contract abi?",
312
+ )
313
+ else:
314
+ event_abi = get_abi_element(self._events, event_name)
315
+ argument_types = get_abi_input_types(event_abi)
316
+ event_signature = str(get_abi_element_signature(event_name, argument_types))
317
+ return super().__getattribute__(event_signature)
318
+
319
+ def __getitem__(self, event_name: str) -> "AsyncContractEvent":
320
+ return getattr(self, event_name)
321
+
274
322
 
275
323
  class AsyncContractFunction(BaseContractFunction):
276
324
  # mypy types
277
325
  w3: "AsyncWeb3"
278
326
 
279
327
  def __call__(self, *args: Any, **kwargs: Any) -> "AsyncContractFunction":
280
- clone = copy.copy(self)
281
- if args is None:
282
- clone.args = tuple()
283
- else:
284
- clone.args = args
328
+ element_name = self.abi_element_identifier
329
+ if element_name in ["fallback", "receive"] or len(args) + len(kwargs):
330
+ # Use only the name if a fallback, receive function
331
+ # or when args/kwargs are present to find the proper element
332
+ element_name = self.fn_name
333
+
334
+ function_abi = get_abi_element(
335
+ filter_by_types(
336
+ ["function", "constructor", "fallback", "receive"],
337
+ self.contract_abi,
338
+ ),
339
+ element_name,
340
+ *args,
341
+ abi_codec=self.w3.codec,
342
+ **kwargs,
343
+ )
285
344
 
286
- if kwargs is None:
287
- clone.kwargs = {}
288
- else:
289
- clone.kwargs = kwargs
290
- clone._set_function_info()
291
- return clone
345
+ argument_types = None
346
+ if function_abi["type"] not in ["fallback", "receive"]:
347
+ argument_types = get_abi_input_types(function_abi)
348
+
349
+ function_signature = str(
350
+ get_abi_element_signature(self.abi_element_identifier, argument_types)
351
+ )
352
+ contract_function = AsyncContractFunction.factory(
353
+ function_signature,
354
+ w3=self.w3,
355
+ contract_abi=self.contract_abi,
356
+ address=self.address,
357
+ abi_element_identifier=function_signature,
358
+ decode_tuples=self.decode_tuples,
359
+ )
360
+
361
+ return copy_contract_function(contract_function, *args, **kwargs)
292
362
 
293
363
  @classmethod
294
364
  def factory(cls, class_name: str, **kwargs: Any) -> Self:
295
- return PropertyCheckingFactory(class_name, (cls,), kwargs)(kwargs.get("abi"))
365
+ return PropertyCheckingFactory(class_name, (cls,), kwargs)()
296
366
 
297
367
  async def call(
298
368
  self,
@@ -332,11 +402,13 @@ class AsyncContractFunction(BaseContractFunction):
332
402
 
333
403
  block_id = await async_parse_block_identifier(self.w3, block_identifier)
334
404
 
405
+ abi_element_identifier = abi_to_signature(self.abi)
406
+
335
407
  return await async_call_contract_function(
336
408
  self.w3,
337
409
  self.address,
338
410
  self._return_data_normalizers,
339
- self.abi_element_identifier,
411
+ abi_element_identifier,
340
412
  call_transaction,
341
413
  block_id,
342
414
  self.contract_abi,
@@ -350,10 +422,11 @@ class AsyncContractFunction(BaseContractFunction):
350
422
 
351
423
  async def transact(self, transaction: Optional[TxParams] = None) -> HexBytes:
352
424
  setup_transaction = self._transact(transaction)
425
+ abi_element_identifier = abi_to_signature(self.abi)
353
426
  return await async_transact_with_contract_function(
354
427
  self.address,
355
428
  self.w3,
356
- self.abi_element_identifier,
429
+ abi_element_identifier,
357
430
  setup_transaction,
358
431
  self.contract_abi,
359
432
  self.abi,
@@ -368,10 +441,11 @@ class AsyncContractFunction(BaseContractFunction):
368
441
  state_override: Optional[StateOverride] = None,
369
442
  ) -> int:
370
443
  setup_transaction = self._estimate_gas(transaction)
444
+ abi_element_identifier = abi_to_signature(self.abi)
371
445
  return await async_estimate_gas_for_function(
372
446
  self.address,
373
447
  self.w3,
374
- self.abi_element_identifier,
448
+ abi_element_identifier,
375
449
  setup_transaction,
376
450
  self.contract_abi,
377
451
  self.abi,
@@ -385,10 +459,11 @@ class AsyncContractFunction(BaseContractFunction):
385
459
  self, transaction: Optional[TxParams] = None
386
460
  ) -> TxParams:
387
461
  built_transaction = self._build_transaction(transaction)
462
+ abi_element_identifier = abi_to_signature(self.abi)
388
463
  return await async_build_transaction_for_function(
389
464
  self.address,
390
465
  self.w3,
391
- self.abi_element_identifier,
466
+ abi_element_identifier,
392
467
  built_transaction,
393
468
  self.contract_abi,
394
469
  self.abi,
@@ -439,23 +514,45 @@ class AsyncContractFunctions(BaseContractFunctions):
439
514
  ) -> None:
440
515
  super().__init__(abi, w3, AsyncContractFunction, address, decode_tuples)
441
516
 
517
+ def __iter__(self) -> Iterable["AsyncContractFunction"]:
518
+ if not hasattr(self, "_functions") or not self._functions:
519
+ return
520
+
521
+ for func in self._functions:
522
+ yield self[abi_to_signature(func)]
523
+
442
524
  def __getattr__(self, function_name: str) -> "AsyncContractFunction":
443
- if self.abi is None:
525
+ if super().__getattribute__("abi") is None:
444
526
  raise NoABIFound(
445
527
  "There is no ABI found for this contract.",
446
528
  )
447
- if "_functions" not in self.__dict__:
529
+ elif "_functions" not in self.__dict__ or len(self._functions) == 0:
448
530
  raise NoABIFunctionsFound(
449
531
  "The abi for this contract contains no function definitions. ",
450
532
  "Are you sure you provided the correct contract abi?",
451
533
  )
452
- elif function_name not in self.__dict__["_functions"]:
534
+ elif get_name_from_abi_element_identifier(function_name) not in [
535
+ get_name_from_abi_element_identifier(function["name"])
536
+ for function in self._functions
537
+ ]:
453
538
  raise ABIFunctionNotFound(
454
- f"The function '{function_name}' was not found in this contract's abi.",
455
- " Are you sure you provided the correct contract abi?",
539
+ f"The function '{function_name}' was not found in this contract's "
540
+ "abi. Are you sure you provided the correct contract abi?",
541
+ )
542
+
543
+ function_identifier = function_name
544
+
545
+ if "(" not in function_name:
546
+ function_identifier = _get_any_abi_signature_with_name(
547
+ function_name, self._functions
456
548
  )
457
- else:
458
- return super().__getattribute__(function_name)
549
+
550
+ return super().__getattribute__(
551
+ function_identifier,
552
+ )
553
+
554
+ def __getitem__(self, function_name: str) -> "AsyncContractFunction":
555
+ return getattr(self, function_name)
459
556
 
460
557
 
461
558
  class AsyncContract(BaseContract):
@@ -523,6 +620,16 @@ class AsyncContract(BaseContract):
523
620
  normalizers=normalizers,
524
621
  ),
525
622
  )
623
+
624
+ if contract.abi:
625
+ for abi in contract.abi:
626
+ abi_name = abi.get("name")
627
+ if abi_name in ["abi", "address"]:
628
+ raise Web3AttributeError(
629
+ f"Contract contains a reserved word `{abi_name}` "
630
+ f"and could not be instantiated."
631
+ )
632
+
526
633
  contract.functions = AsyncContractFunctions(
527
634
  contract.abi, contract.w3, decode_tuples=contract.decode_tuples
528
635
  )
@@ -623,12 +730,12 @@ class AsyncContractCaller(BaseContractCaller):
623
730
  self._functions = get_all_function_abis(self.abi)
624
731
 
625
732
  for func in self._functions:
733
+ abi_signature = abi_to_signature(func)
626
734
  fn = AsyncContractFunction.factory(
627
- func["name"],
735
+ abi_signature,
628
736
  w3=w3,
629
737
  contract_abi=self.abi,
630
738
  address=self.address,
631
- abi_element_identifier=func["name"],
632
739
  decode_tuples=decode_tuples,
633
740
  )
634
741
 
@@ -640,7 +747,7 @@ class AsyncContractCaller(BaseContractCaller):
640
747
  ccip_read_enabled=ccip_read_enabled,
641
748
  )
642
749
 
643
- setattr(self, func["name"], caller_method)
750
+ setattr(self, abi_signature, caller_method)
644
751
 
645
752
  def __call__(
646
753
  self,