web3 7.4.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.
- web3/_utils/abi.py +59 -1
- web3/_utils/contract_sources/contract_data/arrays_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/bytes_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/constructor_contracts.py +7 -7
- web3/_utils/contract_sources/contract_data/contract_caller_tester.py +3 -3
- web3/_utils/contract_sources/contract_data/emitter_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/event_contracts.py +50 -5
- web3/_utils/contract_sources/contract_data/extended_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/fallback_function_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/function_name_tester_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/math_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/offchain_lookup.py +3 -3
- web3/_utils/contract_sources/contract_data/offchain_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/panic_errors_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/payable_tester.py +3 -3
- web3/_utils/contract_sources/contract_data/receive_function_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/reflector_contracts.py +3 -3
- web3/_utils/contract_sources/contract_data/revert_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/simple_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/storage_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/string_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/tuple_contracts.py +5 -5
- web3/_utils/contracts.py +48 -7
- web3/_utils/method_formatters.py +109 -1
- web3/_utils/module_testing/__init__.py +4 -0
- web3/_utils/module_testing/eth_module.py +11 -0
- web3/_utils/module_testing/go_ethereum_debug_module.py +128 -0
- web3/_utils/rpc_abi.py +4 -0
- web3/_utils/validation.py +3 -0
- web3/contract/async_contract.py +191 -41
- web3/contract/base_contract.py +373 -152
- web3/contract/contract.py +182 -34
- web3/contract/utils.py +51 -2
- web3/eth/async_eth.py +11 -0
- web3/eth/eth.py +11 -0
- web3/geth.py +59 -0
- web3/main.py +4 -0
- web3/manager.py +10 -0
- web3/providers/eth_tester/defaults.py +1 -0
- web3/types.py +87 -2
- web3/utils/abi.py +308 -76
- {web3-7.4.0.dist-info → web3-7.6.0.dist-info}/METADATA +3 -2
- {web3-7.4.0.dist-info → web3-7.6.0.dist-info}/RECORD +46 -45
- {web3-7.4.0.dist-info → web3-7.6.0.dist-info}/WHEEL +1 -1
- {web3-7.4.0.dist-info → web3-7.6.0.dist-info}/LICENSE +0 -0
- {web3-7.4.0.dist-info → web3-7.6.0.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,
|
|
@@ -17,8 +16,10 @@ from eth_typing import (
|
|
|
17
16
|
ChecksumAddress,
|
|
18
17
|
)
|
|
19
18
|
from eth_utils import (
|
|
19
|
+
abi_to_signature,
|
|
20
20
|
combomethod,
|
|
21
21
|
get_abi_input_names,
|
|
22
|
+
get_abi_input_types,
|
|
22
23
|
get_all_function_abis,
|
|
23
24
|
)
|
|
24
25
|
from eth_utils.toolz import (
|
|
@@ -30,6 +31,9 @@ from hexbytes import (
|
|
|
30
31
|
|
|
31
32
|
from web3._utils.abi import (
|
|
32
33
|
fallback_func_abi_exists,
|
|
34
|
+
filter_by_types,
|
|
35
|
+
get_abi_element_signature,
|
|
36
|
+
get_name_from_abi_element_identifier,
|
|
33
37
|
receive_func_abi_exists,
|
|
34
38
|
)
|
|
35
39
|
from web3._utils.abi_element_identifiers import (
|
|
@@ -40,6 +44,8 @@ from web3._utils.compat import (
|
|
|
40
44
|
Self,
|
|
41
45
|
)
|
|
42
46
|
from web3._utils.contracts import (
|
|
47
|
+
copy_contract_event,
|
|
48
|
+
copy_contract_function,
|
|
43
49
|
parse_block_identifier,
|
|
44
50
|
)
|
|
45
51
|
from web3._utils.datatypes import (
|
|
@@ -75,12 +81,16 @@ from web3.contract.utils import (
|
|
|
75
81
|
build_transaction_for_function,
|
|
76
82
|
call_contract_function,
|
|
77
83
|
estimate_gas_for_function,
|
|
84
|
+
find_events_by_identifier,
|
|
78
85
|
find_functions_by_identifier,
|
|
86
|
+
get_event_by_identifier,
|
|
79
87
|
get_function_by_identifier,
|
|
80
88
|
transact_with_contract_function,
|
|
81
89
|
)
|
|
82
90
|
from web3.exceptions import (
|
|
91
|
+
ABIEventNotFound,
|
|
83
92
|
ABIFunctionNotFound,
|
|
93
|
+
NoABIEventsFound,
|
|
84
94
|
NoABIFound,
|
|
85
95
|
NoABIFunctionsFound,
|
|
86
96
|
Web3AttributeError,
|
|
@@ -94,6 +104,11 @@ from web3.types import (
|
|
|
94
104
|
StateOverride,
|
|
95
105
|
TxParams,
|
|
96
106
|
)
|
|
107
|
+
from web3.utils.abi import (
|
|
108
|
+
_get_any_abi_signature_with_name,
|
|
109
|
+
filter_abi_by_type,
|
|
110
|
+
get_abi_element,
|
|
111
|
+
)
|
|
97
112
|
|
|
98
113
|
if TYPE_CHECKING:
|
|
99
114
|
from ens import ENS # noqa: F401
|
|
@@ -104,6 +119,28 @@ class ContractEvent(BaseContractEvent):
|
|
|
104
119
|
# mypy types
|
|
105
120
|
w3: "Web3"
|
|
106
121
|
|
|
122
|
+
def __call__(self, *args: Any, **kwargs: Any) -> "ContractEvent":
|
|
123
|
+
event_abi = get_abi_element(
|
|
124
|
+
filter_abi_by_type("event", self.contract_abi),
|
|
125
|
+
self.name,
|
|
126
|
+
*args,
|
|
127
|
+
abi_codec=self.w3.codec,
|
|
128
|
+
**kwargs,
|
|
129
|
+
)
|
|
130
|
+
argument_types = get_abi_input_types(event_abi)
|
|
131
|
+
event_signature = str(
|
|
132
|
+
get_abi_element_signature(self.abi_element_identifier, argument_types)
|
|
133
|
+
)
|
|
134
|
+
contract_event = ContractEvent.factory(
|
|
135
|
+
event_signature,
|
|
136
|
+
w3=self.w3,
|
|
137
|
+
contract_abi=self.contract_abi,
|
|
138
|
+
address=self.address,
|
|
139
|
+
abi_element_identifier=event_signature,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
return copy_contract_event(contract_event, *args, **kwargs)
|
|
143
|
+
|
|
107
144
|
@combomethod
|
|
108
145
|
def get_logs(
|
|
109
146
|
self,
|
|
@@ -169,7 +206,6 @@ class ContractEvent(BaseContractEvent):
|
|
|
169
206
|
:yield: Tuple of :class:`AttributeDict` instances
|
|
170
207
|
"""
|
|
171
208
|
event_abi = self._get_event_abi()
|
|
172
|
-
|
|
173
209
|
# validate ``argument_filters`` if present
|
|
174
210
|
if argument_filters is not None:
|
|
175
211
|
event_arg_names = get_abi_input_names(event_abi)
|
|
@@ -211,7 +247,8 @@ class ContractEvent(BaseContractEvent):
|
|
|
211
247
|
"""
|
|
212
248
|
Create filter object that tracks logs emitted by this contract event.
|
|
213
249
|
"""
|
|
214
|
-
|
|
250
|
+
abi = self._get_event_abi()
|
|
251
|
+
filter_builder = EventFilterBuilder(abi, self.w3.codec)
|
|
215
252
|
self._set_up_filter_builder(
|
|
216
253
|
argument_filters,
|
|
217
254
|
from_block,
|
|
@@ -221,23 +258,26 @@ class ContractEvent(BaseContractEvent):
|
|
|
221
258
|
filter_builder,
|
|
222
259
|
)
|
|
223
260
|
log_filter = filter_builder.deploy(self.w3)
|
|
224
|
-
log_filter.log_entry_formatter = get_event_data(
|
|
225
|
-
self.w3.codec, self._get_event_abi()
|
|
226
|
-
)
|
|
261
|
+
log_filter.log_entry_formatter = get_event_data(self.w3.codec, abi)
|
|
227
262
|
log_filter.builder = filter_builder
|
|
228
263
|
|
|
229
264
|
return log_filter
|
|
230
265
|
|
|
231
266
|
@combomethod
|
|
232
267
|
def build_filter(self) -> EventFilterBuilder:
|
|
268
|
+
abi = self._get_event_abi()
|
|
233
269
|
builder = EventFilterBuilder(
|
|
234
|
-
|
|
270
|
+
abi,
|
|
235
271
|
self.w3.codec,
|
|
236
|
-
formatter=get_event_data(self.w3.codec,
|
|
272
|
+
formatter=get_event_data(self.w3.codec, abi),
|
|
237
273
|
)
|
|
238
274
|
builder.address = self.address
|
|
239
275
|
return builder
|
|
240
276
|
|
|
277
|
+
@classmethod
|
|
278
|
+
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
279
|
+
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
280
|
+
|
|
241
281
|
|
|
242
282
|
class ContractEvents(BaseContractEvents):
|
|
243
283
|
def __init__(
|
|
@@ -245,28 +285,81 @@ class ContractEvents(BaseContractEvents):
|
|
|
245
285
|
) -> None:
|
|
246
286
|
super().__init__(abi, w3, ContractEvent, address)
|
|
247
287
|
|
|
288
|
+
def __getattr__(self, event_name: str) -> "ContractEvent":
|
|
289
|
+
if super().__getattribute__("abi") is None:
|
|
290
|
+
raise NoABIFound(
|
|
291
|
+
"There is no ABI found for this contract.",
|
|
292
|
+
)
|
|
293
|
+
if "_events" not in self.__dict__ or len(self._events) == 0:
|
|
294
|
+
raise NoABIEventsFound(
|
|
295
|
+
"The abi for this contract contains no event definitions. ",
|
|
296
|
+
"Are you sure you provided the correct contract abi?",
|
|
297
|
+
)
|
|
298
|
+
elif get_name_from_abi_element_identifier(event_name) not in [
|
|
299
|
+
get_name_from_abi_element_identifier(event["name"])
|
|
300
|
+
for event in self._events
|
|
301
|
+
]:
|
|
302
|
+
raise ABIEventNotFound(
|
|
303
|
+
f"The event '{event_name}' was not found in this contract's abi. ",
|
|
304
|
+
"Are you sure you provided the correct contract abi?",
|
|
305
|
+
)
|
|
306
|
+
else:
|
|
307
|
+
event_abi = get_abi_element(self._events, event_name)
|
|
308
|
+
argument_types = get_abi_input_types(event_abi)
|
|
309
|
+
event_signature = str(get_abi_element_signature(event_name, argument_types))
|
|
310
|
+
return super().__getattribute__(event_signature)
|
|
311
|
+
|
|
312
|
+
def __getitem__(self, event_name: str) -> "ContractEvent":
|
|
313
|
+
return getattr(self, event_name)
|
|
314
|
+
|
|
315
|
+
def __iter__(self) -> Iterable["ContractEvent"]:
|
|
316
|
+
for event in self._events:
|
|
317
|
+
yield self[event["name"]]
|
|
318
|
+
|
|
248
319
|
|
|
249
320
|
class ContractFunction(BaseContractFunction):
|
|
250
321
|
# mypy types
|
|
251
322
|
w3: "Web3"
|
|
252
323
|
|
|
253
324
|
def __call__(self, *args: Any, **kwargs: Any) -> "ContractFunction":
|
|
254
|
-
|
|
255
|
-
if args
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
325
|
+
element_name = self.abi_element_identifier
|
|
326
|
+
if element_name in ["fallback", "receive"] or len(args) + len(kwargs):
|
|
327
|
+
# Use only the name if a fallback, receive function
|
|
328
|
+
# or when args/kwargs are present to find the proper element
|
|
329
|
+
element_name = self.fn_name
|
|
330
|
+
|
|
331
|
+
function_abi = get_abi_element(
|
|
332
|
+
filter_by_types(
|
|
333
|
+
["function", "constructor", "fallback", "receive"],
|
|
334
|
+
self.contract_abi,
|
|
335
|
+
),
|
|
336
|
+
element_name,
|
|
337
|
+
*args,
|
|
338
|
+
abi_codec=self.w3.codec,
|
|
339
|
+
**kwargs,
|
|
340
|
+
)
|
|
259
341
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
342
|
+
argument_types = None
|
|
343
|
+
if function_abi["type"] not in ["fallback", "receive"]:
|
|
344
|
+
argument_types = get_abi_input_types(function_abi)
|
|
345
|
+
|
|
346
|
+
function_signature = str(
|
|
347
|
+
get_abi_element_signature(self.abi_element_identifier, argument_types)
|
|
348
|
+
)
|
|
349
|
+
contract_function = ContractFunction.factory(
|
|
350
|
+
function_signature,
|
|
351
|
+
w3=self.w3,
|
|
352
|
+
contract_abi=self.contract_abi,
|
|
353
|
+
address=self.address,
|
|
354
|
+
abi_element_identifier=function_signature,
|
|
355
|
+
decode_tuples=self.decode_tuples,
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
return copy_contract_function(contract_function, *args, **kwargs)
|
|
266
359
|
|
|
267
360
|
@classmethod
|
|
268
361
|
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
269
|
-
return PropertyCheckingFactory(class_name, (cls,), kwargs)(
|
|
362
|
+
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
270
363
|
|
|
271
364
|
def call(
|
|
272
365
|
self,
|
|
@@ -306,11 +399,13 @@ class ContractFunction(BaseContractFunction):
|
|
|
306
399
|
|
|
307
400
|
block_id = parse_block_identifier(self.w3, block_identifier)
|
|
308
401
|
|
|
402
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
403
|
+
|
|
309
404
|
return call_contract_function(
|
|
310
405
|
self.w3,
|
|
311
406
|
self.address,
|
|
312
407
|
self._return_data_normalizers,
|
|
313
|
-
|
|
408
|
+
abi_element_identifier,
|
|
314
409
|
call_transaction,
|
|
315
410
|
block_id,
|
|
316
411
|
self.contract_abi,
|
|
@@ -324,11 +419,12 @@ class ContractFunction(BaseContractFunction):
|
|
|
324
419
|
|
|
325
420
|
def transact(self, transaction: Optional[TxParams] = None) -> HexBytes:
|
|
326
421
|
setup_transaction = self._transact(transaction)
|
|
422
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
327
423
|
|
|
328
424
|
return transact_with_contract_function(
|
|
329
425
|
self.address,
|
|
330
426
|
self.w3,
|
|
331
|
-
|
|
427
|
+
abi_element_identifier,
|
|
332
428
|
setup_transaction,
|
|
333
429
|
self.contract_abi,
|
|
334
430
|
self.abi,
|
|
@@ -343,10 +439,11 @@ class ContractFunction(BaseContractFunction):
|
|
|
343
439
|
state_override: Optional[StateOverride] = None,
|
|
344
440
|
) -> int:
|
|
345
441
|
setup_transaction = self._estimate_gas(transaction)
|
|
442
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
346
443
|
return estimate_gas_for_function(
|
|
347
444
|
self.address,
|
|
348
445
|
self.w3,
|
|
349
|
-
|
|
446
|
+
abi_element_identifier,
|
|
350
447
|
setup_transaction,
|
|
351
448
|
self.contract_abi,
|
|
352
449
|
self.abi,
|
|
@@ -358,11 +455,12 @@ class ContractFunction(BaseContractFunction):
|
|
|
358
455
|
|
|
359
456
|
def build_transaction(self, transaction: Optional[TxParams] = None) -> TxParams:
|
|
360
457
|
built_transaction = self._build_transaction(transaction)
|
|
458
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
361
459
|
|
|
362
460
|
return build_transaction_for_function(
|
|
363
461
|
self.address,
|
|
364
462
|
self.w3,
|
|
365
|
-
|
|
463
|
+
abi_element_identifier,
|
|
366
464
|
built_transaction,
|
|
367
465
|
self.contract_abi,
|
|
368
466
|
self.abi,
|
|
@@ -413,23 +511,45 @@ class ContractFunctions(BaseContractFunctions):
|
|
|
413
511
|
) -> None:
|
|
414
512
|
super().__init__(abi, w3, ContractFunction, address, decode_tuples)
|
|
415
513
|
|
|
514
|
+
def __iter__(self) -> Iterable["ContractFunction"]:
|
|
515
|
+
if not hasattr(self, "_functions") or not self._functions:
|
|
516
|
+
return
|
|
517
|
+
|
|
518
|
+
for func in self._functions:
|
|
519
|
+
yield self[abi_to_signature(func)]
|
|
520
|
+
|
|
416
521
|
def __getattr__(self, function_name: str) -> "ContractFunction":
|
|
417
|
-
if
|
|
522
|
+
if super().__getattribute__("abi") is None:
|
|
418
523
|
raise NoABIFound(
|
|
419
524
|
"There is no ABI found for this contract.",
|
|
420
525
|
)
|
|
421
|
-
|
|
526
|
+
elif "_functions" not in self.__dict__ or len(self._functions) == 0:
|
|
422
527
|
raise NoABIFunctionsFound(
|
|
423
528
|
"The abi for this contract contains no function definitions. ",
|
|
424
529
|
"Are you sure you provided the correct contract abi?",
|
|
425
530
|
)
|
|
426
|
-
elif function_name not in
|
|
531
|
+
elif get_name_from_abi_element_identifier(function_name) not in [
|
|
532
|
+
get_name_from_abi_element_identifier(function["name"])
|
|
533
|
+
for function in self._functions
|
|
534
|
+
]:
|
|
427
535
|
raise ABIFunctionNotFound(
|
|
428
|
-
f"The function '{function_name}' was not found in this contract's
|
|
429
|
-
" Are you sure you provided the correct contract abi?",
|
|
536
|
+
f"The function '{function_name}' was not found in this contract's "
|
|
537
|
+
"abi. Are you sure you provided the correct contract abi?",
|
|
430
538
|
)
|
|
431
|
-
|
|
432
|
-
|
|
539
|
+
|
|
540
|
+
function_identifier = function_name
|
|
541
|
+
|
|
542
|
+
if "(" not in function_name:
|
|
543
|
+
function_identifier = _get_any_abi_signature_with_name(
|
|
544
|
+
function_name, self._functions
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
return super().__getattribute__(
|
|
548
|
+
function_identifier,
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
def __getitem__(self, function_name: str) -> "ContractFunction":
|
|
552
|
+
return getattr(self, function_name)
|
|
433
553
|
|
|
434
554
|
|
|
435
555
|
class Contract(BaseContract):
|
|
@@ -503,6 +623,16 @@ class Contract(BaseContract):
|
|
|
503
623
|
normalizers=normalizers,
|
|
504
624
|
),
|
|
505
625
|
)
|
|
626
|
+
|
|
627
|
+
if contract.abi:
|
|
628
|
+
for abi in contract.abi:
|
|
629
|
+
abi_name = abi.get("name")
|
|
630
|
+
if abi_name in ["abi", "address"]:
|
|
631
|
+
raise Web3AttributeError(
|
|
632
|
+
f"Contract contains a reserved word `{abi_name}` "
|
|
633
|
+
f"and could not be instantiated."
|
|
634
|
+
)
|
|
635
|
+
|
|
506
636
|
contract.functions = ContractFunctions(
|
|
507
637
|
contract.abi, contract.w3, decode_tuples=contract.decode_tuples
|
|
508
638
|
)
|
|
@@ -562,6 +692,24 @@ class Contract(BaseContract):
|
|
|
562
692
|
) -> "ContractFunction":
|
|
563
693
|
return get_function_by_identifier(fns, identifier)
|
|
564
694
|
|
|
695
|
+
@combomethod
|
|
696
|
+
def find_events_by_identifier(
|
|
697
|
+
cls,
|
|
698
|
+
contract_abi: ABI,
|
|
699
|
+
w3: "Web3",
|
|
700
|
+
address: ChecksumAddress,
|
|
701
|
+
callable_check: Callable[..., Any],
|
|
702
|
+
) -> List["ContractEvent"]:
|
|
703
|
+
return find_events_by_identifier(
|
|
704
|
+
contract_abi, w3, address, callable_check, ContractEvent
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
@combomethod
|
|
708
|
+
def get_event_by_identifier(
|
|
709
|
+
cls, events: Sequence["ContractEvent"], identifier: str
|
|
710
|
+
) -> "ContractEvent":
|
|
711
|
+
return get_event_by_identifier(events, identifier)
|
|
712
|
+
|
|
565
713
|
|
|
566
714
|
class ContractCaller(BaseContractCaller):
|
|
567
715
|
# mypy types
|
|
@@ -586,12 +734,12 @@ class ContractCaller(BaseContractCaller):
|
|
|
586
734
|
self._functions = get_all_function_abis(self.abi)
|
|
587
735
|
|
|
588
736
|
for func in self._functions:
|
|
737
|
+
abi_signature = abi_to_signature(func)
|
|
589
738
|
fn = ContractFunction.factory(
|
|
590
|
-
|
|
739
|
+
abi_signature,
|
|
591
740
|
w3=w3,
|
|
592
741
|
contract_abi=self.abi,
|
|
593
742
|
address=self.address,
|
|
594
|
-
abi_element_identifier=func["name"],
|
|
595
743
|
decode_tuples=decode_tuples,
|
|
596
744
|
)
|
|
597
745
|
|
|
@@ -603,7 +751,7 @@ class ContractCaller(BaseContractCaller):
|
|
|
603
751
|
ccip_read_enabled=ccip_read_enabled,
|
|
604
752
|
)
|
|
605
753
|
|
|
606
|
-
setattr(self,
|
|
754
|
+
setattr(self, abi_signature, caller_method)
|
|
607
755
|
|
|
608
756
|
def __call__(
|
|
609
757
|
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
|
)
|
|
@@ -63,6 +64,7 @@ from web3.types import (
|
|
|
63
64
|
BlockIdentifier,
|
|
64
65
|
RPCEndpoint,
|
|
65
66
|
StateOverride,
|
|
67
|
+
TContractEvent,
|
|
66
68
|
TContractFn,
|
|
67
69
|
TxParams,
|
|
68
70
|
)
|
|
@@ -338,14 +340,17 @@ def find_functions_by_identifier(
|
|
|
338
340
|
callable_check: Callable[..., Any],
|
|
339
341
|
function_type: Type[TContractFn],
|
|
340
342
|
) -> List[TContractFn]:
|
|
343
|
+
"""
|
|
344
|
+
Given a contract ABI, return a list of TContractFunction instances.
|
|
345
|
+
"""
|
|
341
346
|
fns_abi = filter_abi_by_type("function", contract_abi)
|
|
342
347
|
return [
|
|
343
348
|
function_type.factory(
|
|
344
|
-
fn_abi
|
|
349
|
+
abi_to_signature(fn_abi),
|
|
345
350
|
w3=w3,
|
|
346
351
|
contract_abi=contract_abi,
|
|
347
352
|
address=address,
|
|
348
|
-
abi_element_identifier=fn_abi
|
|
353
|
+
abi_element_identifier=abi_to_signature(fn_abi),
|
|
349
354
|
abi=fn_abi,
|
|
350
355
|
)
|
|
351
356
|
for fn_abi in fns_abi
|
|
@@ -356,6 +361,10 @@ def find_functions_by_identifier(
|
|
|
356
361
|
def get_function_by_identifier(
|
|
357
362
|
fns: Sequence[TContractFn], identifier: str
|
|
358
363
|
) -> TContractFn:
|
|
364
|
+
"""
|
|
365
|
+
Check that the provided list of TContractFunction instances contains one element and
|
|
366
|
+
return it.
|
|
367
|
+
"""
|
|
359
368
|
if len(fns) > 1:
|
|
360
369
|
raise Web3ValueError(
|
|
361
370
|
f"Found multiple functions with matching {identifier}. " f"Found: {fns!r}"
|
|
@@ -365,6 +374,46 @@ def get_function_by_identifier(
|
|
|
365
374
|
return fns[0]
|
|
366
375
|
|
|
367
376
|
|
|
377
|
+
def find_events_by_identifier(
|
|
378
|
+
contract_abi: ABI,
|
|
379
|
+
w3: Union["Web3", "AsyncWeb3"],
|
|
380
|
+
address: ChecksumAddress,
|
|
381
|
+
callable_check: Callable[..., Any],
|
|
382
|
+
event_type: Type[TContractEvent],
|
|
383
|
+
) -> List[TContractEvent]:
|
|
384
|
+
"""
|
|
385
|
+
Given a contract ABI, return a list of TContractEvent instances.
|
|
386
|
+
"""
|
|
387
|
+
event_abis = filter_abi_by_type("event", contract_abi)
|
|
388
|
+
return [
|
|
389
|
+
event_type.factory(
|
|
390
|
+
event_abi["name"],
|
|
391
|
+
w3=w3,
|
|
392
|
+
contract_abi=contract_abi,
|
|
393
|
+
address=address,
|
|
394
|
+
abi=event_abi,
|
|
395
|
+
)
|
|
396
|
+
for event_abi in event_abis
|
|
397
|
+
if callable_check(event_abi)
|
|
398
|
+
]
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def get_event_by_identifier(
|
|
402
|
+
events: Sequence[TContractEvent], identifier: str
|
|
403
|
+
) -> TContractEvent:
|
|
404
|
+
"""
|
|
405
|
+
Check that the provided list of TContractEvent instances contains one element and
|
|
406
|
+
return it.
|
|
407
|
+
"""
|
|
408
|
+
if len(events) > 1:
|
|
409
|
+
raise Web3ValueError(
|
|
410
|
+
f"Found multiple events with matching {identifier}. " f"Found: {events!r}"
|
|
411
|
+
)
|
|
412
|
+
elif len(events) == 0:
|
|
413
|
+
raise Web3ValueError(f"Could not find any event with matching {identifier}")
|
|
414
|
+
return events[0]
|
|
415
|
+
|
|
416
|
+
|
|
368
417
|
# --- async --- #
|
|
369
418
|
|
|
370
419
|
|
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(
|
web3/geth.py
CHANGED
|
@@ -5,6 +5,7 @@ from typing import (
|
|
|
5
5
|
Optional,
|
|
6
6
|
Protocol,
|
|
7
7
|
Tuple,
|
|
8
|
+
Union,
|
|
8
9
|
)
|
|
9
10
|
|
|
10
11
|
from eth_typing.evm import (
|
|
@@ -22,12 +23,19 @@ from web3.module import (
|
|
|
22
23
|
Module,
|
|
23
24
|
)
|
|
24
25
|
from web3.types import (
|
|
26
|
+
CallTrace,
|
|
27
|
+
DiffModeTrace,
|
|
25
28
|
EnodeURI,
|
|
29
|
+
FourByteTrace,
|
|
26
30
|
NodeInfo,
|
|
31
|
+
OpcodeTrace,
|
|
27
32
|
Peer,
|
|
33
|
+
PrestateTrace,
|
|
34
|
+
TraceConfig,
|
|
28
35
|
TxPoolContent,
|
|
29
36
|
TxPoolInspect,
|
|
30
37
|
TxPoolStatus,
|
|
38
|
+
_Hash32,
|
|
31
39
|
)
|
|
32
40
|
|
|
33
41
|
|
|
@@ -133,9 +141,33 @@ class GethAdmin(Module):
|
|
|
133
141
|
)
|
|
134
142
|
|
|
135
143
|
|
|
144
|
+
class GethDebug(Module):
|
|
145
|
+
"""
|
|
146
|
+
https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
def trace_transaction_munger(
|
|
150
|
+
self,
|
|
151
|
+
transaction_hash: _Hash32,
|
|
152
|
+
trace_config: Optional[TraceConfig] = None,
|
|
153
|
+
) -> Tuple[_Hash32, TraceConfig]:
|
|
154
|
+
return (transaction_hash, trace_config)
|
|
155
|
+
|
|
156
|
+
trace_transaction: Method[
|
|
157
|
+
Callable[
|
|
158
|
+
...,
|
|
159
|
+
Union[CallTrace, PrestateTrace, OpcodeTrace, DiffModeTrace, FourByteTrace],
|
|
160
|
+
]
|
|
161
|
+
] = Method(
|
|
162
|
+
RPC.debug_traceTransaction,
|
|
163
|
+
mungers=[trace_transaction_munger],
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
136
167
|
class Geth(Module):
|
|
137
168
|
admin: GethAdmin
|
|
138
169
|
txpool: GethTxPool
|
|
170
|
+
debug: GethDebug
|
|
139
171
|
|
|
140
172
|
|
|
141
173
|
# --- async --- #
|
|
@@ -261,8 +293,35 @@ class AsyncGethAdmin(Module):
|
|
|
261
293
|
return await self._stop_ws()
|
|
262
294
|
|
|
263
295
|
|
|
296
|
+
class AsyncGethDebug(Module):
|
|
297
|
+
"""
|
|
298
|
+
https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
is_async = True
|
|
302
|
+
|
|
303
|
+
_trace_transaction: Method[
|
|
304
|
+
Callable[
|
|
305
|
+
...,
|
|
306
|
+
Awaitable[
|
|
307
|
+
Union[
|
|
308
|
+
CallTrace, PrestateTrace, OpcodeTrace, FourByteTrace, DiffModeTrace
|
|
309
|
+
]
|
|
310
|
+
],
|
|
311
|
+
]
|
|
312
|
+
] = Method(RPC.debug_traceTransaction)
|
|
313
|
+
|
|
314
|
+
async def trace_transaction(
|
|
315
|
+
self,
|
|
316
|
+
transaction_hash: _Hash32,
|
|
317
|
+
trace_config: Optional[TraceConfig] = None,
|
|
318
|
+
) -> Union[CallTrace, PrestateTrace, OpcodeTrace, FourByteTrace, DiffModeTrace]:
|
|
319
|
+
return await self._trace_transaction(transaction_hash, trace_config)
|
|
320
|
+
|
|
321
|
+
|
|
264
322
|
class AsyncGeth(Module):
|
|
265
323
|
is_async = True
|
|
266
324
|
|
|
267
325
|
admin: AsyncGethAdmin
|
|
268
326
|
txpool: AsyncGethTxPool
|
|
327
|
+
debug: AsyncGethDebug
|
web3/main.py
CHANGED
|
@@ -93,9 +93,11 @@ from web3.exceptions import (
|
|
|
93
93
|
from web3.geth import (
|
|
94
94
|
AsyncGeth,
|
|
95
95
|
AsyncGethAdmin,
|
|
96
|
+
AsyncGethDebug,
|
|
96
97
|
AsyncGethTxPool,
|
|
97
98
|
Geth,
|
|
98
99
|
GethAdmin,
|
|
100
|
+
GethDebug,
|
|
99
101
|
GethTxPool,
|
|
100
102
|
)
|
|
101
103
|
from web3.manager import (
|
|
@@ -162,6 +164,7 @@ def get_async_default_modules() -> Dict[str, Union[Type[Module], Sequence[Any]]]
|
|
|
162
164
|
{
|
|
163
165
|
"admin": AsyncGethAdmin,
|
|
164
166
|
"txpool": AsyncGethTxPool,
|
|
167
|
+
"debug": AsyncGethDebug,
|
|
165
168
|
},
|
|
166
169
|
),
|
|
167
170
|
}
|
|
@@ -176,6 +179,7 @@ def get_default_modules() -> Dict[str, Union[Type[Module], Sequence[Any]]]:
|
|
|
176
179
|
{
|
|
177
180
|
"admin": GethAdmin,
|
|
178
181
|
"txpool": GethTxPool,
|
|
182
|
+
"debug": GethDebug,
|
|
179
183
|
},
|
|
180
184
|
),
|
|
181
185
|
"tracing": Tracing,
|
web3/manager.py
CHANGED
|
@@ -39,6 +39,7 @@ from web3.exceptions import (
|
|
|
39
39
|
ProviderConnectionError,
|
|
40
40
|
RequestTimedOut,
|
|
41
41
|
TaskNotRunning,
|
|
42
|
+
TransactionNotFound,
|
|
42
43
|
Web3RPCError,
|
|
43
44
|
Web3TypeError,
|
|
44
45
|
)
|
|
@@ -150,6 +151,7 @@ def _validate_response(
|
|
|
150
151
|
error_formatters: Optional[Callable[..., Any]],
|
|
151
152
|
is_subscription_response: bool = False,
|
|
152
153
|
logger: Optional[logging.Logger] = None,
|
|
154
|
+
params: Optional[Any] = None,
|
|
153
155
|
) -> None:
|
|
154
156
|
if "jsonrpc" not in response or response["jsonrpc"] != "2.0":
|
|
155
157
|
_raise_bad_response_format(
|
|
@@ -210,6 +212,13 @@ def _validate_response(
|
|
|
210
212
|
_raise_bad_response_format(
|
|
211
213
|
response, 'error["message"] is required and must be a string value.'
|
|
212
214
|
)
|
|
215
|
+
elif error_message == "transaction not found":
|
|
216
|
+
transaction_hash = params[0]
|
|
217
|
+
web3_rpc_error = TransactionNotFound(
|
|
218
|
+
repr(error),
|
|
219
|
+
rpc_response=response,
|
|
220
|
+
user_message=(f"Transaction with hash {transaction_hash!r} not found."),
|
|
221
|
+
)
|
|
213
222
|
|
|
214
223
|
# errors must include an integer code
|
|
215
224
|
code = error.get("code")
|
|
@@ -360,6 +369,7 @@ class RequestManager:
|
|
|
360
369
|
error_formatters,
|
|
361
370
|
is_subscription_response=is_subscription_response,
|
|
362
371
|
logger=self.logger,
|
|
372
|
+
params=params,
|
|
363
373
|
)
|
|
364
374
|
|
|
365
375
|
# format results
|