web3 7.0.0b2__py3-none-any.whl → 7.7.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/__init__.py +13 -2
- ens/_normalization.py +4 -4
- ens/async_ens.py +27 -15
- ens/base_ens.py +3 -1
- ens/contract_data.py +2 -2
- ens/ens.py +10 -7
- ens/exceptions.py +16 -29
- ens/specs/nf.json +1 -1
- ens/specs/normalization_spec.json +1 -1
- ens/utils.py +24 -32
- web3/__init__.py +23 -12
- web3/_utils/abi.py +157 -263
- web3/_utils/async_transactions.py +34 -20
- web3/_utils/batching.py +217 -0
- web3/_utils/blocks.py +6 -2
- web3/_utils/caching/__init__.py +12 -0
- web3/_utils/caching/caching_utils.py +433 -0
- web3/_utils/caching/request_caching_validation.py +287 -0
- web3/_utils/compat/__init__.py +2 -3
- web3/_utils/contract_sources/compile_contracts.py +1 -1
- web3/_utils/contract_sources/contract_data/ambiguous_function_contract.py +42 -0
- 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 +172 -220
- web3/_utils/datatypes.py +5 -1
- web3/_utils/decorators.py +6 -1
- web3/_utils/empty.py +1 -1
- web3/_utils/encoding.py +16 -12
- web3/_utils/error_formatters_utils.py +5 -3
- web3/_utils/events.py +78 -72
- web3/_utils/fee_utils.py +1 -3
- web3/_utils/filters.py +24 -22
- web3/_utils/formatters.py +2 -2
- web3/_utils/http.py +8 -2
- web3/_utils/http_session_manager.py +314 -0
- web3/_utils/math.py +14 -15
- web3/_utils/method_formatters.py +161 -34
- web3/_utils/module.py +2 -1
- web3/_utils/module_testing/__init__.py +3 -2
- web3/_utils/module_testing/eth_module.py +736 -583
- web3/_utils/module_testing/go_ethereum_debug_module.py +128 -0
- web3/_utils/module_testing/module_testing_utils.py +81 -24
- web3/_utils/module_testing/persistent_connection_provider.py +702 -220
- web3/_utils/module_testing/utils.py +114 -33
- web3/_utils/module_testing/web3_module.py +438 -17
- web3/_utils/normalizers.py +13 -11
- web3/_utils/rpc_abi.py +10 -22
- web3/_utils/threads.py +8 -7
- web3/_utils/transactions.py +32 -25
- web3/_utils/type_conversion.py +5 -1
- web3/_utils/validation.py +20 -17
- web3/beacon/__init__.py +5 -0
- web3/beacon/api_endpoints.py +3 -0
- web3/beacon/async_beacon.py +29 -6
- web3/beacon/beacon.py +24 -6
- web3/contract/__init__.py +7 -0
- web3/contract/async_contract.py +285 -82
- web3/contract/base_contract.py +556 -258
- web3/contract/contract.py +295 -84
- web3/contract/utils.py +251 -55
- web3/datastructures.py +49 -34
- web3/eth/__init__.py +7 -0
- web3/eth/async_eth.py +89 -69
- web3/eth/base_eth.py +7 -3
- web3/eth/eth.py +43 -66
- web3/exceptions.py +158 -83
- web3/gas_strategies/time_based.py +8 -6
- web3/geth.py +53 -184
- web3/main.py +77 -17
- web3/manager.py +362 -95
- web3/method.py +43 -15
- web3/middleware/__init__.py +17 -0
- web3/middleware/attrdict.py +12 -22
- web3/middleware/base.py +55 -2
- web3/middleware/filter.py +45 -23
- web3/middleware/formatting.py +6 -3
- web3/middleware/names.py +4 -1
- web3/middleware/signing.py +15 -6
- web3/middleware/stalecheck.py +2 -1
- web3/module.py +61 -25
- web3/providers/__init__.py +21 -0
- web3/providers/async_base.py +87 -32
- web3/providers/base.py +77 -32
- web3/providers/eth_tester/__init__.py +5 -0
- web3/providers/eth_tester/defaults.py +2 -55
- web3/providers/eth_tester/main.py +41 -15
- web3/providers/eth_tester/middleware.py +16 -17
- web3/providers/ipc.py +41 -17
- web3/providers/legacy_websocket.py +26 -1
- web3/providers/persistent/__init__.py +7 -0
- web3/providers/persistent/async_ipc.py +61 -121
- web3/providers/persistent/persistent.py +323 -16
- web3/providers/persistent/persistent_connection.py +54 -5
- web3/providers/persistent/request_processor.py +136 -56
- web3/providers/persistent/subscription_container.py +56 -0
- web3/providers/persistent/subscription_manager.py +233 -0
- web3/providers/persistent/websocket.py +29 -92
- web3/providers/rpc/__init__.py +5 -0
- web3/providers/rpc/async_rpc.py +73 -18
- web3/providers/rpc/rpc.py +73 -30
- web3/providers/rpc/utils.py +1 -13
- web3/scripts/install_pre_releases.py +33 -0
- web3/scripts/parse_pygeth_version.py +16 -0
- web3/testing.py +4 -4
- web3/tracing.py +9 -5
- web3/types.py +141 -74
- web3/utils/__init__.py +64 -5
- web3/utils/abi.py +790 -10
- web3/utils/address.py +8 -0
- web3/utils/async_exception_handling.py +20 -11
- web3/utils/caching.py +34 -4
- web3/utils/exception_handling.py +9 -12
- web3/utils/subscriptions.py +285 -0
- {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/LICENSE +1 -1
- web3-7.7.0.dist-info/METADATA +130 -0
- web3-7.7.0.dist-info/RECORD +171 -0
- {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/WHEEL +1 -1
- web3/_utils/caching.py +0 -155
- web3/_utils/contract_sources/contract_data/address_reflector.py +0 -29
- web3/_utils/module_testing/go_ethereum_personal_module.py +0 -300
- web3/_utils/request.py +0 -265
- web3-7.0.0b2.dist-info/METADATA +0 -106
- web3-7.0.0b2.dist-info/RECORD +0 -163
- /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
- {web3-7.0.0b2.dist-info → web3-7.7.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,
|
|
@@ -13,10 +12,15 @@ from typing import (
|
|
|
13
12
|
)
|
|
14
13
|
|
|
15
14
|
from eth_typing import (
|
|
15
|
+
ABI,
|
|
16
|
+
ABIFunction,
|
|
16
17
|
ChecksumAddress,
|
|
17
18
|
)
|
|
18
19
|
from eth_utils import (
|
|
20
|
+
abi_to_signature,
|
|
19
21
|
combomethod,
|
|
22
|
+
filter_abi_by_type,
|
|
23
|
+
get_abi_input_names,
|
|
20
24
|
)
|
|
21
25
|
from eth_utils.toolz import (
|
|
22
26
|
partial,
|
|
@@ -27,13 +31,19 @@ from hexbytes import (
|
|
|
27
31
|
|
|
28
32
|
from web3._utils.abi import (
|
|
29
33
|
fallback_func_abi_exists,
|
|
30
|
-
|
|
34
|
+
get_name_from_abi_element_identifier,
|
|
31
35
|
receive_func_abi_exists,
|
|
32
36
|
)
|
|
37
|
+
from web3._utils.abi_element_identifiers import (
|
|
38
|
+
FallbackFn,
|
|
39
|
+
ReceiveFn,
|
|
40
|
+
)
|
|
33
41
|
from web3._utils.compat import (
|
|
34
42
|
Self,
|
|
35
43
|
)
|
|
36
44
|
from web3._utils.contracts import (
|
|
45
|
+
copy_contract_event,
|
|
46
|
+
copy_contract_function,
|
|
37
47
|
parse_block_identifier,
|
|
38
48
|
)
|
|
39
49
|
from web3._utils.datatypes import (
|
|
@@ -46,10 +56,6 @@ from web3._utils.events import (
|
|
|
46
56
|
from web3._utils.filters import (
|
|
47
57
|
LogFilter,
|
|
48
58
|
)
|
|
49
|
-
from web3._utils.function_identifiers import (
|
|
50
|
-
FallbackFn,
|
|
51
|
-
ReceiveFn,
|
|
52
|
-
)
|
|
53
59
|
from web3._utils.normalizers import (
|
|
54
60
|
normalize_abi,
|
|
55
61
|
normalize_address,
|
|
@@ -73,25 +79,35 @@ from web3.contract.utils import (
|
|
|
73
79
|
build_transaction_for_function,
|
|
74
80
|
call_contract_function,
|
|
75
81
|
estimate_gas_for_function,
|
|
82
|
+
find_events_by_identifier,
|
|
76
83
|
find_functions_by_identifier,
|
|
84
|
+
get_event_by_identifier,
|
|
77
85
|
get_function_by_identifier,
|
|
78
86
|
transact_with_contract_function,
|
|
79
87
|
)
|
|
80
88
|
from web3.exceptions import (
|
|
89
|
+
ABIEventNotFound,
|
|
81
90
|
ABIFunctionNotFound,
|
|
91
|
+
MismatchedABI,
|
|
92
|
+
NoABIEventsFound,
|
|
82
93
|
NoABIFound,
|
|
83
94
|
NoABIFunctionsFound,
|
|
95
|
+
Web3AttributeError,
|
|
96
|
+
Web3TypeError,
|
|
84
97
|
Web3ValidationError,
|
|
98
|
+
Web3ValueError,
|
|
85
99
|
)
|
|
86
100
|
from web3.types import (
|
|
87
|
-
ABI,
|
|
88
101
|
BlockIdentifier,
|
|
89
102
|
EventData,
|
|
90
103
|
StateOverride,
|
|
91
104
|
TxParams,
|
|
92
105
|
)
|
|
93
|
-
from web3.utils import (
|
|
94
|
-
|
|
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,
|
|
95
111
|
)
|
|
96
112
|
|
|
97
113
|
if TYPE_CHECKING:
|
|
@@ -103,15 +119,19 @@ class ContractEvent(BaseContractEvent):
|
|
|
103
119
|
# mypy types
|
|
104
120
|
w3: "Web3"
|
|
105
121
|
|
|
122
|
+
def __call__(self, *args: Any, **kwargs: Any) -> "ContractEvent":
|
|
123
|
+
return copy_contract_event(self, *args, **kwargs)
|
|
124
|
+
|
|
106
125
|
@combomethod
|
|
107
126
|
def get_logs(
|
|
108
127
|
self,
|
|
109
128
|
argument_filters: Optional[Dict[str, Any]] = None,
|
|
110
|
-
|
|
111
|
-
|
|
129
|
+
from_block: Optional[BlockIdentifier] = None,
|
|
130
|
+
to_block: Optional[BlockIdentifier] = None,
|
|
112
131
|
block_hash: Optional[HexBytes] = None,
|
|
113
132
|
) -> Iterable[EventData]:
|
|
114
|
-
"""
|
|
133
|
+
"""
|
|
134
|
+
Get events for this contract instance using eth_getLogs API.
|
|
115
135
|
|
|
116
136
|
This is a stateless method, as opposed to create_filter.
|
|
117
137
|
It can be safely called against nodes which do not provide
|
|
@@ -127,10 +147,10 @@ class ContractEvent(BaseContractEvent):
|
|
|
127
147
|
|
|
128
148
|
.. code-block:: python
|
|
129
149
|
|
|
130
|
-
from = max(
|
|
131
|
-
to =
|
|
150
|
+
from = max(my_contract.web3.eth.block_number - 10, 1)
|
|
151
|
+
to = my_contract.web3.eth.block_number
|
|
132
152
|
|
|
133
|
-
events =
|
|
153
|
+
events = my_contract.events.Transfer.get_logs(from_block=from, to_block=to)
|
|
134
154
|
|
|
135
155
|
for e in events:
|
|
136
156
|
print(e["args"]["from"],
|
|
@@ -160,14 +180,13 @@ class ContractEvent(BaseContractEvent):
|
|
|
160
180
|
|
|
161
181
|
:param argument_filters: Filter by argument values. Indexed arguments are
|
|
162
182
|
filtered by the node while non-indexed arguments are filtered by the library.
|
|
163
|
-
:param
|
|
164
|
-
:param
|
|
183
|
+
:param from_block: block number or "latest", defaults to "latest"
|
|
184
|
+
:param to_block: block number or "latest". Defaults to "latest"
|
|
165
185
|
:param block_hash: block hash. block_hash cannot be set at the
|
|
166
|
-
same time as
|
|
186
|
+
same time as ``from_block`` or ``to_block``
|
|
167
187
|
:yield: Tuple of :class:`AttributeDict` instances
|
|
168
188
|
"""
|
|
169
189
|
event_abi = self._get_event_abi()
|
|
170
|
-
|
|
171
190
|
# validate ``argument_filters`` if present
|
|
172
191
|
if argument_filters is not None:
|
|
173
192
|
event_arg_names = get_abi_input_names(event_abi)
|
|
@@ -178,7 +197,7 @@ class ContractEvent(BaseContractEvent):
|
|
|
178
197
|
)
|
|
179
198
|
|
|
180
199
|
_filter_params = self._get_event_filter_params(
|
|
181
|
-
event_abi, argument_filters,
|
|
200
|
+
event_abi, argument_filters, from_block, to_block, block_hash
|
|
182
201
|
)
|
|
183
202
|
# call JSON-RPC API
|
|
184
203
|
logs = self.w3.eth.get_logs(_filter_params)
|
|
@@ -201,41 +220,45 @@ class ContractEvent(BaseContractEvent):
|
|
|
201
220
|
self,
|
|
202
221
|
*, # PEP 3102
|
|
203
222
|
argument_filters: Optional[Dict[str, Any]] = None,
|
|
204
|
-
|
|
205
|
-
|
|
223
|
+
from_block: Optional[BlockIdentifier] = None,
|
|
224
|
+
to_block: BlockIdentifier = "latest",
|
|
206
225
|
address: Optional[ChecksumAddress] = None,
|
|
207
226
|
topics: Optional[Sequence[Any]] = None,
|
|
208
227
|
) -> LogFilter:
|
|
209
228
|
"""
|
|
210
229
|
Create filter object that tracks logs emitted by this contract event.
|
|
211
230
|
"""
|
|
212
|
-
|
|
231
|
+
abi = self._get_event_abi()
|
|
232
|
+
filter_builder = EventFilterBuilder(abi, self.w3.codec)
|
|
213
233
|
self._set_up_filter_builder(
|
|
214
234
|
argument_filters,
|
|
215
|
-
|
|
216
|
-
|
|
235
|
+
from_block,
|
|
236
|
+
to_block,
|
|
217
237
|
address,
|
|
218
238
|
topics,
|
|
219
239
|
filter_builder,
|
|
220
240
|
)
|
|
221
241
|
log_filter = filter_builder.deploy(self.w3)
|
|
222
|
-
log_filter.log_entry_formatter = get_event_data(
|
|
223
|
-
self.w3.codec, self._get_event_abi()
|
|
224
|
-
)
|
|
242
|
+
log_filter.log_entry_formatter = get_event_data(self.w3.codec, abi)
|
|
225
243
|
log_filter.builder = filter_builder
|
|
226
244
|
|
|
227
245
|
return log_filter
|
|
228
246
|
|
|
229
247
|
@combomethod
|
|
230
248
|
def build_filter(self) -> EventFilterBuilder:
|
|
249
|
+
abi = self._get_event_abi()
|
|
231
250
|
builder = EventFilterBuilder(
|
|
232
|
-
|
|
251
|
+
abi,
|
|
233
252
|
self.w3.codec,
|
|
234
|
-
formatter=get_event_data(self.w3.codec,
|
|
253
|
+
formatter=get_event_data(self.w3.codec, abi),
|
|
235
254
|
)
|
|
236
255
|
builder.address = self.address
|
|
237
256
|
return builder
|
|
238
257
|
|
|
258
|
+
@classmethod
|
|
259
|
+
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
260
|
+
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
261
|
+
|
|
239
262
|
|
|
240
263
|
class ContractEvents(BaseContractEvents):
|
|
241
264
|
def __init__(
|
|
@@ -243,33 +266,155 @@ class ContractEvents(BaseContractEvents):
|
|
|
243
266
|
) -> None:
|
|
244
267
|
super().__init__(abi, w3, ContractEvent, address)
|
|
245
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
|
+
|
|
246
305
|
|
|
247
306
|
class ContractFunction(BaseContractFunction):
|
|
248
307
|
# mypy types
|
|
249
308
|
w3: "Web3"
|
|
250
309
|
|
|
251
310
|
def __call__(self, *args: Any, **kwargs: Any) -> "ContractFunction":
|
|
252
|
-
|
|
253
|
-
if args
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
+
)
|
|
257
343
|
|
|
258
|
-
if
|
|
259
|
-
|
|
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
|
+
)
|
|
260
389
|
else:
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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)
|
|
264
409
|
|
|
265
410
|
@classmethod
|
|
266
411
|
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
267
|
-
return PropertyCheckingFactory(class_name, (cls,), kwargs)(
|
|
412
|
+
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
268
413
|
|
|
269
414
|
def call(
|
|
270
415
|
self,
|
|
271
416
|
transaction: Optional[TxParams] = None,
|
|
272
|
-
block_identifier: BlockIdentifier = None,
|
|
417
|
+
block_identifier: Optional[BlockIdentifier] = None,
|
|
273
418
|
state_override: Optional[StateOverride] = None,
|
|
274
419
|
ccip_read_enabled: Optional[bool] = None,
|
|
275
420
|
) -> Any:
|
|
@@ -294,9 +439,9 @@ class ContractFunction(BaseContractFunction):
|
|
|
294
439
|
addr = contract.functions.owner().call()
|
|
295
440
|
|
|
296
441
|
:param transaction: Dictionary of transaction info for web3 interface
|
|
297
|
-
:param block_identifier:
|
|
298
|
-
:param state_override
|
|
299
|
-
: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
|
|
300
445
|
:return: ``Caller`` object that has contract public functions
|
|
301
446
|
and variables exposed as Python methods
|
|
302
447
|
"""
|
|
@@ -304,11 +449,13 @@ class ContractFunction(BaseContractFunction):
|
|
|
304
449
|
|
|
305
450
|
block_id = parse_block_identifier(self.w3, block_identifier)
|
|
306
451
|
|
|
452
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
453
|
+
|
|
307
454
|
return call_contract_function(
|
|
308
455
|
self.w3,
|
|
309
456
|
self.address,
|
|
310
457
|
self._return_data_normalizers,
|
|
311
|
-
|
|
458
|
+
abi_element_identifier,
|
|
312
459
|
call_transaction,
|
|
313
460
|
block_id,
|
|
314
461
|
self.contract_abi,
|
|
@@ -316,21 +463,23 @@ class ContractFunction(BaseContractFunction):
|
|
|
316
463
|
state_override,
|
|
317
464
|
ccip_read_enabled,
|
|
318
465
|
self.decode_tuples,
|
|
319
|
-
*self.args,
|
|
320
|
-
**self.kwargs,
|
|
466
|
+
*self.args or (),
|
|
467
|
+
**self.kwargs or {},
|
|
321
468
|
)
|
|
322
469
|
|
|
323
470
|
def transact(self, transaction: Optional[TxParams] = None) -> HexBytes:
|
|
324
471
|
setup_transaction = self._transact(transaction)
|
|
472
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
473
|
+
|
|
325
474
|
return transact_with_contract_function(
|
|
326
475
|
self.address,
|
|
327
476
|
self.w3,
|
|
328
|
-
|
|
477
|
+
abi_element_identifier,
|
|
329
478
|
setup_transaction,
|
|
330
479
|
self.contract_abi,
|
|
331
480
|
self.abi,
|
|
332
|
-
*self.args,
|
|
333
|
-
**self.kwargs,
|
|
481
|
+
*self.args or (),
|
|
482
|
+
**self.kwargs or {},
|
|
334
483
|
)
|
|
335
484
|
|
|
336
485
|
def estimate_gas(
|
|
@@ -340,30 +489,33 @@ class ContractFunction(BaseContractFunction):
|
|
|
340
489
|
state_override: Optional[StateOverride] = None,
|
|
341
490
|
) -> int:
|
|
342
491
|
setup_transaction = self._estimate_gas(transaction)
|
|
492
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
343
493
|
return estimate_gas_for_function(
|
|
344
494
|
self.address,
|
|
345
495
|
self.w3,
|
|
346
|
-
|
|
496
|
+
abi_element_identifier,
|
|
347
497
|
setup_transaction,
|
|
348
498
|
self.contract_abi,
|
|
349
499
|
self.abi,
|
|
350
500
|
block_identifier,
|
|
351
501
|
state_override,
|
|
352
|
-
*self.args,
|
|
353
|
-
**self.kwargs,
|
|
502
|
+
*self.args or (),
|
|
503
|
+
**self.kwargs or {},
|
|
354
504
|
)
|
|
355
505
|
|
|
356
506
|
def build_transaction(self, transaction: Optional[TxParams] = None) -> TxParams:
|
|
357
507
|
built_transaction = self._build_transaction(transaction)
|
|
508
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
509
|
+
|
|
358
510
|
return build_transaction_for_function(
|
|
359
511
|
self.address,
|
|
360
512
|
self.w3,
|
|
361
|
-
|
|
513
|
+
abi_element_identifier,
|
|
362
514
|
built_transaction,
|
|
363
515
|
self.contract_abi,
|
|
364
516
|
self.abi,
|
|
365
|
-
*self.args,
|
|
366
|
-
**self.kwargs,
|
|
517
|
+
*self.args or (),
|
|
518
|
+
**self.kwargs or {},
|
|
367
519
|
)
|
|
368
520
|
|
|
369
521
|
@staticmethod
|
|
@@ -373,12 +525,14 @@ class ContractFunction(BaseContractFunction):
|
|
|
373
525
|
address: Optional[ChecksumAddress] = None,
|
|
374
526
|
) -> "ContractFunction":
|
|
375
527
|
if abi and fallback_func_abi_exists(abi):
|
|
528
|
+
fallback_abi = filter_abi_by_type("fallback", abi)[0]
|
|
376
529
|
return ContractFunction.factory(
|
|
377
530
|
"fallback",
|
|
378
531
|
w3=w3,
|
|
379
532
|
contract_abi=abi,
|
|
380
533
|
address=address,
|
|
381
|
-
|
|
534
|
+
abi_element_identifier=FallbackFn,
|
|
535
|
+
abi=fallback_abi,
|
|
382
536
|
)()
|
|
383
537
|
return cast(ContractFunction, NonExistentFallbackFunction())
|
|
384
538
|
|
|
@@ -389,12 +543,14 @@ class ContractFunction(BaseContractFunction):
|
|
|
389
543
|
address: Optional[ChecksumAddress] = None,
|
|
390
544
|
) -> "ContractFunction":
|
|
391
545
|
if abi and receive_func_abi_exists(abi):
|
|
546
|
+
receive_abi = filter_abi_by_type("receive", abi)[0]
|
|
392
547
|
return ContractFunction.factory(
|
|
393
548
|
"receive",
|
|
394
549
|
w3=w3,
|
|
395
550
|
contract_abi=abi,
|
|
396
551
|
address=address,
|
|
397
|
-
|
|
552
|
+
abi_element_identifier=ReceiveFn,
|
|
553
|
+
abi=receive_abi,
|
|
398
554
|
)()
|
|
399
555
|
return cast(ContractFunction, NonExistentReceiveFunction())
|
|
400
556
|
|
|
@@ -409,23 +565,45 @@ class ContractFunctions(BaseContractFunctions):
|
|
|
409
565
|
) -> None:
|
|
410
566
|
super().__init__(abi, w3, ContractFunction, address, decode_tuples)
|
|
411
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
|
+
|
|
412
575
|
def __getattr__(self, function_name: str) -> "ContractFunction":
|
|
413
|
-
if
|
|
576
|
+
if super().__getattribute__("abi") is None:
|
|
414
577
|
raise NoABIFound(
|
|
415
578
|
"There is no ABI found for this contract.",
|
|
416
579
|
)
|
|
417
|
-
|
|
580
|
+
elif "_functions" not in self.__dict__ or len(self._functions) == 0:
|
|
418
581
|
raise NoABIFunctionsFound(
|
|
419
582
|
"The abi for this contract contains no function definitions. ",
|
|
420
583
|
"Are you sure you provided the correct contract abi?",
|
|
421
584
|
)
|
|
422
|
-
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
|
+
]:
|
|
423
589
|
raise ABIFunctionNotFound(
|
|
424
|
-
f"The function '{function_name}' was not found in this
|
|
425
|
-
"
|
|
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
|
|
426
597
|
)
|
|
427
598
|
else:
|
|
428
|
-
|
|
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)
|
|
429
607
|
|
|
430
608
|
|
|
431
609
|
class Contract(BaseContract):
|
|
@@ -438,20 +616,23 @@ class Contract(BaseContract):
|
|
|
438
616
|
events: ContractEvents = None
|
|
439
617
|
|
|
440
618
|
def __init__(self, address: Optional[ChecksumAddress] = None) -> None:
|
|
441
|
-
"""
|
|
442
|
-
|
|
619
|
+
"""
|
|
620
|
+
Create a new smart contract proxy object.
|
|
621
|
+
:param address: Contract address as 0x hex string
|
|
622
|
+
"""
|
|
443
623
|
_w3 = self.w3
|
|
444
624
|
if _w3 is None:
|
|
445
|
-
raise
|
|
625
|
+
raise Web3AttributeError(
|
|
446
626
|
"The `Contract` class has not been initialized. Please use the "
|
|
447
627
|
"`web3.contract` interface to create your contract class."
|
|
448
628
|
)
|
|
449
629
|
|
|
450
630
|
if address:
|
|
451
|
-
|
|
631
|
+
# invoke ``w3._ens`` over ``w3.ens`` to avoid premature instantiation
|
|
632
|
+
self.address = normalize_address(cast("ENS", _w3._ens), address)
|
|
452
633
|
|
|
453
634
|
if not self.address:
|
|
454
|
-
raise
|
|
635
|
+
raise Web3TypeError(
|
|
455
636
|
"The address argument is required to instantiate a contract."
|
|
456
637
|
)
|
|
457
638
|
|
|
@@ -459,7 +640,11 @@ class Contract(BaseContract):
|
|
|
459
640
|
self.abi, _w3, self.address, decode_tuples=self.decode_tuples
|
|
460
641
|
)
|
|
461
642
|
self.caller = ContractCaller(
|
|
462
|
-
self.abi,
|
|
643
|
+
self.abi,
|
|
644
|
+
_w3,
|
|
645
|
+
self.address,
|
|
646
|
+
decode_tuples=self.decode_tuples,
|
|
647
|
+
contract_functions=self.functions,
|
|
463
648
|
)
|
|
464
649
|
self.events = ContractEvents(self.abi, _w3, self.address)
|
|
465
650
|
self.fallback = Contract.get_fallback_function(
|
|
@@ -483,7 +668,8 @@ class Contract(BaseContract):
|
|
|
483
668
|
|
|
484
669
|
normalizers = {
|
|
485
670
|
"abi": normalize_abi,
|
|
486
|
-
|
|
671
|
+
# invoke ``w3._ens`` over ``w3.ens`` to avoid premature instantiation
|
|
672
|
+
"address": partial(normalize_address, w3._ens),
|
|
487
673
|
"bytecode": normalize_bytecode,
|
|
488
674
|
"bytecode_runtime": normalize_bytecode,
|
|
489
675
|
}
|
|
@@ -497,6 +683,16 @@ class Contract(BaseContract):
|
|
|
497
683
|
normalizers=normalizers,
|
|
498
684
|
),
|
|
499
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
|
+
|
|
500
696
|
contract.functions = ContractFunctions(
|
|
501
697
|
contract.abi, contract.w3, decode_tuples=contract.decode_tuples
|
|
502
698
|
)
|
|
@@ -505,6 +701,7 @@ class Contract(BaseContract):
|
|
|
505
701
|
contract.w3,
|
|
506
702
|
contract.address,
|
|
507
703
|
decode_tuples=contract.decode_tuples,
|
|
704
|
+
contract_functions=contract.functions,
|
|
508
705
|
)
|
|
509
706
|
contract.events = ContractEvents(contract.abi, contract.w3)
|
|
510
707
|
contract.fallback = Contract.get_fallback_function(
|
|
@@ -528,7 +725,7 @@ class Contract(BaseContract):
|
|
|
528
725
|
:return: a contract constructor object
|
|
529
726
|
"""
|
|
530
727
|
if cls.bytecode is None:
|
|
531
|
-
raise
|
|
728
|
+
raise Web3ValueError(
|
|
532
729
|
"Cannot call constructor on a contract that does not have "
|
|
533
730
|
"'bytecode' associated with it"
|
|
534
731
|
)
|
|
@@ -556,6 +753,24 @@ class Contract(BaseContract):
|
|
|
556
753
|
) -> "ContractFunction":
|
|
557
754
|
return get_function_by_identifier(fns, identifier)
|
|
558
755
|
|
|
756
|
+
@combomethod
|
|
757
|
+
def find_events_by_identifier(
|
|
758
|
+
cls,
|
|
759
|
+
contract_abi: ABI,
|
|
760
|
+
w3: "Web3",
|
|
761
|
+
address: ChecksumAddress,
|
|
762
|
+
callable_check: Callable[..., Any],
|
|
763
|
+
) -> List["ContractEvent"]:
|
|
764
|
+
return find_events_by_identifier(
|
|
765
|
+
contract_abi, w3, address, callable_check, ContractEvent
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
@combomethod
|
|
769
|
+
def get_event_by_identifier(
|
|
770
|
+
self, events: Sequence["ContractEvent"], identifier: str
|
|
771
|
+
) -> "ContractEvent":
|
|
772
|
+
return get_event_by_identifier(events, identifier)
|
|
773
|
+
|
|
559
774
|
|
|
560
775
|
class ContractCaller(BaseContractCaller):
|
|
561
776
|
# mypy types
|
|
@@ -570,6 +785,7 @@ class ContractCaller(BaseContractCaller):
|
|
|
570
785
|
block_identifier: BlockIdentifier = None,
|
|
571
786
|
ccip_read_enabled: Optional[bool] = None,
|
|
572
787
|
decode_tuples: Optional[bool] = False,
|
|
788
|
+
contract_functions: Optional[ContractFunctions] = None,
|
|
573
789
|
) -> None:
|
|
574
790
|
super().__init__(abi, w3, address, decode_tuples=decode_tuples)
|
|
575
791
|
|
|
@@ -577,17 +793,13 @@ class ContractCaller(BaseContractCaller):
|
|
|
577
793
|
if transaction is None:
|
|
578
794
|
transaction = {}
|
|
579
795
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
func["name"],
|
|
584
|
-
w3=w3,
|
|
585
|
-
contract_abi=self.abi,
|
|
586
|
-
address=self.address,
|
|
587
|
-
function_identifier=func["name"],
|
|
588
|
-
decode_tuples=decode_tuples,
|
|
796
|
+
if contract_functions is None:
|
|
797
|
+
contract_functions = ContractFunctions(
|
|
798
|
+
abi, w3, address=address, decode_tuples=decode_tuples
|
|
589
799
|
)
|
|
590
800
|
|
|
801
|
+
self._functions = contract_functions._functions
|
|
802
|
+
for fn in contract_functions.__iter__():
|
|
591
803
|
caller_method = partial(
|
|
592
804
|
self.call_function,
|
|
593
805
|
fn,
|
|
@@ -595,8 +807,7 @@ class ContractCaller(BaseContractCaller):
|
|
|
595
807
|
block_identifier=block_identifier,
|
|
596
808
|
ccip_read_enabled=ccip_read_enabled,
|
|
597
809
|
)
|
|
598
|
-
|
|
599
|
-
setattr(self, func["name"], caller_method)
|
|
810
|
+
setattr(self, str(fn.abi_element_identifier), caller_method)
|
|
600
811
|
|
|
601
812
|
def __call__(
|
|
602
813
|
self,
|