web3 7.5.0__py3-none-any.whl → 7.6.1__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.
- web3/_utils/abi.py +59 -1
- web3/_utils/contract_sources/contract_data/ambiguous_function_contract.py +42 -0
- web3/_utils/contract_sources/contract_data/event_contracts.py +49 -4
- web3/_utils/contracts.py +49 -8
- web3/_utils/method_formatters.py +1 -0
- web3/_utils/module_testing/eth_module.py +11 -0
- web3/_utils/rpc_abi.py +1 -0
- web3/_utils/validation.py +3 -0
- web3/contract/async_contract.py +216 -62
- web3/contract/base_contract.py +176 -110
- web3/contract/contract.py +227 -64
- web3/contract/utils.py +7 -3
- web3/eth/async_eth.py +11 -0
- web3/eth/eth.py +11 -0
- web3/providers/eth_tester/defaults.py +1 -0
- web3/providers/ipc.py +1 -1
- web3/providers/persistent/async_ipc.py +1 -1
- web3/utils/abi.py +300 -85
- web3/utils/address.py +8 -0
- {web3-7.5.0.dist-info → web3-7.6.1.dist-info}/METADATA +8 -8
- {web3-7.5.0.dist-info → web3-7.6.1.dist-info}/RECORD +24 -23
- {web3-7.5.0.dist-info → web3-7.6.1.dist-info}/LICENSE +0 -0
- {web3-7.5.0.dist-info → web3-7.6.1.dist-info}/WHEEL +0 -0
- {web3-7.5.0.dist-info → web3-7.6.1.dist-info}/top_level.txt +0 -0
web3/contract/contract.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import copy
|
|
2
1
|
from typing import (
|
|
3
2
|
TYPE_CHECKING,
|
|
4
3
|
Any,
|
|
@@ -14,13 +13,14 @@ from typing import (
|
|
|
14
13
|
|
|
15
14
|
from eth_typing import (
|
|
16
15
|
ABI,
|
|
17
|
-
|
|
16
|
+
ABIFunction,
|
|
18
17
|
ChecksumAddress,
|
|
19
18
|
)
|
|
20
19
|
from eth_utils import (
|
|
20
|
+
abi_to_signature,
|
|
21
21
|
combomethod,
|
|
22
|
+
filter_abi_by_type,
|
|
22
23
|
get_abi_input_names,
|
|
23
|
-
get_all_function_abis,
|
|
24
24
|
)
|
|
25
25
|
from eth_utils.toolz import (
|
|
26
26
|
partial,
|
|
@@ -31,6 +31,7 @@ from hexbytes import (
|
|
|
31
31
|
|
|
32
32
|
from web3._utils.abi import (
|
|
33
33
|
fallback_func_abi_exists,
|
|
34
|
+
get_name_from_abi_element_identifier,
|
|
34
35
|
receive_func_abi_exists,
|
|
35
36
|
)
|
|
36
37
|
from web3._utils.abi_element_identifiers import (
|
|
@@ -41,6 +42,8 @@ from web3._utils.compat import (
|
|
|
41
42
|
Self,
|
|
42
43
|
)
|
|
43
44
|
from web3._utils.contracts import (
|
|
45
|
+
copy_contract_event,
|
|
46
|
+
copy_contract_function,
|
|
44
47
|
parse_block_identifier,
|
|
45
48
|
)
|
|
46
49
|
from web3._utils.datatypes import (
|
|
@@ -83,7 +86,10 @@ from web3.contract.utils import (
|
|
|
83
86
|
transact_with_contract_function,
|
|
84
87
|
)
|
|
85
88
|
from web3.exceptions import (
|
|
89
|
+
ABIEventNotFound,
|
|
86
90
|
ABIFunctionNotFound,
|
|
91
|
+
MismatchedABI,
|
|
92
|
+
NoABIEventsFound,
|
|
87
93
|
NoABIFound,
|
|
88
94
|
NoABIFunctionsFound,
|
|
89
95
|
Web3AttributeError,
|
|
@@ -98,6 +104,9 @@ from web3.types import (
|
|
|
98
104
|
TxParams,
|
|
99
105
|
)
|
|
100
106
|
from web3.utils.abi import (
|
|
107
|
+
_filter_by_argument_count,
|
|
108
|
+
_get_any_abi_signature_with_name,
|
|
109
|
+
_mismatched_abi_error_diagnosis,
|
|
101
110
|
get_abi_element,
|
|
102
111
|
)
|
|
103
112
|
|
|
@@ -110,16 +119,8 @@ class ContractEvent(BaseContractEvent):
|
|
|
110
119
|
# mypy types
|
|
111
120
|
w3: "Web3"
|
|
112
121
|
|
|
113
|
-
def __call__(self) -> "ContractEvent":
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if not self.abi:
|
|
117
|
-
self.abi = cast(
|
|
118
|
-
ABIEvent,
|
|
119
|
-
get_abi_element(self.contract_abi, self.event_name),
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
return clone
|
|
122
|
+
def __call__(self, *args: Any, **kwargs: Any) -> "ContractEvent":
|
|
123
|
+
return copy_contract_event(self, *args, **kwargs)
|
|
123
124
|
|
|
124
125
|
@combomethod
|
|
125
126
|
def get_logs(
|
|
@@ -186,7 +187,6 @@ class ContractEvent(BaseContractEvent):
|
|
|
186
187
|
:yield: Tuple of :class:`AttributeDict` instances
|
|
187
188
|
"""
|
|
188
189
|
event_abi = self._get_event_abi()
|
|
189
|
-
|
|
190
190
|
# validate ``argument_filters`` if present
|
|
191
191
|
if argument_filters is not None:
|
|
192
192
|
event_arg_names = get_abi_input_names(event_abi)
|
|
@@ -228,7 +228,8 @@ class ContractEvent(BaseContractEvent):
|
|
|
228
228
|
"""
|
|
229
229
|
Create filter object that tracks logs emitted by this contract event.
|
|
230
230
|
"""
|
|
231
|
-
|
|
231
|
+
abi = self._get_event_abi()
|
|
232
|
+
filter_builder = EventFilterBuilder(abi, self.w3.codec)
|
|
232
233
|
self._set_up_filter_builder(
|
|
233
234
|
argument_filters,
|
|
234
235
|
from_block,
|
|
@@ -238,28 +239,25 @@ class ContractEvent(BaseContractEvent):
|
|
|
238
239
|
filter_builder,
|
|
239
240
|
)
|
|
240
241
|
log_filter = filter_builder.deploy(self.w3)
|
|
241
|
-
log_filter.log_entry_formatter = get_event_data(
|
|
242
|
-
self.w3.codec, self._get_event_abi()
|
|
243
|
-
)
|
|
242
|
+
log_filter.log_entry_formatter = get_event_data(self.w3.codec, abi)
|
|
244
243
|
log_filter.builder = filter_builder
|
|
245
244
|
|
|
246
245
|
return log_filter
|
|
247
246
|
|
|
248
247
|
@combomethod
|
|
249
248
|
def build_filter(self) -> EventFilterBuilder:
|
|
249
|
+
abi = self._get_event_abi()
|
|
250
250
|
builder = EventFilterBuilder(
|
|
251
|
-
|
|
251
|
+
abi,
|
|
252
252
|
self.w3.codec,
|
|
253
|
-
formatter=get_event_data(self.w3.codec,
|
|
253
|
+
formatter=get_event_data(self.w3.codec, abi),
|
|
254
254
|
)
|
|
255
255
|
builder.address = self.address
|
|
256
256
|
return builder
|
|
257
257
|
|
|
258
258
|
@classmethod
|
|
259
259
|
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
260
|
-
return PropertyCheckingFactory(class_name, (cls,), kwargs)(
|
|
261
|
-
abi=kwargs.get("abi")
|
|
262
|
-
)
|
|
260
|
+
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
263
261
|
|
|
264
262
|
|
|
265
263
|
class ContractEvents(BaseContractEvents):
|
|
@@ -268,33 +266,155 @@ class ContractEvents(BaseContractEvents):
|
|
|
268
266
|
) -> None:
|
|
269
267
|
super().__init__(abi, w3, ContractEvent, address)
|
|
270
268
|
|
|
269
|
+
def __getattr__(self, event_name: str) -> "ContractEvent":
|
|
270
|
+
if super().__getattribute__("abi") is None:
|
|
271
|
+
raise NoABIFound(
|
|
272
|
+
"There is no ABI found for this contract.",
|
|
273
|
+
)
|
|
274
|
+
elif "_events" not in self.__dict__ or len(self._events) == 0:
|
|
275
|
+
raise NoABIEventsFound(
|
|
276
|
+
"The abi for this contract contains no event definitions. ",
|
|
277
|
+
"Are you sure you provided the correct contract abi?",
|
|
278
|
+
)
|
|
279
|
+
elif get_name_from_abi_element_identifier(event_name) not in [
|
|
280
|
+
get_name_from_abi_element_identifier(event["name"])
|
|
281
|
+
for event in self._events
|
|
282
|
+
]:
|
|
283
|
+
raise ABIEventNotFound(
|
|
284
|
+
f"The event '{event_name}' was not found in this contract's abi. ",
|
|
285
|
+
"Are you sure you provided the correct contract abi?",
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
if "(" not in event_name:
|
|
289
|
+
event_name = _get_any_abi_signature_with_name(event_name, self._events)
|
|
290
|
+
else:
|
|
291
|
+
event_name = f"_{event_name}"
|
|
292
|
+
|
|
293
|
+
return super().__getattribute__(event_name)
|
|
294
|
+
|
|
295
|
+
def __getitem__(self, event_name: str) -> "ContractEvent":
|
|
296
|
+
return getattr(self, event_name)
|
|
297
|
+
|
|
298
|
+
def __iter__(self) -> Iterable["ContractEvent"]:
|
|
299
|
+
if not hasattr(self, "_events") or not self._events:
|
|
300
|
+
return
|
|
301
|
+
|
|
302
|
+
for event in self._events:
|
|
303
|
+
yield self[abi_to_signature(event)]
|
|
304
|
+
|
|
271
305
|
|
|
272
306
|
class ContractFunction(BaseContractFunction):
|
|
273
307
|
# mypy types
|
|
274
308
|
w3: "Web3"
|
|
275
309
|
|
|
276
310
|
def __call__(self, *args: Any, **kwargs: Any) -> "ContractFunction":
|
|
277
|
-
|
|
278
|
-
if args
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
311
|
+
# When a function is called, check arguments to obtain the correct function
|
|
312
|
+
# in the contract. self will be used if all args and kwargs are
|
|
313
|
+
# encodable to self.abi, otherwise the correct function is obtained from
|
|
314
|
+
# the contract.
|
|
315
|
+
if (
|
|
316
|
+
self.abi_element_identifier in [FallbackFn, ReceiveFn]
|
|
317
|
+
or self.abi_element_identifier == "constructor"
|
|
318
|
+
):
|
|
319
|
+
return copy_contract_function(self, *args, **kwargs)
|
|
320
|
+
|
|
321
|
+
all_functions = cast(
|
|
322
|
+
List[ABIFunction],
|
|
323
|
+
filter_abi_by_type(
|
|
324
|
+
"function",
|
|
325
|
+
self.contract_abi,
|
|
326
|
+
),
|
|
327
|
+
)
|
|
328
|
+
# Filter functions by name to obtain function signatures
|
|
329
|
+
function_name = get_name_from_abi_element_identifier(
|
|
330
|
+
self.abi_element_identifier
|
|
331
|
+
)
|
|
332
|
+
function_abis = [
|
|
333
|
+
function for function in all_functions if function["name"] == function_name
|
|
334
|
+
]
|
|
335
|
+
num_args = len(args) + len(kwargs)
|
|
336
|
+
function_abis_with_arg_count = cast(
|
|
337
|
+
List[ABIFunction],
|
|
338
|
+
_filter_by_argument_count(
|
|
339
|
+
num_args,
|
|
340
|
+
function_abis,
|
|
341
|
+
),
|
|
342
|
+
)
|
|
282
343
|
|
|
283
|
-
if
|
|
284
|
-
|
|
344
|
+
if not len(function_abis_with_arg_count):
|
|
345
|
+
# Build an ABI without arguments to determine if one exists
|
|
346
|
+
function_abis_with_arg_count = [
|
|
347
|
+
ABIFunction({"type": "function", "name": function_name})
|
|
348
|
+
]
|
|
349
|
+
|
|
350
|
+
# Check that arguments in call match a function ABI
|
|
351
|
+
num_attempts = 0
|
|
352
|
+
function_abi_matches = []
|
|
353
|
+
contract_function = None
|
|
354
|
+
for abi in function_abis_with_arg_count:
|
|
355
|
+
try:
|
|
356
|
+
num_attempts += 1
|
|
357
|
+
|
|
358
|
+
# Search for a function ABI that matches the arguments used
|
|
359
|
+
function_abi_matches.append(
|
|
360
|
+
cast(
|
|
361
|
+
ABIFunction,
|
|
362
|
+
get_abi_element(
|
|
363
|
+
function_abis,
|
|
364
|
+
abi_to_signature(abi),
|
|
365
|
+
*args,
|
|
366
|
+
abi_codec=self.w3.codec,
|
|
367
|
+
**kwargs,
|
|
368
|
+
),
|
|
369
|
+
)
|
|
370
|
+
)
|
|
371
|
+
except MismatchedABI:
|
|
372
|
+
# ignore exceptions
|
|
373
|
+
continue
|
|
374
|
+
|
|
375
|
+
if len(function_abi_matches) == 1:
|
|
376
|
+
function_abi = function_abi_matches[0]
|
|
377
|
+
if abi_to_signature(self.abi) == abi_to_signature(function_abi):
|
|
378
|
+
contract_function = self
|
|
379
|
+
else:
|
|
380
|
+
# Found a match that is not self
|
|
381
|
+
contract_function = ContractFunction.factory(
|
|
382
|
+
abi_to_signature(function_abi),
|
|
383
|
+
w3=self.w3,
|
|
384
|
+
contract_abi=self.contract_abi,
|
|
385
|
+
address=self.address,
|
|
386
|
+
abi_element_identifier=abi_to_signature(function_abi),
|
|
387
|
+
abi=function_abi,
|
|
388
|
+
)
|
|
285
389
|
else:
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
390
|
+
for abi in function_abi_matches:
|
|
391
|
+
if abi_to_signature(self.abi) == abi_to_signature(abi):
|
|
392
|
+
contract_function = self
|
|
393
|
+
break
|
|
394
|
+
else:
|
|
395
|
+
# Raise exception if multiple found
|
|
396
|
+
raise MismatchedABI(
|
|
397
|
+
_mismatched_abi_error_diagnosis(
|
|
398
|
+
function_name,
|
|
399
|
+
self.contract_abi,
|
|
400
|
+
len(function_abi_matches),
|
|
401
|
+
num_args,
|
|
402
|
+
*args,
|
|
403
|
+
abi_codec=self.w3.codec,
|
|
404
|
+
**kwargs,
|
|
405
|
+
)
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
return copy_contract_function(contract_function, *args, **kwargs)
|
|
289
409
|
|
|
290
410
|
@classmethod
|
|
291
411
|
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
292
|
-
return PropertyCheckingFactory(class_name, (cls,), kwargs)(
|
|
412
|
+
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
293
413
|
|
|
294
414
|
def call(
|
|
295
415
|
self,
|
|
296
416
|
transaction: Optional[TxParams] = None,
|
|
297
|
-
block_identifier: BlockIdentifier = None,
|
|
417
|
+
block_identifier: Optional[BlockIdentifier] = None,
|
|
298
418
|
state_override: Optional[StateOverride] = None,
|
|
299
419
|
ccip_read_enabled: Optional[bool] = None,
|
|
300
420
|
) -> Any:
|
|
@@ -319,9 +439,9 @@ class ContractFunction(BaseContractFunction):
|
|
|
319
439
|
addr = contract.functions.owner().call()
|
|
320
440
|
|
|
321
441
|
:param transaction: Dictionary of transaction info for web3 interface
|
|
322
|
-
:param block_identifier:
|
|
323
|
-
:param state_override
|
|
324
|
-
:param ccip_read_enabled
|
|
442
|
+
:param block_identifier: Block number or string "latest", "pending", "earliest"
|
|
443
|
+
:param state_override: Dictionary of state override values
|
|
444
|
+
:param ccip_read_enabled: Enable CCIP read operations for the call
|
|
325
445
|
:return: ``Caller`` object that has contract public functions
|
|
326
446
|
and variables exposed as Python methods
|
|
327
447
|
"""
|
|
@@ -329,11 +449,13 @@ class ContractFunction(BaseContractFunction):
|
|
|
329
449
|
|
|
330
450
|
block_id = parse_block_identifier(self.w3, block_identifier)
|
|
331
451
|
|
|
452
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
453
|
+
|
|
332
454
|
return call_contract_function(
|
|
333
455
|
self.w3,
|
|
334
456
|
self.address,
|
|
335
457
|
self._return_data_normalizers,
|
|
336
|
-
|
|
458
|
+
abi_element_identifier,
|
|
337
459
|
call_transaction,
|
|
338
460
|
block_id,
|
|
339
461
|
self.contract_abi,
|
|
@@ -347,11 +469,12 @@ class ContractFunction(BaseContractFunction):
|
|
|
347
469
|
|
|
348
470
|
def transact(self, transaction: Optional[TxParams] = None) -> HexBytes:
|
|
349
471
|
setup_transaction = self._transact(transaction)
|
|
472
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
350
473
|
|
|
351
474
|
return transact_with_contract_function(
|
|
352
475
|
self.address,
|
|
353
476
|
self.w3,
|
|
354
|
-
|
|
477
|
+
abi_element_identifier,
|
|
355
478
|
setup_transaction,
|
|
356
479
|
self.contract_abi,
|
|
357
480
|
self.abi,
|
|
@@ -366,10 +489,11 @@ class ContractFunction(BaseContractFunction):
|
|
|
366
489
|
state_override: Optional[StateOverride] = None,
|
|
367
490
|
) -> int:
|
|
368
491
|
setup_transaction = self._estimate_gas(transaction)
|
|
492
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
369
493
|
return estimate_gas_for_function(
|
|
370
494
|
self.address,
|
|
371
495
|
self.w3,
|
|
372
|
-
|
|
496
|
+
abi_element_identifier,
|
|
373
497
|
setup_transaction,
|
|
374
498
|
self.contract_abi,
|
|
375
499
|
self.abi,
|
|
@@ -381,11 +505,12 @@ class ContractFunction(BaseContractFunction):
|
|
|
381
505
|
|
|
382
506
|
def build_transaction(self, transaction: Optional[TxParams] = None) -> TxParams:
|
|
383
507
|
built_transaction = self._build_transaction(transaction)
|
|
508
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
384
509
|
|
|
385
510
|
return build_transaction_for_function(
|
|
386
511
|
self.address,
|
|
387
512
|
self.w3,
|
|
388
|
-
|
|
513
|
+
abi_element_identifier,
|
|
389
514
|
built_transaction,
|
|
390
515
|
self.contract_abi,
|
|
391
516
|
self.abi,
|
|
@@ -400,12 +525,14 @@ class ContractFunction(BaseContractFunction):
|
|
|
400
525
|
address: Optional[ChecksumAddress] = None,
|
|
401
526
|
) -> "ContractFunction":
|
|
402
527
|
if abi and fallback_func_abi_exists(abi):
|
|
528
|
+
fallback_abi = filter_abi_by_type("fallback", abi)[0]
|
|
403
529
|
return ContractFunction.factory(
|
|
404
530
|
"fallback",
|
|
405
531
|
w3=w3,
|
|
406
532
|
contract_abi=abi,
|
|
407
533
|
address=address,
|
|
408
534
|
abi_element_identifier=FallbackFn,
|
|
535
|
+
abi=fallback_abi,
|
|
409
536
|
)()
|
|
410
537
|
return cast(ContractFunction, NonExistentFallbackFunction())
|
|
411
538
|
|
|
@@ -416,12 +543,14 @@ class ContractFunction(BaseContractFunction):
|
|
|
416
543
|
address: Optional[ChecksumAddress] = None,
|
|
417
544
|
) -> "ContractFunction":
|
|
418
545
|
if abi and receive_func_abi_exists(abi):
|
|
546
|
+
receive_abi = filter_abi_by_type("receive", abi)[0]
|
|
419
547
|
return ContractFunction.factory(
|
|
420
548
|
"receive",
|
|
421
549
|
w3=w3,
|
|
422
550
|
contract_abi=abi,
|
|
423
551
|
address=address,
|
|
424
552
|
abi_element_identifier=ReceiveFn,
|
|
553
|
+
abi=receive_abi,
|
|
425
554
|
)()
|
|
426
555
|
return cast(ContractFunction, NonExistentReceiveFunction())
|
|
427
556
|
|
|
@@ -436,23 +565,45 @@ class ContractFunctions(BaseContractFunctions):
|
|
|
436
565
|
) -> None:
|
|
437
566
|
super().__init__(abi, w3, ContractFunction, address, decode_tuples)
|
|
438
567
|
|
|
568
|
+
def __iter__(self) -> Iterable["ContractFunction"]:
|
|
569
|
+
if not hasattr(self, "_functions") or not self._functions:
|
|
570
|
+
return
|
|
571
|
+
|
|
572
|
+
for func in self._functions:
|
|
573
|
+
yield self[abi_to_signature(func)]
|
|
574
|
+
|
|
439
575
|
def __getattr__(self, function_name: str) -> "ContractFunction":
|
|
440
|
-
if
|
|
576
|
+
if super().__getattribute__("abi") is None:
|
|
441
577
|
raise NoABIFound(
|
|
442
578
|
"There is no ABI found for this contract.",
|
|
443
579
|
)
|
|
444
|
-
|
|
580
|
+
elif "_functions" not in self.__dict__ or len(self._functions) == 0:
|
|
445
581
|
raise NoABIFunctionsFound(
|
|
446
582
|
"The abi for this contract contains no function definitions. ",
|
|
447
583
|
"Are you sure you provided the correct contract abi?",
|
|
448
584
|
)
|
|
449
|
-
elif function_name not in
|
|
585
|
+
elif get_name_from_abi_element_identifier(function_name) not in [
|
|
586
|
+
get_name_from_abi_element_identifier(function["name"])
|
|
587
|
+
for function in self._functions
|
|
588
|
+
]:
|
|
450
589
|
raise ABIFunctionNotFound(
|
|
451
|
-
f"The function '{function_name}' was not found in this
|
|
452
|
-
"
|
|
590
|
+
f"The function '{function_name}' was not found in this ",
|
|
591
|
+
"contract's abi.",
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
if "(" not in function_name:
|
|
595
|
+
function_name = _get_any_abi_signature_with_name(
|
|
596
|
+
function_name, self._functions
|
|
453
597
|
)
|
|
454
598
|
else:
|
|
455
|
-
|
|
599
|
+
function_name = f"_{function_name}"
|
|
600
|
+
|
|
601
|
+
return super().__getattribute__(
|
|
602
|
+
function_name,
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
def __getitem__(self, function_name: str) -> "ContractFunction":
|
|
606
|
+
return getattr(self, function_name)
|
|
456
607
|
|
|
457
608
|
|
|
458
609
|
class Contract(BaseContract):
|
|
@@ -477,7 +628,8 @@ class Contract(BaseContract):
|
|
|
477
628
|
)
|
|
478
629
|
|
|
479
630
|
if address:
|
|
480
|
-
|
|
631
|
+
# invoke ``w3._ens`` over ``w3.ens`` to avoid premature instantiation
|
|
632
|
+
self.address = normalize_address(cast("ENS", _w3._ens), address)
|
|
481
633
|
|
|
482
634
|
if not self.address:
|
|
483
635
|
raise Web3TypeError(
|
|
@@ -488,7 +640,11 @@ class Contract(BaseContract):
|
|
|
488
640
|
self.abi, _w3, self.address, decode_tuples=self.decode_tuples
|
|
489
641
|
)
|
|
490
642
|
self.caller = ContractCaller(
|
|
491
|
-
self.abi,
|
|
643
|
+
self.abi,
|
|
644
|
+
_w3,
|
|
645
|
+
self.address,
|
|
646
|
+
decode_tuples=self.decode_tuples,
|
|
647
|
+
contract_functions=self.functions,
|
|
492
648
|
)
|
|
493
649
|
self.events = ContractEvents(self.abi, _w3, self.address)
|
|
494
650
|
self.fallback = Contract.get_fallback_function(
|
|
@@ -512,7 +668,8 @@ class Contract(BaseContract):
|
|
|
512
668
|
|
|
513
669
|
normalizers = {
|
|
514
670
|
"abi": normalize_abi,
|
|
515
|
-
|
|
671
|
+
# invoke ``w3._ens`` over ``w3.ens`` to avoid premature instantiation
|
|
672
|
+
"address": partial(normalize_address, w3._ens),
|
|
516
673
|
"bytecode": normalize_bytecode,
|
|
517
674
|
"bytecode_runtime": normalize_bytecode,
|
|
518
675
|
}
|
|
@@ -526,6 +683,16 @@ class Contract(BaseContract):
|
|
|
526
683
|
normalizers=normalizers,
|
|
527
684
|
),
|
|
528
685
|
)
|
|
686
|
+
|
|
687
|
+
if contract.abi:
|
|
688
|
+
for abi in contract.abi:
|
|
689
|
+
abi_name = abi.get("name")
|
|
690
|
+
if abi_name in ["abi", "address"]:
|
|
691
|
+
raise Web3AttributeError(
|
|
692
|
+
f"Contract contains a reserved word `{abi_name}` "
|
|
693
|
+
f"and could not be instantiated."
|
|
694
|
+
)
|
|
695
|
+
|
|
529
696
|
contract.functions = ContractFunctions(
|
|
530
697
|
contract.abi, contract.w3, decode_tuples=contract.decode_tuples
|
|
531
698
|
)
|
|
@@ -534,6 +701,7 @@ class Contract(BaseContract):
|
|
|
534
701
|
contract.w3,
|
|
535
702
|
contract.address,
|
|
536
703
|
decode_tuples=contract.decode_tuples,
|
|
704
|
+
contract_functions=contract.functions,
|
|
537
705
|
)
|
|
538
706
|
contract.events = ContractEvents(contract.abi, contract.w3)
|
|
539
707
|
contract.fallback = Contract.get_fallback_function(
|
|
@@ -599,7 +767,7 @@ class Contract(BaseContract):
|
|
|
599
767
|
|
|
600
768
|
@combomethod
|
|
601
769
|
def get_event_by_identifier(
|
|
602
|
-
|
|
770
|
+
self, events: Sequence["ContractEvent"], identifier: str
|
|
603
771
|
) -> "ContractEvent":
|
|
604
772
|
return get_event_by_identifier(events, identifier)
|
|
605
773
|
|
|
@@ -617,6 +785,7 @@ class ContractCaller(BaseContractCaller):
|
|
|
617
785
|
block_identifier: BlockIdentifier = None,
|
|
618
786
|
ccip_read_enabled: Optional[bool] = None,
|
|
619
787
|
decode_tuples: Optional[bool] = False,
|
|
788
|
+
contract_functions: Optional[ContractFunctions] = None,
|
|
620
789
|
) -> None:
|
|
621
790
|
super().__init__(abi, w3, address, decode_tuples=decode_tuples)
|
|
622
791
|
|
|
@@ -624,18 +793,13 @@ class ContractCaller(BaseContractCaller):
|
|
|
624
793
|
if transaction is None:
|
|
625
794
|
transaction = {}
|
|
626
795
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
fn = ContractFunction.factory(
|
|
631
|
-
func["name"],
|
|
632
|
-
w3=w3,
|
|
633
|
-
contract_abi=self.abi,
|
|
634
|
-
address=self.address,
|
|
635
|
-
abi_element_identifier=func["name"],
|
|
636
|
-
decode_tuples=decode_tuples,
|
|
796
|
+
if contract_functions is None:
|
|
797
|
+
contract_functions = ContractFunctions(
|
|
798
|
+
abi, w3, address=address, decode_tuples=decode_tuples
|
|
637
799
|
)
|
|
638
800
|
|
|
801
|
+
self._functions = contract_functions._functions
|
|
802
|
+
for fn in contract_functions.__iter__():
|
|
639
803
|
caller_method = partial(
|
|
640
804
|
self.call_function,
|
|
641
805
|
fn,
|
|
@@ -643,8 +807,7 @@ class ContractCaller(BaseContractCaller):
|
|
|
643
807
|
block_identifier=block_identifier,
|
|
644
808
|
ccip_read_enabled=ccip_read_enabled,
|
|
645
809
|
)
|
|
646
|
-
|
|
647
|
-
setattr(self, func["name"], caller_method)
|
|
810
|
+
setattr(self, str(fn.abi_element_identifier), caller_method)
|
|
648
811
|
|
|
649
812
|
def __call__(
|
|
650
813
|
self,
|
web3/contract/utils.py
CHANGED
|
@@ -23,6 +23,7 @@ from eth_typing import (
|
|
|
23
23
|
TypeStr,
|
|
24
24
|
)
|
|
25
25
|
from eth_utils.abi import (
|
|
26
|
+
abi_to_signature,
|
|
26
27
|
filter_abi_by_type,
|
|
27
28
|
get_abi_output_types,
|
|
28
29
|
)
|
|
@@ -342,14 +343,17 @@ def find_functions_by_identifier(
|
|
|
342
343
|
"""
|
|
343
344
|
Given a contract ABI, return a list of TContractFunction instances.
|
|
344
345
|
"""
|
|
345
|
-
fns_abi =
|
|
346
|
+
fns_abi = sorted(
|
|
347
|
+
filter_abi_by_type("function", contract_abi),
|
|
348
|
+
key=lambda fn: (fn["name"], len(fn.get("inputs", []))),
|
|
349
|
+
)
|
|
346
350
|
return [
|
|
347
351
|
function_type.factory(
|
|
348
|
-
fn_abi
|
|
352
|
+
abi_to_signature(fn_abi),
|
|
349
353
|
w3=w3,
|
|
350
354
|
contract_abi=contract_abi,
|
|
351
355
|
address=address,
|
|
352
|
-
abi_element_identifier=fn_abi
|
|
356
|
+
abi_element_identifier=abi_to_signature(fn_abi),
|
|
353
357
|
abi=fn_abi,
|
|
354
358
|
)
|
|
355
359
|
for fn_abi in fns_abi
|
web3/eth/async_eth.py
CHANGED
|
@@ -127,6 +127,17 @@ class AsyncEth(BaseEth):
|
|
|
127
127
|
async def accounts(self) -> Tuple[ChecksumAddress]:
|
|
128
128
|
return await self._accounts()
|
|
129
129
|
|
|
130
|
+
# eth_blobBaseFee
|
|
131
|
+
|
|
132
|
+
_eth_blobBaseFee: Method[Callable[[], Awaitable[Wei]]] = Method(
|
|
133
|
+
RPC.eth_blobBaseFee,
|
|
134
|
+
is_property=True,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
async def blob_base_fee(self) -> Wei:
|
|
139
|
+
return await self._eth_blobBaseFee()
|
|
140
|
+
|
|
130
141
|
# eth_blockNumber
|
|
131
142
|
|
|
132
143
|
get_block_number: Method[Callable[[], Awaitable[BlockNumber]]] = Method(
|
web3/eth/eth.py
CHANGED
|
@@ -119,6 +119,17 @@ class Eth(BaseEth):
|
|
|
119
119
|
def accounts(self) -> Tuple[ChecksumAddress]:
|
|
120
120
|
return self._accounts()
|
|
121
121
|
|
|
122
|
+
# eth_blobBaseFee
|
|
123
|
+
|
|
124
|
+
_eth_blobBaseFee: Method[Callable[[], Wei]] = Method(
|
|
125
|
+
RPC.eth_blobBaseFee,
|
|
126
|
+
is_property=True,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def blob_base_fee(self) -> Wei:
|
|
131
|
+
return self._eth_blobBaseFee()
|
|
132
|
+
|
|
122
133
|
# eth_blockNumber
|
|
123
134
|
|
|
124
135
|
get_block_number: Method[Callable[[], BlockNumber]] = Method(
|
|
@@ -246,6 +246,7 @@ API_ENDPOINTS = {
|
|
|
246
246
|
"chainId": static_return(131277322940537), # from fixture generation file
|
|
247
247
|
"feeHistory": call_eth_tester("get_fee_history"),
|
|
248
248
|
"maxPriorityFeePerGas": static_return(10**9),
|
|
249
|
+
"blobBaseFee": static_return(10**9),
|
|
249
250
|
"gasPrice": static_return(10**9), # must be >= base fee post-London
|
|
250
251
|
"accounts": call_eth_tester("get_accounts"),
|
|
251
252
|
"blockNumber": compose(
|
web3/providers/ipc.py
CHANGED
|
@@ -164,7 +164,7 @@ class IPCProvider(JSONBaseProvider):
|
|
|
164
164
|
def _make_request(self, request: bytes) -> RPCResponse:
|
|
165
165
|
with self._lock, self._socket as sock:
|
|
166
166
|
try:
|
|
167
|
-
sock.sendall(request)
|
|
167
|
+
sock.sendall(request + b"\n")
|
|
168
168
|
except BrokenPipeError:
|
|
169
169
|
# one extra attempt, then give up
|
|
170
170
|
sock = self._socket.reset()
|
|
@@ -116,7 +116,7 @@ class AsyncIPCProvider(PersistentConnectionProvider):
|
|
|
116
116
|
|
|
117
117
|
async def _socket_send(self, request_data: bytes) -> None:
|
|
118
118
|
try:
|
|
119
|
-
self._writer.write(request_data)
|
|
119
|
+
self._writer.write(request_data + b"\n")
|
|
120
120
|
await self._writer.drain()
|
|
121
121
|
except OSError as e:
|
|
122
122
|
# Broken pipe
|