web3 7.6.1__py3-none-any.whl → 7.8.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.
- ens/async_ens.py +1 -1
- ens/ens.py +1 -1
- web3/_utils/caching/caching_utils.py +64 -0
- web3/_utils/caching/request_caching_validation.py +1 -0
- web3/_utils/events.py +1 -1
- web3/_utils/http_session_manager.py +32 -3
- web3/_utils/module_testing/eth_module.py +5 -18
- web3/_utils/module_testing/module_testing_utils.py +1 -43
- web3/_utils/module_testing/persistent_connection_provider.py +696 -207
- web3/_utils/module_testing/utils.py +99 -33
- web3/beacon/api_endpoints.py +10 -0
- web3/beacon/async_beacon.py +47 -0
- web3/beacon/beacon.py +45 -0
- web3/contract/async_contract.py +2 -206
- web3/contract/base_contract.py +217 -13
- web3/contract/contract.py +2 -205
- web3/datastructures.py +15 -16
- web3/eth/async_eth.py +23 -5
- web3/exceptions.py +7 -0
- web3/main.py +24 -3
- web3/manager.py +140 -48
- web3/method.py +1 -1
- web3/middleware/attrdict.py +12 -22
- web3/middleware/base.py +14 -6
- web3/module.py +17 -21
- web3/providers/async_base.py +23 -14
- web3/providers/base.py +6 -8
- web3/providers/ipc.py +7 -6
- web3/providers/legacy_websocket.py +1 -1
- web3/providers/persistent/async_ipc.py +5 -3
- web3/providers/persistent/persistent.py +121 -17
- web3/providers/persistent/persistent_connection.py +11 -4
- web3/providers/persistent/request_processor.py +49 -41
- web3/providers/persistent/subscription_container.py +56 -0
- web3/providers/persistent/subscription_manager.py +298 -0
- web3/providers/persistent/websocket.py +4 -4
- web3/providers/rpc/async_rpc.py +16 -3
- web3/providers/rpc/rpc.py +9 -5
- web3/types.py +28 -14
- web3/utils/__init__.py +4 -0
- web3/utils/subscriptions.py +289 -0
- {web3-7.6.1.dist-info → web3-7.8.0.dist-info}/LICENSE +1 -1
- {web3-7.6.1.dist-info → web3-7.8.0.dist-info}/METADATA +68 -56
- {web3-7.6.1.dist-info → web3-7.8.0.dist-info}/RECORD +46 -43
- {web3-7.6.1.dist-info → web3-7.8.0.dist-info}/WHEEL +1 -1
- {web3-7.6.1.dist-info → web3-7.8.0.dist-info}/top_level.txt +0 -0
web3/contract/base_contract.py
CHANGED
|
@@ -4,6 +4,7 @@ from typing import (
|
|
|
4
4
|
Callable,
|
|
5
5
|
Collection,
|
|
6
6
|
Dict,
|
|
7
|
+
Generic,
|
|
7
8
|
Iterable,
|
|
8
9
|
List,
|
|
9
10
|
NoReturn,
|
|
@@ -58,7 +59,12 @@ from web3._utils.abi_element_identifiers import (
|
|
|
58
59
|
FallbackFn,
|
|
59
60
|
ReceiveFn,
|
|
60
61
|
)
|
|
62
|
+
from web3._utils.compat import (
|
|
63
|
+
Self,
|
|
64
|
+
)
|
|
61
65
|
from web3._utils.contracts import (
|
|
66
|
+
copy_contract_event,
|
|
67
|
+
copy_contract_function,
|
|
62
68
|
decode_transaction_data,
|
|
63
69
|
encode_abi,
|
|
64
70
|
prepare_transaction,
|
|
@@ -98,6 +104,7 @@ from web3.exceptions import (
|
|
|
98
104
|
InvalidEventABI,
|
|
99
105
|
LogTopicError,
|
|
100
106
|
MismatchedABI,
|
|
107
|
+
NoABIEventsFound,
|
|
101
108
|
NoABIFound,
|
|
102
109
|
NoABIFunctionsFound,
|
|
103
110
|
Web3AttributeError,
|
|
@@ -117,12 +124,17 @@ from web3.types import (
|
|
|
117
124
|
BlockIdentifier,
|
|
118
125
|
EventData,
|
|
119
126
|
FilterParams,
|
|
127
|
+
LogReceipt,
|
|
128
|
+
StateOverride,
|
|
129
|
+
TContractEvent,
|
|
120
130
|
TContractFn,
|
|
121
131
|
TxParams,
|
|
122
132
|
TxReceipt,
|
|
123
133
|
)
|
|
124
134
|
from web3.utils.abi import (
|
|
135
|
+
_filter_by_argument_count,
|
|
125
136
|
_get_any_abi_signature_with_name,
|
|
137
|
+
_mismatched_abi_error_diagnosis,
|
|
126
138
|
check_if_arguments_can_be_encoded,
|
|
127
139
|
get_abi_element,
|
|
128
140
|
get_abi_element_info,
|
|
@@ -164,6 +176,7 @@ class BaseContractEvent:
|
|
|
164
176
|
argument_types: Tuple[str, ...] = tuple()
|
|
165
177
|
args: Any = None
|
|
166
178
|
kwargs: Any = None
|
|
179
|
+
_topic: HexStr = None
|
|
167
180
|
|
|
168
181
|
def __init__(self, *argument_names: str, abi: Optional[ABIEvent] = None) -> None:
|
|
169
182
|
self.abi_element_identifier = type(self).__name__
|
|
@@ -187,6 +200,15 @@ class BaseContractEvent:
|
|
|
187
200
|
return f"<Event {abi_to_signature(self.abi)}>"
|
|
188
201
|
return f"<Event {get_abi_element_signature(self.abi_element_identifier)}>"
|
|
189
202
|
|
|
203
|
+
def __call__(self, *args: Any, **kwargs: Any) -> Self:
|
|
204
|
+
return copy_contract_event(self, *args, **kwargs)
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def topic(self) -> HexStr:
|
|
208
|
+
if self._topic is None:
|
|
209
|
+
self._topic = encode_hex(keccak(text=self.signature))
|
|
210
|
+
return self._topic
|
|
211
|
+
|
|
190
212
|
@combomethod
|
|
191
213
|
def _get_event_abi(cls) -> ABIEvent:
|
|
192
214
|
if cls.abi:
|
|
@@ -253,7 +275,7 @@ class BaseContractEvent:
|
|
|
253
275
|
yield rich_log
|
|
254
276
|
|
|
255
277
|
@combomethod
|
|
256
|
-
def process_log(self, log:
|
|
278
|
+
def process_log(self, log: LogReceipt) -> EventData:
|
|
257
279
|
return get_event_data(self.w3.codec, self.abi, log)
|
|
258
280
|
|
|
259
281
|
@combomethod
|
|
@@ -302,9 +324,7 @@ class BaseContractEvent:
|
|
|
302
324
|
return event_filter_params
|
|
303
325
|
|
|
304
326
|
@classmethod
|
|
305
|
-
def factory(
|
|
306
|
-
cls, class_name: str, **kwargs: Any
|
|
307
|
-
) -> Union["ContractEvent", "AsyncContractEvent"]:
|
|
327
|
+
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
308
328
|
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
309
329
|
|
|
310
330
|
@staticmethod
|
|
@@ -432,7 +452,7 @@ class BaseContractEvent:
|
|
|
432
452
|
filter_builder.args[arg].match_single(value)
|
|
433
453
|
|
|
434
454
|
|
|
435
|
-
class BaseContractEvents:
|
|
455
|
+
class BaseContractEvents(Generic[TContractEvent]):
|
|
436
456
|
"""
|
|
437
457
|
Class containing contract event objects
|
|
438
458
|
|
|
@@ -458,12 +478,13 @@ class BaseContractEvents:
|
|
|
458
478
|
self,
|
|
459
479
|
abi: ABI,
|
|
460
480
|
w3: Union["Web3", "AsyncWeb3"],
|
|
461
|
-
contract_event_type:
|
|
481
|
+
contract_event_type: Type[TContractEvent],
|
|
462
482
|
address: Optional[ChecksumAddress] = None,
|
|
463
483
|
) -> None:
|
|
464
484
|
self.abi = abi
|
|
465
485
|
self.w3 = w3
|
|
466
486
|
self.address = address
|
|
487
|
+
self.contract_event_type = contract_event_type
|
|
467
488
|
_events: Sequence[ABIEvent] = None
|
|
468
489
|
|
|
469
490
|
if self.abi:
|
|
@@ -498,6 +519,42 @@ class BaseContractEvents:
|
|
|
498
519
|
except ABIEventNotFound:
|
|
499
520
|
return False
|
|
500
521
|
|
|
522
|
+
def __getattr__(self, event_name: str) -> TContractEvent:
|
|
523
|
+
if super().__getattribute__("abi") is None:
|
|
524
|
+
raise NoABIFound(
|
|
525
|
+
"There is no ABI found for this contract.",
|
|
526
|
+
)
|
|
527
|
+
elif "_events" not in self.__dict__ or len(self._events) == 0:
|
|
528
|
+
raise NoABIEventsFound(
|
|
529
|
+
"The abi for this contract contains no event definitions. ",
|
|
530
|
+
"Are you sure you provided the correct contract abi?",
|
|
531
|
+
)
|
|
532
|
+
elif get_name_from_abi_element_identifier(event_name) not in [
|
|
533
|
+
get_name_from_abi_element_identifier(event["name"])
|
|
534
|
+
for event in self._events
|
|
535
|
+
]:
|
|
536
|
+
raise ABIEventNotFound(
|
|
537
|
+
f"The event '{event_name}' was not found in this contract's abi. ",
|
|
538
|
+
"Are you sure you provided the correct contract abi?",
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
if "(" not in event_name:
|
|
542
|
+
event_name = _get_any_abi_signature_with_name(event_name, self._events)
|
|
543
|
+
else:
|
|
544
|
+
event_name = f"_{event_name}"
|
|
545
|
+
|
|
546
|
+
return super().__getattribute__(event_name)
|
|
547
|
+
|
|
548
|
+
def __getitem__(self, event_name: str) -> TContractEvent:
|
|
549
|
+
return getattr(self, event_name)
|
|
550
|
+
|
|
551
|
+
def __iter__(self) -> Iterable[TContractEvent]:
|
|
552
|
+
if not hasattr(self, "_events") or not self._events:
|
|
553
|
+
return
|
|
554
|
+
|
|
555
|
+
for event in self._events:
|
|
556
|
+
yield self[abi_to_signature(event)]
|
|
557
|
+
|
|
501
558
|
|
|
502
559
|
class BaseContractFunction:
|
|
503
560
|
"""
|
|
@@ -713,14 +770,123 @@ class BaseContractFunction:
|
|
|
713
770
|
return _repr + ">"
|
|
714
771
|
return f"<Function {get_abi_element_signature(self.abi_element_identifier)}>"
|
|
715
772
|
|
|
773
|
+
def __call__(self, *args: Any, **kwargs: Any) -> Self:
|
|
774
|
+
# When a function is called, check arguments to obtain the correct function
|
|
775
|
+
# in the contract. self will be used if all args and kwargs are
|
|
776
|
+
# encodable to self.abi, otherwise the correct function is obtained from
|
|
777
|
+
# the contract.
|
|
778
|
+
if (
|
|
779
|
+
self.abi_element_identifier in [FallbackFn, ReceiveFn]
|
|
780
|
+
or self.abi_element_identifier == "constructor"
|
|
781
|
+
):
|
|
782
|
+
return copy_contract_function(self, *args, **kwargs)
|
|
783
|
+
|
|
784
|
+
all_functions = cast(
|
|
785
|
+
List[ABIFunction],
|
|
786
|
+
filter_abi_by_type(
|
|
787
|
+
"function",
|
|
788
|
+
self.contract_abi,
|
|
789
|
+
),
|
|
790
|
+
)
|
|
791
|
+
# Filter functions by name to obtain function signatures
|
|
792
|
+
function_name = get_name_from_abi_element_identifier(
|
|
793
|
+
self.abi_element_identifier
|
|
794
|
+
)
|
|
795
|
+
function_abis = [
|
|
796
|
+
function for function in all_functions if function["name"] == function_name
|
|
797
|
+
]
|
|
798
|
+
num_args = len(args) + len(kwargs)
|
|
799
|
+
function_abis_with_arg_count = cast(
|
|
800
|
+
List[ABIFunction],
|
|
801
|
+
_filter_by_argument_count(
|
|
802
|
+
num_args,
|
|
803
|
+
function_abis,
|
|
804
|
+
),
|
|
805
|
+
)
|
|
806
|
+
|
|
807
|
+
if not len(function_abis_with_arg_count):
|
|
808
|
+
# Build an ABI without arguments to determine if one exists
|
|
809
|
+
function_abis_with_arg_count = [
|
|
810
|
+
ABIFunction({"type": "function", "name": function_name})
|
|
811
|
+
]
|
|
812
|
+
|
|
813
|
+
function_abi_matches = []
|
|
814
|
+
contract_function = None
|
|
815
|
+
for abi in function_abis_with_arg_count:
|
|
816
|
+
try:
|
|
817
|
+
# Search for a function ABI that matches the arguments used
|
|
818
|
+
function_abi_matches.append(
|
|
819
|
+
cast(
|
|
820
|
+
ABIFunction,
|
|
821
|
+
get_abi_element(
|
|
822
|
+
function_abis,
|
|
823
|
+
abi_to_signature(abi),
|
|
824
|
+
*args,
|
|
825
|
+
abi_codec=self.w3.codec,
|
|
826
|
+
**kwargs,
|
|
827
|
+
),
|
|
828
|
+
)
|
|
829
|
+
)
|
|
830
|
+
except MismatchedABI:
|
|
831
|
+
# ignore exceptions
|
|
832
|
+
continue
|
|
833
|
+
|
|
834
|
+
if len(function_abi_matches) == 1:
|
|
835
|
+
function_abi = function_abi_matches[0]
|
|
836
|
+
if abi_to_signature(self.abi) == abi_to_signature(function_abi):
|
|
837
|
+
contract_function = self
|
|
838
|
+
else:
|
|
839
|
+
# Found a match that is not self
|
|
840
|
+
contract_function = self.__class__.factory(
|
|
841
|
+
abi_to_signature(function_abi),
|
|
842
|
+
w3=self.w3,
|
|
843
|
+
contract_abi=self.contract_abi,
|
|
844
|
+
address=self.address,
|
|
845
|
+
abi_element_identifier=abi_to_signature(function_abi),
|
|
846
|
+
abi=function_abi,
|
|
847
|
+
)
|
|
848
|
+
else:
|
|
849
|
+
for abi in function_abi_matches:
|
|
850
|
+
if abi_to_signature(self.abi) == abi_to_signature(abi):
|
|
851
|
+
contract_function = self
|
|
852
|
+
break
|
|
853
|
+
else:
|
|
854
|
+
# Raise exception if multiple found
|
|
855
|
+
raise MismatchedABI(
|
|
856
|
+
_mismatched_abi_error_diagnosis(
|
|
857
|
+
function_name,
|
|
858
|
+
self.contract_abi,
|
|
859
|
+
len(function_abi_matches),
|
|
860
|
+
num_args,
|
|
861
|
+
*args,
|
|
862
|
+
abi_codec=self.w3.codec,
|
|
863
|
+
**kwargs,
|
|
864
|
+
)
|
|
865
|
+
)
|
|
866
|
+
|
|
867
|
+
return copy_contract_function(contract_function, *args, **kwargs)
|
|
868
|
+
|
|
716
869
|
@classmethod
|
|
717
|
-
def factory(
|
|
718
|
-
cls, class_name: str, **kwargs: Any
|
|
719
|
-
) -> Union["ContractFunction", "AsyncContractFunction"]:
|
|
870
|
+
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
720
871
|
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
721
872
|
|
|
873
|
+
def call(
|
|
874
|
+
self,
|
|
875
|
+
transaction: Optional[TxParams] = None,
|
|
876
|
+
block_identifier: Optional[BlockIdentifier] = None,
|
|
877
|
+
state_override: Optional[StateOverride] = None,
|
|
878
|
+
ccip_read_enabled: Optional[bool] = None,
|
|
879
|
+
) -> Any:
|
|
880
|
+
"""
|
|
881
|
+
Implementation of ``call`` should create a callable contract function
|
|
882
|
+
and execute it using the `eth_call` interface.
|
|
883
|
+
"""
|
|
884
|
+
raise NotImplementedError(
|
|
885
|
+
"This method should be implemented in the inherited class"
|
|
886
|
+
)
|
|
887
|
+
|
|
722
888
|
|
|
723
|
-
class BaseContractFunctions:
|
|
889
|
+
class BaseContractFunctions(Generic[TContractFn]):
|
|
724
890
|
"""Class containing contract function objects"""
|
|
725
891
|
|
|
726
892
|
_functions: Sequence[ABIFunction] = None
|
|
@@ -729,9 +895,7 @@ class BaseContractFunctions:
|
|
|
729
895
|
self,
|
|
730
896
|
abi: ABI,
|
|
731
897
|
w3: Union["Web3", "AsyncWeb3"],
|
|
732
|
-
contract_function_class:
|
|
733
|
-
Type["ContractFunction"], Type["AsyncContractFunction"]
|
|
734
|
-
],
|
|
898
|
+
contract_function_class: Type[TContractFn],
|
|
735
899
|
address: Optional[ChecksumAddress] = None,
|
|
736
900
|
decode_tuples: Optional[bool] = False,
|
|
737
901
|
) -> None:
|
|
@@ -777,6 +941,46 @@ class BaseContractFunctions:
|
|
|
777
941
|
except ABIFunctionNotFound:
|
|
778
942
|
return False
|
|
779
943
|
|
|
944
|
+
def __iter__(self) -> Iterable[TContractFn]:
|
|
945
|
+
if not hasattr(self, "_functions") or not self._functions:
|
|
946
|
+
return
|
|
947
|
+
|
|
948
|
+
for func in self._functions:
|
|
949
|
+
yield self[abi_to_signature(func)]
|
|
950
|
+
|
|
951
|
+
def __getattr__(self, function_name: str) -> TContractFn:
|
|
952
|
+
if super().__getattribute__("abi") is None:
|
|
953
|
+
raise NoABIFound(
|
|
954
|
+
"There is no ABI found for this contract.",
|
|
955
|
+
)
|
|
956
|
+
elif "_functions" not in self.__dict__ or len(self._functions) == 0:
|
|
957
|
+
raise NoABIFunctionsFound(
|
|
958
|
+
"The abi for this contract contains no function definitions. ",
|
|
959
|
+
"Are you sure you provided the correct contract abi?",
|
|
960
|
+
)
|
|
961
|
+
elif get_name_from_abi_element_identifier(function_name) not in [
|
|
962
|
+
get_name_from_abi_element_identifier(function["name"])
|
|
963
|
+
for function in self._functions
|
|
964
|
+
]:
|
|
965
|
+
raise ABIFunctionNotFound(
|
|
966
|
+
f"The function '{function_name}' was not found in this ",
|
|
967
|
+
"contract's abi.",
|
|
968
|
+
)
|
|
969
|
+
|
|
970
|
+
if "(" not in function_name:
|
|
971
|
+
function_name = _get_any_abi_signature_with_name(
|
|
972
|
+
function_name, self._functions
|
|
973
|
+
)
|
|
974
|
+
else:
|
|
975
|
+
function_name = f"_{function_name}"
|
|
976
|
+
|
|
977
|
+
return super().__getattribute__(
|
|
978
|
+
function_name,
|
|
979
|
+
)
|
|
980
|
+
|
|
981
|
+
def __getitem__(self, function_name: str) -> TContractFn:
|
|
982
|
+
return getattr(self, function_name)
|
|
983
|
+
|
|
780
984
|
|
|
781
985
|
class BaseContract:
|
|
782
986
|
"""
|
web3/contract/contract.py
CHANGED
|
@@ -13,7 +13,6 @@ from typing import (
|
|
|
13
13
|
|
|
14
14
|
from eth_typing import (
|
|
15
15
|
ABI,
|
|
16
|
-
ABIFunction,
|
|
17
16
|
ChecksumAddress,
|
|
18
17
|
)
|
|
19
18
|
from eth_utils import (
|
|
@@ -31,7 +30,6 @@ from hexbytes import (
|
|
|
31
30
|
|
|
32
31
|
from web3._utils.abi import (
|
|
33
32
|
fallback_func_abi_exists,
|
|
34
|
-
get_name_from_abi_element_identifier,
|
|
35
33
|
receive_func_abi_exists,
|
|
36
34
|
)
|
|
37
35
|
from web3._utils.abi_element_identifiers import (
|
|
@@ -42,8 +40,6 @@ from web3._utils.compat import (
|
|
|
42
40
|
Self,
|
|
43
41
|
)
|
|
44
42
|
from web3._utils.contracts import (
|
|
45
|
-
copy_contract_event,
|
|
46
|
-
copy_contract_function,
|
|
47
43
|
parse_block_identifier,
|
|
48
44
|
)
|
|
49
45
|
from web3._utils.datatypes import (
|
|
@@ -86,12 +82,6 @@ from web3.contract.utils import (
|
|
|
86
82
|
transact_with_contract_function,
|
|
87
83
|
)
|
|
88
84
|
from web3.exceptions import (
|
|
89
|
-
ABIEventNotFound,
|
|
90
|
-
ABIFunctionNotFound,
|
|
91
|
-
MismatchedABI,
|
|
92
|
-
NoABIEventsFound,
|
|
93
|
-
NoABIFound,
|
|
94
|
-
NoABIFunctionsFound,
|
|
95
85
|
Web3AttributeError,
|
|
96
86
|
Web3TypeError,
|
|
97
87
|
Web3ValidationError,
|
|
@@ -103,12 +93,6 @@ from web3.types import (
|
|
|
103
93
|
StateOverride,
|
|
104
94
|
TxParams,
|
|
105
95
|
)
|
|
106
|
-
from web3.utils.abi import (
|
|
107
|
-
_filter_by_argument_count,
|
|
108
|
-
_get_any_abi_signature_with_name,
|
|
109
|
-
_mismatched_abi_error_diagnosis,
|
|
110
|
-
get_abi_element,
|
|
111
|
-
)
|
|
112
96
|
|
|
113
97
|
if TYPE_CHECKING:
|
|
114
98
|
from ens import ENS # noqa: F401
|
|
@@ -119,9 +103,6 @@ class ContractEvent(BaseContractEvent):
|
|
|
119
103
|
# mypy types
|
|
120
104
|
w3: "Web3"
|
|
121
105
|
|
|
122
|
-
def __call__(self, *args: Any, **kwargs: Any) -> "ContractEvent":
|
|
123
|
-
return copy_contract_event(self, *args, **kwargs)
|
|
124
|
-
|
|
125
106
|
@combomethod
|
|
126
107
|
def get_logs(
|
|
127
108
|
self,
|
|
@@ -255,162 +236,18 @@ class ContractEvent(BaseContractEvent):
|
|
|
255
236
|
builder.address = self.address
|
|
256
237
|
return builder
|
|
257
238
|
|
|
258
|
-
@classmethod
|
|
259
|
-
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
260
|
-
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
261
239
|
|
|
262
|
-
|
|
263
|
-
class ContractEvents(BaseContractEvents):
|
|
240
|
+
class ContractEvents(BaseContractEvents[ContractEvent]):
|
|
264
241
|
def __init__(
|
|
265
242
|
self, abi: ABI, w3: "Web3", address: Optional[ChecksumAddress] = None
|
|
266
243
|
) -> None:
|
|
267
244
|
super().__init__(abi, w3, ContractEvent, address)
|
|
268
245
|
|
|
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
|
-
|
|
305
246
|
|
|
306
247
|
class ContractFunction(BaseContractFunction):
|
|
307
248
|
# mypy types
|
|
308
249
|
w3: "Web3"
|
|
309
250
|
|
|
310
|
-
def __call__(self, *args: Any, **kwargs: Any) -> "ContractFunction":
|
|
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
|
-
)
|
|
343
|
-
|
|
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
|
-
)
|
|
389
|
-
else:
|
|
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)
|
|
409
|
-
|
|
410
|
-
@classmethod
|
|
411
|
-
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
412
|
-
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
413
|
-
|
|
414
251
|
def call(
|
|
415
252
|
self,
|
|
416
253
|
transaction: Optional[TxParams] = None,
|
|
@@ -555,7 +392,7 @@ class ContractFunction(BaseContractFunction):
|
|
|
555
392
|
return cast(ContractFunction, NonExistentReceiveFunction())
|
|
556
393
|
|
|
557
394
|
|
|
558
|
-
class ContractFunctions(BaseContractFunctions):
|
|
395
|
+
class ContractFunctions(BaseContractFunctions[ContractFunction]):
|
|
559
396
|
def __init__(
|
|
560
397
|
self,
|
|
561
398
|
abi: ABI,
|
|
@@ -565,46 +402,6 @@ class ContractFunctions(BaseContractFunctions):
|
|
|
565
402
|
) -> None:
|
|
566
403
|
super().__init__(abi, w3, ContractFunction, address, decode_tuples)
|
|
567
404
|
|
|
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
|
-
|
|
575
|
-
def __getattr__(self, function_name: str) -> "ContractFunction":
|
|
576
|
-
if super().__getattribute__("abi") is None:
|
|
577
|
-
raise NoABIFound(
|
|
578
|
-
"There is no ABI found for this contract.",
|
|
579
|
-
)
|
|
580
|
-
elif "_functions" not in self.__dict__ or len(self._functions) == 0:
|
|
581
|
-
raise NoABIFunctionsFound(
|
|
582
|
-
"The abi for this contract contains no function definitions. ",
|
|
583
|
-
"Are you sure you provided the correct contract abi?",
|
|
584
|
-
)
|
|
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
|
-
]:
|
|
589
|
-
raise ABIFunctionNotFound(
|
|
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
|
|
597
|
-
)
|
|
598
|
-
else:
|
|
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)
|
|
607
|
-
|
|
608
405
|
|
|
609
406
|
class Contract(BaseContract):
|
|
610
407
|
# mypy types
|
web3/datastructures.py
CHANGED
|
@@ -15,9 +15,9 @@ from typing import (
|
|
|
15
15
|
Optional,
|
|
16
16
|
Sequence,
|
|
17
17
|
Tuple,
|
|
18
|
-
Type,
|
|
19
18
|
TypeVar,
|
|
20
19
|
Union,
|
|
20
|
+
ValuesView,
|
|
21
21
|
cast,
|
|
22
22
|
)
|
|
23
23
|
|
|
@@ -25,9 +25,6 @@ from eth_utils import (
|
|
|
25
25
|
is_integer,
|
|
26
26
|
)
|
|
27
27
|
|
|
28
|
-
from web3._utils.formatters import (
|
|
29
|
-
recursive_map,
|
|
30
|
-
)
|
|
31
28
|
from web3.exceptions import (
|
|
32
29
|
Web3AssertionError,
|
|
33
30
|
Web3TypeError,
|
|
@@ -81,19 +78,18 @@ class ReadableAttributeDict(Mapping[TKey, TValue]):
|
|
|
81
78
|
builder.text(")")
|
|
82
79
|
|
|
83
80
|
@classmethod
|
|
84
|
-
def
|
|
81
|
+
def recursive(cls, value: TValue) -> Any:
|
|
82
|
+
"""
|
|
83
|
+
Recursively convert mappings to ReadableAttributeDict instances and
|
|
84
|
+
process nested collections (e.g., lists, sets, and dictionaries).
|
|
85
|
+
"""
|
|
85
86
|
if isinstance(value, Mapping):
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def recursive(cls, value: TValue) -> "ReadableAttributeDict[TKey, TValue]":
|
|
93
|
-
return cast(
|
|
94
|
-
"ReadableAttributeDict[TKey, TValue]",
|
|
95
|
-
recursive_map(cls._apply_if_mapping, value),
|
|
96
|
-
)
|
|
87
|
+
return cls({k: cls.recursive(v) for k, v in value.items()})
|
|
88
|
+
elif isinstance(value, Sequence) and not isinstance(value, (str, bytes)):
|
|
89
|
+
return type(value)([cls.recursive(v) for v in value]) # type: ignore
|
|
90
|
+
elif isinstance(value, set):
|
|
91
|
+
return {cls.recursive(v) for v in value}
|
|
92
|
+
return value
|
|
97
93
|
|
|
98
94
|
|
|
99
95
|
class MutableAttributeDict(
|
|
@@ -342,3 +338,6 @@ class NamedElementOnion(Mapping[TKey, TValue]):
|
|
|
342
338
|
# This leads to typing issues, so it's better to use
|
|
343
339
|
# ``as_tuple_of_middleware()`` to achieve the same result.
|
|
344
340
|
return iter(self._reversed_middleware()) # type: ignore
|
|
341
|
+
|
|
342
|
+
def values(self) -> ValuesView[TValue]:
|
|
343
|
+
return ValuesView(self._queue)
|