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/base_contract.py
CHANGED
|
@@ -38,6 +38,8 @@ from eth_utils import (
|
|
|
38
38
|
get_normalized_abi_inputs,
|
|
39
39
|
is_list_like,
|
|
40
40
|
is_text,
|
|
41
|
+
keccak,
|
|
42
|
+
to_bytes,
|
|
41
43
|
to_tuple,
|
|
42
44
|
)
|
|
43
45
|
from hexbytes import (
|
|
@@ -46,7 +48,10 @@ from hexbytes import (
|
|
|
46
48
|
|
|
47
49
|
from web3._utils.abi import (
|
|
48
50
|
fallback_func_abi_exists,
|
|
51
|
+
filter_by_types,
|
|
49
52
|
find_constructor_abi_element_by_type,
|
|
53
|
+
get_abi_element_signature,
|
|
54
|
+
get_name_from_abi_element_identifier,
|
|
50
55
|
is_array_type,
|
|
51
56
|
receive_func_abi_exists,
|
|
52
57
|
)
|
|
@@ -66,6 +71,7 @@ from web3._utils.empty import (
|
|
|
66
71
|
empty,
|
|
67
72
|
)
|
|
68
73
|
from web3._utils.encoding import (
|
|
74
|
+
hexstr_if_str,
|
|
69
75
|
to_4byte_hex,
|
|
70
76
|
to_hex,
|
|
71
77
|
)
|
|
@@ -93,7 +99,6 @@ from web3.exceptions import (
|
|
|
93
99
|
InvalidEventABI,
|
|
94
100
|
LogTopicError,
|
|
95
101
|
MismatchedABI,
|
|
96
|
-
NoABIEventsFound,
|
|
97
102
|
NoABIFound,
|
|
98
103
|
NoABIFunctionsFound,
|
|
99
104
|
Web3AttributeError,
|
|
@@ -118,10 +123,10 @@ from web3.types import (
|
|
|
118
123
|
TxReceipt,
|
|
119
124
|
)
|
|
120
125
|
from web3.utils.abi import (
|
|
126
|
+
_get_any_abi_signature_with_name,
|
|
121
127
|
check_if_arguments_can_be_encoded,
|
|
122
128
|
get_abi_element,
|
|
123
129
|
get_abi_element_info,
|
|
124
|
-
get_event_abi,
|
|
125
130
|
)
|
|
126
131
|
|
|
127
132
|
if TYPE_CHECKING:
|
|
@@ -130,8 +135,14 @@ if TYPE_CHECKING:
|
|
|
130
135
|
Web3,
|
|
131
136
|
)
|
|
132
137
|
|
|
133
|
-
from .async_contract import
|
|
134
|
-
|
|
138
|
+
from .async_contract import ( # noqa: F401
|
|
139
|
+
AsyncContractEvent,
|
|
140
|
+
AsyncContractFunction,
|
|
141
|
+
)
|
|
142
|
+
from .contract import ( # noqa: F401
|
|
143
|
+
ContractEvent,
|
|
144
|
+
ContractFunction,
|
|
145
|
+
)
|
|
135
146
|
|
|
136
147
|
|
|
137
148
|
class BaseContractEvent:
|
|
@@ -144,29 +155,56 @@ class BaseContractEvent:
|
|
|
144
155
|
|
|
145
156
|
address: ChecksumAddress = None
|
|
146
157
|
event_name: str = None
|
|
158
|
+
abi_element_identifier: ABIElementIdentifier = None
|
|
147
159
|
w3: Union["Web3", "AsyncWeb3"] = None
|
|
148
160
|
contract_abi: ABI = None
|
|
149
161
|
abi: ABIEvent = None
|
|
162
|
+
argument_types: Tuple[str] = None
|
|
163
|
+
args: Any = None
|
|
164
|
+
kwargs: Any = None
|
|
150
165
|
|
|
151
166
|
def __init__(self, *argument_names: Tuple[str]) -> None:
|
|
167
|
+
self.event_name = get_name_from_abi_element_identifier(type(self).__name__)
|
|
168
|
+
self.abi_element_identifier = type(self).__name__
|
|
169
|
+
abi = self._get_event_abi()
|
|
170
|
+
self.name = abi_to_signature(abi)
|
|
171
|
+
self.abi = abi
|
|
172
|
+
|
|
152
173
|
if argument_names is None:
|
|
153
174
|
# https://github.com/python/mypy/issues/6283
|
|
154
175
|
self.argument_names = tuple() # type: ignore
|
|
155
176
|
else:
|
|
156
177
|
self.argument_names = argument_names
|
|
157
178
|
|
|
158
|
-
|
|
179
|
+
def __repr__(self) -> str:
|
|
180
|
+
if self.abi:
|
|
181
|
+
return f"<Event {abi_to_signature(self.abi)}>"
|
|
182
|
+
return f"<Event {get_abi_element_signature(self.abi_element_identifier)}>"
|
|
159
183
|
|
|
160
|
-
@
|
|
184
|
+
@combomethod
|
|
161
185
|
def _get_event_abi(cls) -> ABIEvent:
|
|
162
|
-
|
|
186
|
+
if cls.abi:
|
|
187
|
+
return cls.abi
|
|
188
|
+
|
|
189
|
+
return cast(
|
|
190
|
+
ABIEvent,
|
|
191
|
+
get_abi_element(
|
|
192
|
+
filter_abi_by_type("event", cls.contract_abi),
|
|
193
|
+
cls.abi_element_identifier,
|
|
194
|
+
abi_codec=cls.w3.codec,
|
|
195
|
+
),
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
def _set_event_info(self) -> None:
|
|
199
|
+
self.abi = self._get_event_abi()
|
|
163
200
|
|
|
164
201
|
@combomethod
|
|
165
202
|
def process_receipt(
|
|
166
203
|
self, txn_receipt: TxReceipt, errors: EventLogErrorFlags = WARN
|
|
167
204
|
) -> Iterable[EventData]:
|
|
168
|
-
return self._parse_logs(txn_receipt, errors)
|
|
205
|
+
return self._parse_logs(txn_receipt=txn_receipt, errors=errors)
|
|
169
206
|
|
|
207
|
+
@combomethod
|
|
170
208
|
@to_tuple
|
|
171
209
|
def _parse_logs(
|
|
172
210
|
self, txn_receipt: TxReceipt, errors: EventLogErrorFlags
|
|
@@ -258,8 +296,10 @@ class BaseContractEvent:
|
|
|
258
296
|
return event_filter_params
|
|
259
297
|
|
|
260
298
|
@classmethod
|
|
261
|
-
def factory(
|
|
262
|
-
|
|
299
|
+
def factory(
|
|
300
|
+
cls, class_name: str, **kwargs: Any
|
|
301
|
+
) -> Union["ContractEvent", "AsyncContractEvent"]:
|
|
302
|
+
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
263
303
|
|
|
264
304
|
@staticmethod
|
|
265
305
|
def check_for_forbidden_api_filter_arguments(
|
|
@@ -349,12 +389,10 @@ class BaseContractEvent:
|
|
|
349
389
|
|
|
350
390
|
_filters = dict(**argument_filters)
|
|
351
391
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
self.check_for_forbidden_api_filter_arguments(event_abi, _filters)
|
|
392
|
+
self.check_for_forbidden_api_filter_arguments(self.abi, _filters)
|
|
355
393
|
|
|
356
394
|
_, event_filter_params = construct_event_filter_params(
|
|
357
|
-
self.
|
|
395
|
+
self.abi,
|
|
358
396
|
self.w3.codec,
|
|
359
397
|
contract_address=self.address,
|
|
360
398
|
argument_filters=_filters,
|
|
@@ -414,50 +452,29 @@ class BaseContractEvents:
|
|
|
414
452
|
self,
|
|
415
453
|
abi: ABI,
|
|
416
454
|
w3: Union["Web3", "AsyncWeb3"],
|
|
417
|
-
contract_event_type: Type["
|
|
455
|
+
contract_event_type: Union[Type["ContractEvent"], Type["AsyncContractEvent"]],
|
|
418
456
|
address: Optional[ChecksumAddress] = None,
|
|
419
457
|
) -> None:
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
setattr(
|
|
425
|
-
self,
|
|
426
|
-
event["name"],
|
|
427
|
-
contract_event_type.factory(
|
|
428
|
-
event["name"],
|
|
429
|
-
w3=w3,
|
|
430
|
-
contract_abi=self.abi,
|
|
431
|
-
address=address,
|
|
432
|
-
event_name=event["name"],
|
|
433
|
-
),
|
|
434
|
-
)
|
|
435
|
-
|
|
436
|
-
def __getattr__(self, event_name: str) -> Type["BaseContractEvent"]:
|
|
437
|
-
if "_events" not in self.__dict__:
|
|
438
|
-
raise NoABIEventsFound(
|
|
439
|
-
"The abi for this contract contains no event definitions. ",
|
|
440
|
-
"Are you sure you provided the correct contract abi?",
|
|
441
|
-
)
|
|
442
|
-
elif event_name not in self.__dict__["_events"]:
|
|
443
|
-
raise ABIEventNotFound(
|
|
444
|
-
f"The event '{event_name}' was not found in this contract's abi. ",
|
|
445
|
-
"Are you sure you provided the correct contract abi?",
|
|
446
|
-
)
|
|
447
|
-
else:
|
|
448
|
-
return super().__getattribute__(event_name)
|
|
449
|
-
|
|
450
|
-
def __getitem__(self, event_name: str) -> Type["BaseContractEvent"]:
|
|
451
|
-
return getattr(self, event_name)
|
|
458
|
+
self.abi = abi
|
|
459
|
+
self.w3 = w3
|
|
460
|
+
self.address = address
|
|
461
|
+
_events: Sequence[ABIEvent] = None
|
|
452
462
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
463
|
+
if self.abi:
|
|
464
|
+
_events = filter_abi_by_type("event", abi)
|
|
465
|
+
for event in _events:
|
|
466
|
+
abi_signature = abi_to_signature(event)
|
|
467
|
+
event_factory = contract_event_type.factory(
|
|
468
|
+
abi_signature,
|
|
469
|
+
w3=self.w3,
|
|
470
|
+
contract_abi=self.abi,
|
|
471
|
+
address=self.address,
|
|
472
|
+
event_name=event["name"],
|
|
473
|
+
)
|
|
474
|
+
setattr(self, abi_signature, event_factory)
|
|
456
475
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
for event in self._events:
|
|
460
|
-
yield self[event["name"]]
|
|
476
|
+
if _events:
|
|
477
|
+
self._events = _events
|
|
461
478
|
|
|
462
479
|
def __hasattr__(self, event_name: str) -> bool:
|
|
463
480
|
try:
|
|
@@ -475,52 +492,80 @@ class BaseContractFunction:
|
|
|
475
492
|
"""
|
|
476
493
|
|
|
477
494
|
address: ChecksumAddress = None
|
|
495
|
+
fn_name: str = None
|
|
496
|
+
name: str = None
|
|
478
497
|
abi_element_identifier: ABIElementIdentifier = None
|
|
479
498
|
w3: Union["Web3", "AsyncWeb3"] = None
|
|
480
499
|
contract_abi: ABI = None
|
|
481
500
|
abi: ABIFunction = None
|
|
482
501
|
transaction: TxParams = None
|
|
483
502
|
arguments: Tuple[Any, ...] = None
|
|
484
|
-
decode_tuples: Optional[bool] =
|
|
503
|
+
decode_tuples: Optional[bool] = None
|
|
485
504
|
args: Any = None
|
|
486
505
|
kwargs: Any = None
|
|
487
506
|
|
|
488
507
|
def __init__(self, abi: Optional[ABIFunction] = None) -> None:
|
|
489
|
-
self.
|
|
490
|
-
|
|
508
|
+
if not self.abi_element_identifier:
|
|
509
|
+
self.abi_element_identifier = type(self).__name__
|
|
510
|
+
|
|
511
|
+
self.fn_name = get_name_from_abi_element_identifier(self.abi_element_identifier)
|
|
512
|
+
self.abi = cast(
|
|
513
|
+
ABIFunction,
|
|
514
|
+
get_abi_element(
|
|
515
|
+
filter_by_types(
|
|
516
|
+
["function", "constructor", "fallback", "receive"],
|
|
517
|
+
self.contract_abi,
|
|
518
|
+
),
|
|
519
|
+
self.abi_element_identifier,
|
|
520
|
+
),
|
|
521
|
+
)
|
|
522
|
+
self.name = abi_to_signature(self.abi)
|
|
491
523
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
524
|
+
@combomethod
|
|
525
|
+
def _get_abi(cls) -> ABIFunction:
|
|
526
|
+
if not cls.args and not cls.kwargs:
|
|
527
|
+
# If no args or kwargs are provided, get the ABI element by name
|
|
528
|
+
return cast(
|
|
495
529
|
ABIFunction,
|
|
496
530
|
get_abi_element(
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
abi_codec=self.w3.codec,
|
|
501
|
-
**self.kwargs,
|
|
531
|
+
cls.contract_abi,
|
|
532
|
+
get_abi_element_signature(cls.abi_element_identifier),
|
|
533
|
+
abi_codec=cls.w3.codec,
|
|
502
534
|
),
|
|
503
535
|
)
|
|
504
536
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
537
|
+
return cast(
|
|
538
|
+
ABIFunction,
|
|
539
|
+
get_abi_element(
|
|
540
|
+
cls.contract_abi,
|
|
541
|
+
get_name_from_abi_element_identifier(cls.abi_element_identifier),
|
|
542
|
+
*cls.args,
|
|
543
|
+
abi_codec=cls.w3.codec,
|
|
544
|
+
**cls.kwargs,
|
|
545
|
+
),
|
|
546
|
+
)
|
|
514
547
|
|
|
548
|
+
def _set_function_info(self) -> None:
|
|
549
|
+
self.selector = encode_hex(b"")
|
|
515
550
|
if self.abi_element_identifier in [
|
|
551
|
+
"fallback",
|
|
552
|
+
"receive",
|
|
516
553
|
FallbackFn,
|
|
517
554
|
ReceiveFn,
|
|
518
555
|
]:
|
|
556
|
+
self.abi = self._get_abi()
|
|
557
|
+
|
|
558
|
+
self.selector = encode_hex(function_abi_to_4byte_selector(self.abi))
|
|
519
559
|
self.arguments = None
|
|
520
|
-
|
|
560
|
+
elif is_text(self.abi_element_identifier):
|
|
561
|
+
self.abi = self._get_abi()
|
|
562
|
+
|
|
563
|
+
self.selector = encode_hex(function_abi_to_4byte_selector(self.abi))
|
|
521
564
|
self.arguments = get_normalized_abi_inputs(
|
|
522
565
|
self.abi, *self.args, **self.kwargs
|
|
523
566
|
)
|
|
567
|
+
else:
|
|
568
|
+
raise Web3TypeError("Unsupported function identifier")
|
|
524
569
|
|
|
525
570
|
def _get_call_txparams(self, transaction: Optional[TxParams] = None) -> TxParams:
|
|
526
571
|
if transaction is None:
|
|
@@ -652,18 +697,20 @@ class BaseContractFunction:
|
|
|
652
697
|
if self.arguments is not None:
|
|
653
698
|
_repr += f" bound to {self.arguments!r}"
|
|
654
699
|
return _repr + ">"
|
|
655
|
-
return f"<Function {self.
|
|
700
|
+
return f"<Function {get_abi_element_signature(self.abi_element_identifier)}>"
|
|
656
701
|
|
|
657
702
|
@classmethod
|
|
658
703
|
def factory(
|
|
659
704
|
cls, class_name: str, **kwargs: Any
|
|
660
705
|
) -> Union["ContractFunction", "AsyncContractFunction"]:
|
|
661
|
-
return PropertyCheckingFactory(class_name, (cls,), kwargs)(
|
|
706
|
+
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
662
707
|
|
|
663
708
|
|
|
664
709
|
class BaseContractFunctions:
|
|
665
710
|
"""Class containing contract function objects"""
|
|
666
711
|
|
|
712
|
+
_functions: Sequence[ABIFunction] = None
|
|
713
|
+
|
|
667
714
|
def __init__(
|
|
668
715
|
self,
|
|
669
716
|
abi: ABI,
|
|
@@ -677,32 +724,26 @@ class BaseContractFunctions:
|
|
|
677
724
|
self.abi = abi
|
|
678
725
|
self.w3 = w3
|
|
679
726
|
self.address = address
|
|
727
|
+
_functions: Sequence[ABIFunction] = None
|
|
680
728
|
|
|
681
729
|
if self.abi:
|
|
682
|
-
|
|
683
|
-
for func in
|
|
730
|
+
_functions = filter_abi_by_type("function", self.abi)
|
|
731
|
+
for func in _functions:
|
|
732
|
+
abi_signature = abi_to_signature(func)
|
|
684
733
|
setattr(
|
|
685
734
|
self,
|
|
686
|
-
|
|
735
|
+
abi_signature,
|
|
687
736
|
contract_function_class.factory(
|
|
688
|
-
|
|
737
|
+
abi_signature,
|
|
689
738
|
w3=self.w3,
|
|
690
739
|
contract_abi=self.abi,
|
|
691
740
|
address=self.address,
|
|
692
741
|
decode_tuples=decode_tuples,
|
|
693
|
-
abi_element_identifier=func["name"],
|
|
694
742
|
),
|
|
695
743
|
)
|
|
696
744
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
return
|
|
700
|
-
|
|
701
|
-
for func in self._functions:
|
|
702
|
-
yield self[func["name"]]
|
|
703
|
-
|
|
704
|
-
def __getitem__(self, function_name: str) -> ABIFunction:
|
|
705
|
-
return getattr(self, function_name)
|
|
745
|
+
if _functions:
|
|
746
|
+
self._functions = _functions
|
|
706
747
|
|
|
707
748
|
def __hasattr__(self, function_name: str) -> bool:
|
|
708
749
|
try:
|
|
@@ -766,7 +807,7 @@ class BaseContract:
|
|
|
766
807
|
) -> HexStr:
|
|
767
808
|
"""
|
|
768
809
|
Encodes the arguments using the Ethereum ABI for the contract function
|
|
769
|
-
that matches the given name and arguments
|
|
810
|
+
that matches the given name and arguments.
|
|
770
811
|
|
|
771
812
|
:param data: defaults to function selector
|
|
772
813
|
"""
|
|
@@ -786,16 +827,27 @@ class BaseContract:
|
|
|
786
827
|
|
|
787
828
|
return encode_abi(cls.w3, element_info["abi"], element_info["arguments"], data)
|
|
788
829
|
|
|
830
|
+
#
|
|
831
|
+
# Functions API
|
|
832
|
+
#
|
|
789
833
|
@combomethod
|
|
790
834
|
def all_functions(
|
|
791
835
|
self,
|
|
792
|
-
) -> "BaseContractFunction":
|
|
836
|
+
) -> List["BaseContractFunction"]:
|
|
837
|
+
"""
|
|
838
|
+
Return all functions in the contract.
|
|
839
|
+
"""
|
|
793
840
|
return self.find_functions_by_identifier(
|
|
794
841
|
self.abi, self.w3, self.address, lambda _: True
|
|
795
842
|
)
|
|
796
843
|
|
|
797
844
|
@combomethod
|
|
798
845
|
def get_function_by_signature(self, signature: str) -> "BaseContractFunction":
|
|
846
|
+
"""
|
|
847
|
+
Return a distinct function with matching signature.
|
|
848
|
+
Raises a Web3ValueError if the signature is invalid or if there is no match or
|
|
849
|
+
more than one is found.
|
|
850
|
+
"""
|
|
799
851
|
if " " in signature:
|
|
800
852
|
raise Web3ValueError(
|
|
801
853
|
"Function signature should not contain any spaces. "
|
|
@@ -811,7 +863,12 @@ class BaseContract:
|
|
|
811
863
|
return self.get_function_by_identifier(fns, "signature")
|
|
812
864
|
|
|
813
865
|
@combomethod
|
|
814
|
-
def find_functions_by_name(self, fn_name: str) -> "BaseContractFunction":
|
|
866
|
+
def find_functions_by_name(self, fn_name: str) -> List["BaseContractFunction"]:
|
|
867
|
+
"""
|
|
868
|
+
Return all functions with matching name.
|
|
869
|
+
Raises a Web3ValueError if there is no match or more than one is found.
|
|
870
|
+
"""
|
|
871
|
+
|
|
815
872
|
def callable_check(fn_abi: ABIFunction) -> bool:
|
|
816
873
|
return fn_abi["name"] == fn_name
|
|
817
874
|
|
|
@@ -821,6 +878,10 @@ class BaseContract:
|
|
|
821
878
|
|
|
822
879
|
@combomethod
|
|
823
880
|
def get_function_by_name(self, fn_name: str) -> "BaseContractFunction":
|
|
881
|
+
"""
|
|
882
|
+
Return a distinct function with matching name.
|
|
883
|
+
Raises a Web3ValueError if there is no match or more than one is found.
|
|
884
|
+
"""
|
|
824
885
|
fns = self.find_functions_by_name(fn_name)
|
|
825
886
|
return self.get_function_by_identifier(fns, "name")
|
|
826
887
|
|
|
@@ -828,6 +889,11 @@ class BaseContract:
|
|
|
828
889
|
def get_function_by_selector(
|
|
829
890
|
self, selector: Union[bytes, int, HexStr]
|
|
830
891
|
) -> "BaseContractFunction":
|
|
892
|
+
"""
|
|
893
|
+
Return a distinct function with matching 4byte selector.
|
|
894
|
+
Raises a Web3ValueError if there is no match or more than one is found.
|
|
895
|
+
"""
|
|
896
|
+
|
|
831
897
|
def callable_check(fn_abi: ABIFunction) -> bool:
|
|
832
898
|
return encode_hex(function_abi_to_4byte_selector(fn_abi)) == to_4byte_hex(
|
|
833
899
|
selector
|
|
@@ -842,6 +908,9 @@ class BaseContract:
|
|
|
842
908
|
def decode_function_input(
|
|
843
909
|
self, data: HexStr
|
|
844
910
|
) -> Tuple["BaseContractFunction", Dict[str, Any]]:
|
|
911
|
+
"""
|
|
912
|
+
Return a Tuple of the function selector and decoded arguments.
|
|
913
|
+
"""
|
|
845
914
|
func = self.get_function_by_selector(HexBytes(data)[:4])
|
|
846
915
|
arguments = decode_transaction_data(
|
|
847
916
|
func.abi, data, normalizers=BASE_RETURN_NORMALIZERS
|
|
@@ -850,6 +919,11 @@ class BaseContract:
|
|
|
850
919
|
|
|
851
920
|
@combomethod
|
|
852
921
|
def find_functions_by_args(self, *args: Any) -> "BaseContractFunction":
|
|
922
|
+
"""
|
|
923
|
+
Return all functions with matching args, checking each argument can be encoded
|
|
924
|
+
with the type.
|
|
925
|
+
"""
|
|
926
|
+
|
|
853
927
|
def callable_check(fn_abi: ABIFunction) -> bool:
|
|
854
928
|
return check_if_arguments_can_be_encoded(
|
|
855
929
|
fn_abi,
|
|
@@ -864,77 +938,119 @@ class BaseContract:
|
|
|
864
938
|
|
|
865
939
|
@combomethod
|
|
866
940
|
def get_function_by_args(self, *args: Any) -> "BaseContractFunction":
|
|
941
|
+
"""
|
|
942
|
+
Return a distinct function with matching args, checking each argument can be
|
|
943
|
+
encoded with the type.
|
|
944
|
+
Raises a Web3ValueError if there is no match or more than one is found.
|
|
945
|
+
"""
|
|
867
946
|
fns = self.find_functions_by_args(*args)
|
|
868
947
|
return self.get_function_by_identifier(fns, "args")
|
|
869
948
|
|
|
870
949
|
#
|
|
871
|
-
#
|
|
950
|
+
# Events API
|
|
872
951
|
#
|
|
873
|
-
|
|
952
|
+
@combomethod
|
|
953
|
+
def all_events(self) -> List["BaseContractEvent"]:
|
|
954
|
+
"""
|
|
955
|
+
Return all events in the contract.
|
|
956
|
+
"""
|
|
957
|
+
return self.find_events_by_identifier(
|
|
958
|
+
self.abi, self.w3, self.address, lambda _: True
|
|
959
|
+
)
|
|
874
960
|
|
|
875
|
-
@
|
|
876
|
-
def
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
transaction=transaction,
|
|
889
|
-
fn_args=fn_args,
|
|
890
|
-
fn_kwargs=fn_kwargs,
|
|
961
|
+
@combomethod
|
|
962
|
+
def get_event_by_signature(self, signature: str) -> "BaseContractEvent":
|
|
963
|
+
"""
|
|
964
|
+
Return a distinct event with matching signature.
|
|
965
|
+
Raises a Web3ValueError if the signature is invalid or if there is no match or
|
|
966
|
+
more than one is found.
|
|
967
|
+
"""
|
|
968
|
+
|
|
969
|
+
def callable_check(event_abi: ABIEvent) -> bool:
|
|
970
|
+
return abi_to_signature(event_abi) == signature.replace(" ", "")
|
|
971
|
+
|
|
972
|
+
events = self.find_events_by_identifier(
|
|
973
|
+
self.abi, self.w3, self.address, callable_check
|
|
891
974
|
)
|
|
975
|
+
return self.get_event_by_identifier(events, "signature")
|
|
892
976
|
|
|
893
|
-
@
|
|
894
|
-
def
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
**kwargs,
|
|
977
|
+
@combomethod
|
|
978
|
+
def find_events_by_name(self, event_name: str) -> List["BaseContractEvent"]:
|
|
979
|
+
"""
|
|
980
|
+
Return all events with matching name.
|
|
981
|
+
Raises a Web3ValueError if there is no match or more than one is found.
|
|
982
|
+
"""
|
|
983
|
+
|
|
984
|
+
def callable_check(fn_abi: ABIFunction) -> bool:
|
|
985
|
+
return fn_abi["name"] == event_name
|
|
986
|
+
|
|
987
|
+
return self.find_events_by_identifier(
|
|
988
|
+
self.abi, self.w3, self.address, callable_check
|
|
906
989
|
)
|
|
907
990
|
|
|
908
|
-
@
|
|
909
|
-
def
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
991
|
+
@combomethod
|
|
992
|
+
def get_event_by_name(self, event_name: str) -> "BaseContractEvent":
|
|
993
|
+
"""
|
|
994
|
+
Return a distinct event with matching name.
|
|
995
|
+
Raises a Web3ValueError if there is no match or more than one is found.
|
|
996
|
+
"""
|
|
997
|
+
events = self.find_events_by_name(event_name)
|
|
998
|
+
return self.get_event_by_identifier(events, "name")
|
|
999
|
+
|
|
1000
|
+
@combomethod
|
|
1001
|
+
def find_events_by_selector(
|
|
1002
|
+
self, selector: Union[bytes, int, HexStr]
|
|
1003
|
+
) -> List["BaseContractEvent"]:
|
|
1004
|
+
"""
|
|
1005
|
+
Return all events with matching selector.
|
|
1006
|
+
Raises a Web3ValueError if there is no match or more than one is found.
|
|
1007
|
+
"""
|
|
1008
|
+
|
|
1009
|
+
def callable_check(event_abi: ABIEvent) -> bool:
|
|
1010
|
+
return encode_hex(
|
|
1011
|
+
keccak(text=abi_to_signature(event_abi).replace(" ", ""))
|
|
1012
|
+
) == encode_hex(hexstr_if_str(to_bytes, selector))
|
|
1013
|
+
|
|
1014
|
+
return self.find_events_by_identifier(
|
|
1015
|
+
self.abi, self.w3, self.address, callable_check
|
|
916
1016
|
)
|
|
917
1017
|
|
|
918
1018
|
@combomethod
|
|
919
|
-
def
|
|
920
|
-
|
|
921
|
-
) ->
|
|
922
|
-
|
|
1019
|
+
def get_event_by_selector(
|
|
1020
|
+
self, selector: Union[bytes, int, HexStr]
|
|
1021
|
+
) -> "BaseContractEvent":
|
|
1022
|
+
"""
|
|
1023
|
+
Return a distinct event with matching keccak selector.
|
|
1024
|
+
Raises a Web3ValueError if there is no match or more than one is found.
|
|
1025
|
+
"""
|
|
1026
|
+
events = self.find_events_by_selector(selector)
|
|
1027
|
+
return self.get_event_by_identifier(events, "selector")
|
|
923
1028
|
|
|
924
|
-
|
|
925
|
-
|
|
1029
|
+
@combomethod
|
|
1030
|
+
def find_events_by_topic(self, topic: HexStr) -> List["BaseContractEvent"]:
|
|
1031
|
+
"""
|
|
1032
|
+
Return all events with matching topic.
|
|
1033
|
+
Raises a Web3ValueError if there is no match or more than one is found.
|
|
1034
|
+
"""
|
|
926
1035
|
|
|
927
|
-
|
|
928
|
-
|
|
1036
|
+
def callable_check(event_abi: ABIEvent) -> bool:
|
|
1037
|
+
return (
|
|
1038
|
+
encode_hex(keccak(text=abi_to_signature(event_abi).replace(" ", "")))
|
|
1039
|
+
== topic
|
|
929
1040
|
)
|
|
930
|
-
else:
|
|
931
|
-
if args or kwargs:
|
|
932
|
-
msg = "Constructor args were provided, but no constructor function was provided." # noqa: E501
|
|
933
|
-
raise Web3TypeError(msg)
|
|
934
1041
|
|
|
935
|
-
|
|
1042
|
+
return self.find_events_by_identifier(
|
|
1043
|
+
self.abi, self.w3, self.address, callable_check
|
|
1044
|
+
)
|
|
936
1045
|
|
|
937
|
-
|
|
1046
|
+
@combomethod
|
|
1047
|
+
def get_event_by_topic(self, topic: HexStr) -> "BaseContractEvent":
|
|
1048
|
+
"""
|
|
1049
|
+
Return a distinct event with matching topic.
|
|
1050
|
+
Raises a Web3ValueError if there is no match or more than one is found.
|
|
1051
|
+
"""
|
|
1052
|
+
events = self.find_events_by_topic(topic)
|
|
1053
|
+
return self.get_event_by_identifier(events, "topic")
|
|
938
1054
|
|
|
939
1055
|
@combomethod
|
|
940
1056
|
def find_functions_by_identifier(
|
|
@@ -956,6 +1072,26 @@ class BaseContract:
|
|
|
956
1072
|
"This method should be implemented in the inherited class"
|
|
957
1073
|
)
|
|
958
1074
|
|
|
1075
|
+
@combomethod
|
|
1076
|
+
def find_events_by_identifier(
|
|
1077
|
+
cls,
|
|
1078
|
+
contract_abi: ABI,
|
|
1079
|
+
w3: Union["Web3", "AsyncWeb3"],
|
|
1080
|
+
address: ChecksumAddress,
|
|
1081
|
+
callable_check: Callable[..., Any],
|
|
1082
|
+
) -> List[Any]:
|
|
1083
|
+
raise NotImplementedError(
|
|
1084
|
+
"This method should be implemented in the inherited class"
|
|
1085
|
+
)
|
|
1086
|
+
|
|
1087
|
+
@combomethod
|
|
1088
|
+
def get_event_by_identifier(
|
|
1089
|
+
cls, fns: Sequence["BaseContractEvent"], identifier: str
|
|
1090
|
+
) -> "BaseContractEvent":
|
|
1091
|
+
raise NotImplementedError(
|
|
1092
|
+
"This method should be implemented in the inherited class"
|
|
1093
|
+
)
|
|
1094
|
+
|
|
959
1095
|
@staticmethod
|
|
960
1096
|
def get_fallback_function(
|
|
961
1097
|
abi: ABI,
|
|
@@ -992,6 +1128,83 @@ class BaseContract:
|
|
|
992
1128
|
|
|
993
1129
|
return cast(function_type, NonExistentReceiveFunction()) # type: ignore
|
|
994
1130
|
|
|
1131
|
+
#
|
|
1132
|
+
# Private Helpers
|
|
1133
|
+
#
|
|
1134
|
+
_return_data_normalizers: Tuple[Callable[..., Any], ...] = tuple()
|
|
1135
|
+
|
|
1136
|
+
@classmethod
|
|
1137
|
+
def _prepare_transaction(
|
|
1138
|
+
cls,
|
|
1139
|
+
abi_element_identifier: ABIElementIdentifier,
|
|
1140
|
+
fn_args: Optional[Any] = None,
|
|
1141
|
+
fn_kwargs: Optional[Any] = None,
|
|
1142
|
+
transaction: Optional[TxParams] = None,
|
|
1143
|
+
) -> TxParams:
|
|
1144
|
+
return prepare_transaction(
|
|
1145
|
+
cls.address,
|
|
1146
|
+
cls.w3,
|
|
1147
|
+
abi_element_identifier=abi_element_identifier,
|
|
1148
|
+
contract_abi=cls.abi,
|
|
1149
|
+
transaction=transaction,
|
|
1150
|
+
fn_args=fn_args,
|
|
1151
|
+
fn_kwargs=fn_kwargs,
|
|
1152
|
+
)
|
|
1153
|
+
|
|
1154
|
+
@classmethod
|
|
1155
|
+
def _find_matching_fn_abi(
|
|
1156
|
+
cls,
|
|
1157
|
+
fn_identifier: Optional[ABIElementIdentifier] = None,
|
|
1158
|
+
*args: Sequence[Any],
|
|
1159
|
+
**kwargs: Dict[str, Any],
|
|
1160
|
+
) -> ABIElement:
|
|
1161
|
+
if not args and not kwargs:
|
|
1162
|
+
fn_identifier = get_abi_element_signature(fn_identifier)
|
|
1163
|
+
|
|
1164
|
+
return get_abi_element(
|
|
1165
|
+
cls.abi,
|
|
1166
|
+
fn_identifier,
|
|
1167
|
+
*args,
|
|
1168
|
+
abi_codec=cls.w3.codec,
|
|
1169
|
+
**kwargs,
|
|
1170
|
+
)
|
|
1171
|
+
|
|
1172
|
+
@classmethod
|
|
1173
|
+
def _get_event_abi(
|
|
1174
|
+
cls,
|
|
1175
|
+
event_name: Optional[str] = None,
|
|
1176
|
+
argument_names: Optional[Sequence[str]] = None,
|
|
1177
|
+
) -> ABIEvent:
|
|
1178
|
+
return cast(
|
|
1179
|
+
ABIEvent,
|
|
1180
|
+
get_abi_element(
|
|
1181
|
+
abi=cls.abi,
|
|
1182
|
+
abi_element_identifier=event_name,
|
|
1183
|
+
argument_names=argument_names,
|
|
1184
|
+
),
|
|
1185
|
+
)
|
|
1186
|
+
|
|
1187
|
+
@combomethod
|
|
1188
|
+
def _encode_constructor_data(
|
|
1189
|
+
cls, *args: Sequence[Any], **kwargs: Dict[str, Any]
|
|
1190
|
+
) -> HexStr:
|
|
1191
|
+
constructor_abi = find_constructor_abi_element_by_type(cls.abi)
|
|
1192
|
+
|
|
1193
|
+
if constructor_abi:
|
|
1194
|
+
arguments = get_normalized_abi_inputs(constructor_abi, *args, **kwargs)
|
|
1195
|
+
|
|
1196
|
+
deploy_data = add_0x_prefix(
|
|
1197
|
+
encode_abi(cls.w3, constructor_abi, arguments, data=cls.bytecode)
|
|
1198
|
+
)
|
|
1199
|
+
else:
|
|
1200
|
+
if args or kwargs:
|
|
1201
|
+
msg = "Constructor args were provided, but no constructor function was provided." # noqa: E501
|
|
1202
|
+
raise Web3TypeError(msg)
|
|
1203
|
+
|
|
1204
|
+
deploy_data = to_hex(cls.bytecode)
|
|
1205
|
+
|
|
1206
|
+
return deploy_data
|
|
1207
|
+
|
|
995
1208
|
|
|
996
1209
|
class BaseContractCaller:
|
|
997
1210
|
"""
|
|
@@ -1034,7 +1247,9 @@ class BaseContractCaller:
|
|
|
1034
1247
|
|
|
1035
1248
|
def __getattr__(self, function_name: str) -> Any:
|
|
1036
1249
|
function_names = [
|
|
1037
|
-
fn["name"]
|
|
1250
|
+
get_name_from_abi_element_identifier(fn["name"])
|
|
1251
|
+
for fn in self._functions
|
|
1252
|
+
if fn.get("type") == "function"
|
|
1038
1253
|
]
|
|
1039
1254
|
if self.abi is None:
|
|
1040
1255
|
raise NoABIFound(
|
|
@@ -1045,7 +1260,7 @@ class BaseContractCaller:
|
|
|
1045
1260
|
"The ABI for this contract contains no function definitions. ",
|
|
1046
1261
|
"Are you sure you provided the correct contract ABI?",
|
|
1047
1262
|
)
|
|
1048
|
-
elif function_name not in function_names:
|
|
1263
|
+
elif get_name_from_abi_element_identifier(function_name) not in function_names:
|
|
1049
1264
|
functions_available = ", ".join(function_names)
|
|
1050
1265
|
raise ABIFunctionNotFound(
|
|
1051
1266
|
f"The function '{function_name}' was not found in this contract's ABI.",
|
|
@@ -1054,11 +1269,17 @@ class BaseContractCaller:
|
|
|
1054
1269
|
"Did you mean to call one of those functions?",
|
|
1055
1270
|
)
|
|
1056
1271
|
else:
|
|
1057
|
-
|
|
1272
|
+
function_identifier = function_name
|
|
1058
1273
|
|
|
1059
|
-
|
|
1274
|
+
if "(" not in function_name:
|
|
1275
|
+
function_identifier = _get_any_abi_signature_with_name(
|
|
1276
|
+
function_name, self._functions
|
|
1277
|
+
)
|
|
1278
|
+
return super().__getattribute__(function_identifier)
|
|
1279
|
+
|
|
1280
|
+
def __hasattr__(self, function_name: str) -> bool:
|
|
1060
1281
|
try:
|
|
1061
|
-
return
|
|
1282
|
+
return function_name in self.__dict__["_functions"]
|
|
1062
1283
|
except ABIFunctionNotFound:
|
|
1063
1284
|
return False
|
|
1064
1285
|
|