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
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from typing import (
|
|
3
|
+
cast,
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
from eth_typing import (
|
|
7
|
+
HexStr,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from web3 import (
|
|
11
|
+
AsyncWeb3,
|
|
12
|
+
Web3,
|
|
13
|
+
)
|
|
14
|
+
from web3.types import (
|
|
15
|
+
BlockData,
|
|
16
|
+
CallTrace,
|
|
17
|
+
ChecksumAddress,
|
|
18
|
+
DiffModeTrace,
|
|
19
|
+
OpcodeTrace,
|
|
20
|
+
PrestateTrace,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class GoEthereumAsyncDebugModuleTest:
|
|
25
|
+
@pytest.mark.asyncio
|
|
26
|
+
async def test_async_geth_debug_trace_transaction_opcode_logger(
|
|
27
|
+
self, async_w3: "AsyncWeb3", txn_hash_with_log: HexStr
|
|
28
|
+
) -> None:
|
|
29
|
+
result = await async_w3.geth.debug.trace_transaction(txn_hash_with_log)
|
|
30
|
+
assert "structLogs" in dict(result).keys()
|
|
31
|
+
assert "gas" in dict(result).keys()
|
|
32
|
+
assert "failed" in dict(result).keys()
|
|
33
|
+
|
|
34
|
+
@pytest.mark.asyncio
|
|
35
|
+
async def test_async_geth_debug_trace_transaction_call_tracer(
|
|
36
|
+
self, async_w3: "AsyncWeb3", txn_hash_with_log: HexStr
|
|
37
|
+
) -> None:
|
|
38
|
+
result = cast(
|
|
39
|
+
CallTrace,
|
|
40
|
+
await async_w3.geth.debug.trace_transaction(
|
|
41
|
+
txn_hash_with_log, {"tracer": "callTracer"}
|
|
42
|
+
),
|
|
43
|
+
)
|
|
44
|
+
assert result.get("type") == "CALL"
|
|
45
|
+
|
|
46
|
+
@pytest.mark.asyncio
|
|
47
|
+
async def test_async_geth_debug_trace_transaction_prestate_tracer_diffMode(
|
|
48
|
+
self, async_w3: "AsyncWeb3", txn_hash_with_log: HexStr
|
|
49
|
+
) -> None:
|
|
50
|
+
result = cast(
|
|
51
|
+
DiffModeTrace,
|
|
52
|
+
await async_w3.geth.debug.trace_transaction(
|
|
53
|
+
txn_hash_with_log,
|
|
54
|
+
{"tracer": "prestateTracer", "tracerConfig": {"diffMode": True}},
|
|
55
|
+
),
|
|
56
|
+
)
|
|
57
|
+
assert "post" in dict(result).keys()
|
|
58
|
+
assert "pre" in dict(result).keys()
|
|
59
|
+
|
|
60
|
+
@pytest.mark.asyncio
|
|
61
|
+
async def test_async_geth_debug_trace_transaction_prestate_tracer(
|
|
62
|
+
self,
|
|
63
|
+
async_w3: "AsyncWeb3",
|
|
64
|
+
txn_hash_with_log: HexStr,
|
|
65
|
+
async_block_with_txn_with_log: BlockData,
|
|
66
|
+
) -> None:
|
|
67
|
+
result = cast(
|
|
68
|
+
PrestateTrace,
|
|
69
|
+
await async_w3.geth.debug.trace_transaction(
|
|
70
|
+
txn_hash_with_log,
|
|
71
|
+
{"tracer": "prestateTracer"},
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
tx = await async_w3.eth.get_transaction(txn_hash_with_log)
|
|
75
|
+
from_addr: ChecksumAddress = tx["from"]
|
|
76
|
+
assert isinstance(result[from_addr].get("balance"), int)
|
|
77
|
+
assert "post" not in dict(result).keys()
|
|
78
|
+
assert "pre" not in dict(result).keys()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class GoEthereumDebugModuleTest:
|
|
82
|
+
def test_geth_debug_trace_transaction_opcode_logger(
|
|
83
|
+
self, w3: "Web3", txn_hash_with_log: HexStr
|
|
84
|
+
) -> None:
|
|
85
|
+
result = cast(OpcodeTrace, w3.geth.debug.trace_transaction(txn_hash_with_log))
|
|
86
|
+
assert "structLogs" in dict(result).keys()
|
|
87
|
+
assert "gas" in dict(result).keys()
|
|
88
|
+
assert "failed" in dict(result).keys()
|
|
89
|
+
|
|
90
|
+
def test_geth_debug_trace_transaction_call_tracer(
|
|
91
|
+
self, w3: "Web3", txn_hash_with_log: HexStr
|
|
92
|
+
) -> None:
|
|
93
|
+
result = cast(
|
|
94
|
+
CallTrace,
|
|
95
|
+
w3.geth.debug.trace_transaction(
|
|
96
|
+
txn_hash_with_log, {"tracer": "callTracer"}
|
|
97
|
+
),
|
|
98
|
+
)
|
|
99
|
+
assert result.get("type") == "CALL"
|
|
100
|
+
|
|
101
|
+
def test_geth_debug_trace_transaction_prestate_tracer_diffmode(
|
|
102
|
+
self, w3: "Web3", txn_hash_with_log: HexStr
|
|
103
|
+
) -> None:
|
|
104
|
+
result = cast(
|
|
105
|
+
DiffModeTrace,
|
|
106
|
+
w3.geth.debug.trace_transaction(
|
|
107
|
+
txn_hash_with_log,
|
|
108
|
+
{"tracer": "prestateTracer", "tracerConfig": {"diffMode": True}},
|
|
109
|
+
),
|
|
110
|
+
)
|
|
111
|
+
assert "post" in dict(result).keys()
|
|
112
|
+
assert "pre" in dict(result).keys()
|
|
113
|
+
|
|
114
|
+
def test_geth_debug_trace_transaction_prestate_tracer(
|
|
115
|
+
self, w3: "Web3", txn_hash_with_log: HexStr
|
|
116
|
+
) -> None:
|
|
117
|
+
result = cast(
|
|
118
|
+
PrestateTrace,
|
|
119
|
+
w3.geth.debug.trace_transaction(
|
|
120
|
+
txn_hash_with_log,
|
|
121
|
+
{"tracer": "prestateTracer"},
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
tx = w3.eth.get_transaction(txn_hash_with_log)
|
|
125
|
+
from_addr: ChecksumAddress = tx["from"]
|
|
126
|
+
assert isinstance(result[from_addr].get("balance"), int)
|
|
127
|
+
assert "post" not in dict(result).keys()
|
|
128
|
+
assert "pre" not in dict(result).keys()
|
web3/_utils/rpc_abi.py
CHANGED
|
@@ -48,6 +48,7 @@ class RPC:
|
|
|
48
48
|
|
|
49
49
|
# eth
|
|
50
50
|
eth_accounts = RPCEndpoint("eth_accounts")
|
|
51
|
+
eth_blobBaseFee = RPCEndpoint("eth_blobBaseFee")
|
|
51
52
|
eth_blockNumber = RPCEndpoint("eth_blockNumber")
|
|
52
53
|
eth_call = RPCEndpoint("eth_call")
|
|
53
54
|
eth_createAccessList = RPCEndpoint("eth_createAccessList")
|
|
@@ -140,6 +141,9 @@ class RPC:
|
|
|
140
141
|
# web3
|
|
141
142
|
web3_clientVersion = RPCEndpoint("web3_clientVersion")
|
|
142
143
|
|
|
144
|
+
# debug
|
|
145
|
+
debug_traceTransaction = RPCEndpoint("debug_traceTransaction")
|
|
146
|
+
|
|
143
147
|
|
|
144
148
|
TRANSACTION_PARAMS_ABIS = {
|
|
145
149
|
"data": "bytes",
|
web3/_utils/validation.py
CHANGED
|
@@ -79,6 +79,9 @@ def validate_abi(abi: ABI) -> None:
|
|
|
79
79
|
if not all(is_dict(e) for e in abi):
|
|
80
80
|
raise Web3ValueError("'abi' is not a list of dictionaries")
|
|
81
81
|
|
|
82
|
+
if not all("type" in e for e in abi):
|
|
83
|
+
raise Web3ValueError("'abi' must contain a list of elements each with a type")
|
|
84
|
+
|
|
82
85
|
functions = filter_abi_by_type("function", abi)
|
|
83
86
|
selectors = groupby(compose(encode_hex, function_abi_to_4byte_selector), functions)
|
|
84
87
|
duplicates = valfilter(lambda funcs: len(funcs) > 1, selectors)
|
web3/contract/async_contract.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import copy
|
|
2
1
|
from typing import (
|
|
3
2
|
TYPE_CHECKING,
|
|
4
3
|
Any,
|
|
@@ -21,7 +20,9 @@ from eth_utils import (
|
|
|
21
20
|
combomethod,
|
|
22
21
|
)
|
|
23
22
|
from eth_utils.abi import (
|
|
23
|
+
abi_to_signature,
|
|
24
24
|
get_abi_input_names,
|
|
25
|
+
get_abi_input_types,
|
|
25
26
|
get_all_function_abis,
|
|
26
27
|
)
|
|
27
28
|
from eth_utils.toolz import (
|
|
@@ -33,6 +34,9 @@ from hexbytes import (
|
|
|
33
34
|
|
|
34
35
|
from web3._utils.abi import (
|
|
35
36
|
fallback_func_abi_exists,
|
|
37
|
+
filter_by_types,
|
|
38
|
+
get_abi_element_signature,
|
|
39
|
+
get_name_from_abi_element_identifier,
|
|
36
40
|
receive_func_abi_exists,
|
|
37
41
|
)
|
|
38
42
|
from web3._utils.abi_element_identifiers import (
|
|
@@ -47,6 +51,8 @@ from web3._utils.compat import (
|
|
|
47
51
|
)
|
|
48
52
|
from web3._utils.contracts import (
|
|
49
53
|
async_parse_block_identifier,
|
|
54
|
+
copy_contract_event,
|
|
55
|
+
copy_contract_function,
|
|
50
56
|
)
|
|
51
57
|
from web3._utils.datatypes import (
|
|
52
58
|
PropertyCheckingFactory,
|
|
@@ -79,11 +85,15 @@ from web3.contract.utils import (
|
|
|
79
85
|
async_call_contract_function,
|
|
80
86
|
async_estimate_gas_for_function,
|
|
81
87
|
async_transact_with_contract_function,
|
|
88
|
+
find_events_by_identifier,
|
|
82
89
|
find_functions_by_identifier,
|
|
90
|
+
get_event_by_identifier,
|
|
83
91
|
get_function_by_identifier,
|
|
84
92
|
)
|
|
85
93
|
from web3.exceptions import (
|
|
94
|
+
ABIEventNotFound,
|
|
86
95
|
ABIFunctionNotFound,
|
|
96
|
+
NoABIEventsFound,
|
|
87
97
|
NoABIFound,
|
|
88
98
|
NoABIFunctionsFound,
|
|
89
99
|
Web3AttributeError,
|
|
@@ -97,6 +107,11 @@ from web3.types import (
|
|
|
97
107
|
StateOverride,
|
|
98
108
|
TxParams,
|
|
99
109
|
)
|
|
110
|
+
from web3.utils.abi import (
|
|
111
|
+
_get_any_abi_signature_with_name,
|
|
112
|
+
filter_abi_by_type,
|
|
113
|
+
get_abi_element,
|
|
114
|
+
)
|
|
100
115
|
|
|
101
116
|
if TYPE_CHECKING:
|
|
102
117
|
from ens import AsyncENS # noqa: F401
|
|
@@ -107,6 +122,28 @@ class AsyncContractEvent(BaseContractEvent):
|
|
|
107
122
|
# mypy types
|
|
108
123
|
w3: "AsyncWeb3"
|
|
109
124
|
|
|
125
|
+
def __call__(self, *args: Any, **kwargs: Any) -> "AsyncContractEvent":
|
|
126
|
+
event_abi = get_abi_element(
|
|
127
|
+
filter_abi_by_type("event", self.contract_abi),
|
|
128
|
+
self.name,
|
|
129
|
+
*args,
|
|
130
|
+
abi_codec=self.w3.codec,
|
|
131
|
+
**kwargs,
|
|
132
|
+
)
|
|
133
|
+
argument_types = get_abi_input_types(event_abi)
|
|
134
|
+
event_signature = str(
|
|
135
|
+
get_abi_element_signature(self.abi_element_identifier, argument_types)
|
|
136
|
+
)
|
|
137
|
+
contract_event = AsyncContractEvent.factory(
|
|
138
|
+
event_signature,
|
|
139
|
+
w3=self.w3,
|
|
140
|
+
contract_abi=self.contract_abi,
|
|
141
|
+
address=self.address,
|
|
142
|
+
abi_element_identifier=event_signature,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
return copy_contract_event(contract_event, *args, **kwargs)
|
|
146
|
+
|
|
110
147
|
@combomethod
|
|
111
148
|
async def get_logs(
|
|
112
149
|
self,
|
|
@@ -135,7 +172,7 @@ class AsyncContractEvent(BaseContractEvent):
|
|
|
135
172
|
from = max(mycontract.web3.eth.block_number - 10, 1)
|
|
136
173
|
to = mycontract.web3.eth.block_number
|
|
137
174
|
|
|
138
|
-
events = mycontract.events.Transfer.
|
|
175
|
+
events = mycontract.events.Transfer.get_logs(from_block=from, to_block=to)
|
|
139
176
|
|
|
140
177
|
for e in events:
|
|
141
178
|
print(e["args"]["from"],
|
|
@@ -171,11 +208,9 @@ class AsyncContractEvent(BaseContractEvent):
|
|
|
171
208
|
same time as ``from_block`` or ``to_block``
|
|
172
209
|
:yield: Tuple of :class:`AttributeDict` instances
|
|
173
210
|
"""
|
|
174
|
-
event_abi = self._get_event_abi()
|
|
175
|
-
|
|
176
211
|
# validate ``argument_filters`` if present
|
|
177
212
|
if argument_filters is not None:
|
|
178
|
-
event_arg_names = get_abi_input_names(
|
|
213
|
+
event_arg_names = get_abi_input_names(self.abi)
|
|
179
214
|
if not all(arg in event_arg_names for arg in argument_filters.keys()):
|
|
180
215
|
raise Web3ValidationError(
|
|
181
216
|
"When filtering by argument names, all argument names must be "
|
|
@@ -183,21 +218,23 @@ class AsyncContractEvent(BaseContractEvent):
|
|
|
183
218
|
)
|
|
184
219
|
|
|
185
220
|
_filter_params = self._get_event_filter_params(
|
|
186
|
-
|
|
221
|
+
self.abi, argument_filters, from_block, to_block, block_hash
|
|
187
222
|
)
|
|
188
223
|
# call JSON-RPC API
|
|
189
224
|
logs = await self.w3.eth.get_logs(_filter_params)
|
|
190
225
|
|
|
191
226
|
# convert raw binary data to Python proxy objects as described by ABI:
|
|
192
227
|
all_event_logs = tuple(
|
|
193
|
-
get_event_data(self.w3.codec,
|
|
228
|
+
get_event_data(self.w3.codec, self.abi, entry) for entry in logs
|
|
194
229
|
)
|
|
195
230
|
filtered_logs = self._process_get_logs_argument_filters(
|
|
196
|
-
|
|
231
|
+
self.abi,
|
|
197
232
|
all_event_logs,
|
|
198
233
|
argument_filters,
|
|
199
234
|
)
|
|
200
|
-
|
|
235
|
+
sorted_logs = sorted(filtered_logs, key=lambda e: e["logIndex"])
|
|
236
|
+
sorted_logs = sorted(sorted_logs, key=lambda e: e["blockNumber"])
|
|
237
|
+
return cast(Awaitable[Iterable[EventData]], sorted_logs)
|
|
201
238
|
|
|
202
239
|
@combomethod
|
|
203
240
|
async def create_filter(
|
|
@@ -212,7 +249,7 @@ class AsyncContractEvent(BaseContractEvent):
|
|
|
212
249
|
"""
|
|
213
250
|
Create filter object that tracks logs emitted by this contract event.
|
|
214
251
|
"""
|
|
215
|
-
filter_builder = AsyncEventFilterBuilder(self.
|
|
252
|
+
filter_builder = AsyncEventFilterBuilder(self.abi, self.w3.codec)
|
|
216
253
|
self._set_up_filter_builder(
|
|
217
254
|
argument_filters,
|
|
218
255
|
from_block,
|
|
@@ -222,9 +259,7 @@ class AsyncContractEvent(BaseContractEvent):
|
|
|
222
259
|
filter_builder,
|
|
223
260
|
)
|
|
224
261
|
log_filter = await filter_builder.deploy(self.w3)
|
|
225
|
-
log_filter.log_entry_formatter = get_event_data(
|
|
226
|
-
self.w3.codec, self._get_event_abi()
|
|
227
|
-
)
|
|
262
|
+
log_filter.log_entry_formatter = get_event_data(self.w3.codec, self.abi)
|
|
228
263
|
log_filter.builder = filter_builder
|
|
229
264
|
|
|
230
265
|
return log_filter
|
|
@@ -232,13 +267,17 @@ class AsyncContractEvent(BaseContractEvent):
|
|
|
232
267
|
@combomethod
|
|
233
268
|
def build_filter(self) -> AsyncEventFilterBuilder:
|
|
234
269
|
builder = AsyncEventFilterBuilder(
|
|
235
|
-
self.
|
|
270
|
+
self.abi,
|
|
236
271
|
self.w3.codec,
|
|
237
|
-
formatter=get_event_data(self.w3.codec, self.
|
|
272
|
+
formatter=get_event_data(self.w3.codec, self.abi),
|
|
238
273
|
)
|
|
239
274
|
builder.address = self.address
|
|
240
275
|
return builder
|
|
241
276
|
|
|
277
|
+
@classmethod
|
|
278
|
+
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
279
|
+
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
280
|
+
|
|
242
281
|
|
|
243
282
|
class AsyncContractEvents(BaseContractEvents):
|
|
244
283
|
def __init__(
|
|
@@ -246,28 +285,84 @@ class AsyncContractEvents(BaseContractEvents):
|
|
|
246
285
|
) -> None:
|
|
247
286
|
super().__init__(abi, w3, AsyncContractEvent, address)
|
|
248
287
|
|
|
288
|
+
def __iter__(self) -> Iterable["AsyncContractEvent"]:
|
|
289
|
+
if not hasattr(self, "_events") or not self._events:
|
|
290
|
+
return
|
|
291
|
+
|
|
292
|
+
for event in self._events:
|
|
293
|
+
yield self[abi_to_signature(event)]
|
|
294
|
+
|
|
295
|
+
def __getattr__(self, event_name: str) -> "AsyncContractEvent":
|
|
296
|
+
if super().__getattribute__("abi") is None:
|
|
297
|
+
raise NoABIFound(
|
|
298
|
+
"There is no ABI found for this contract.",
|
|
299
|
+
)
|
|
300
|
+
if "_events" not in self.__dict__ or len(self._events) == 0:
|
|
301
|
+
raise NoABIEventsFound(
|
|
302
|
+
"The abi for this contract contains no event definitions. ",
|
|
303
|
+
"Are you sure you provided the correct contract abi?",
|
|
304
|
+
)
|
|
305
|
+
elif get_name_from_abi_element_identifier(event_name) not in [
|
|
306
|
+
get_name_from_abi_element_identifier(event["name"])
|
|
307
|
+
for event in self._events
|
|
308
|
+
]:
|
|
309
|
+
raise ABIEventNotFound(
|
|
310
|
+
f"The event '{event_name}' was not found in this contract's abi. ",
|
|
311
|
+
"Are you sure you provided the correct contract abi?",
|
|
312
|
+
)
|
|
313
|
+
else:
|
|
314
|
+
event_abi = get_abi_element(self._events, event_name)
|
|
315
|
+
argument_types = get_abi_input_types(event_abi)
|
|
316
|
+
event_signature = str(get_abi_element_signature(event_name, argument_types))
|
|
317
|
+
return super().__getattribute__(event_signature)
|
|
318
|
+
|
|
319
|
+
def __getitem__(self, event_name: str) -> "AsyncContractEvent":
|
|
320
|
+
return getattr(self, event_name)
|
|
321
|
+
|
|
249
322
|
|
|
250
323
|
class AsyncContractFunction(BaseContractFunction):
|
|
251
324
|
# mypy types
|
|
252
325
|
w3: "AsyncWeb3"
|
|
253
326
|
|
|
254
327
|
def __call__(self, *args: Any, **kwargs: Any) -> "AsyncContractFunction":
|
|
255
|
-
|
|
256
|
-
if args
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
328
|
+
element_name = self.abi_element_identifier
|
|
329
|
+
if element_name in ["fallback", "receive"] or len(args) + len(kwargs):
|
|
330
|
+
# Use only the name if a fallback, receive function
|
|
331
|
+
# or when args/kwargs are present to find the proper element
|
|
332
|
+
element_name = self.fn_name
|
|
333
|
+
|
|
334
|
+
function_abi = get_abi_element(
|
|
335
|
+
filter_by_types(
|
|
336
|
+
["function", "constructor", "fallback", "receive"],
|
|
337
|
+
self.contract_abi,
|
|
338
|
+
),
|
|
339
|
+
element_name,
|
|
340
|
+
*args,
|
|
341
|
+
abi_codec=self.w3.codec,
|
|
342
|
+
**kwargs,
|
|
343
|
+
)
|
|
260
344
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
345
|
+
argument_types = None
|
|
346
|
+
if function_abi["type"] not in ["fallback", "receive"]:
|
|
347
|
+
argument_types = get_abi_input_types(function_abi)
|
|
348
|
+
|
|
349
|
+
function_signature = str(
|
|
350
|
+
get_abi_element_signature(self.abi_element_identifier, argument_types)
|
|
351
|
+
)
|
|
352
|
+
contract_function = AsyncContractFunction.factory(
|
|
353
|
+
function_signature,
|
|
354
|
+
w3=self.w3,
|
|
355
|
+
contract_abi=self.contract_abi,
|
|
356
|
+
address=self.address,
|
|
357
|
+
abi_element_identifier=function_signature,
|
|
358
|
+
decode_tuples=self.decode_tuples,
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
return copy_contract_function(contract_function, *args, **kwargs)
|
|
267
362
|
|
|
268
363
|
@classmethod
|
|
269
364
|
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
270
|
-
return PropertyCheckingFactory(class_name, (cls,), kwargs)(
|
|
365
|
+
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
271
366
|
|
|
272
367
|
async def call(
|
|
273
368
|
self,
|
|
@@ -307,11 +402,13 @@ class AsyncContractFunction(BaseContractFunction):
|
|
|
307
402
|
|
|
308
403
|
block_id = await async_parse_block_identifier(self.w3, block_identifier)
|
|
309
404
|
|
|
405
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
406
|
+
|
|
310
407
|
return await async_call_contract_function(
|
|
311
408
|
self.w3,
|
|
312
409
|
self.address,
|
|
313
410
|
self._return_data_normalizers,
|
|
314
|
-
|
|
411
|
+
abi_element_identifier,
|
|
315
412
|
call_transaction,
|
|
316
413
|
block_id,
|
|
317
414
|
self.contract_abi,
|
|
@@ -325,10 +422,11 @@ class AsyncContractFunction(BaseContractFunction):
|
|
|
325
422
|
|
|
326
423
|
async def transact(self, transaction: Optional[TxParams] = None) -> HexBytes:
|
|
327
424
|
setup_transaction = self._transact(transaction)
|
|
425
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
328
426
|
return await async_transact_with_contract_function(
|
|
329
427
|
self.address,
|
|
330
428
|
self.w3,
|
|
331
|
-
|
|
429
|
+
abi_element_identifier,
|
|
332
430
|
setup_transaction,
|
|
333
431
|
self.contract_abi,
|
|
334
432
|
self.abi,
|
|
@@ -343,10 +441,11 @@ class AsyncContractFunction(BaseContractFunction):
|
|
|
343
441
|
state_override: Optional[StateOverride] = None,
|
|
344
442
|
) -> int:
|
|
345
443
|
setup_transaction = self._estimate_gas(transaction)
|
|
444
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
346
445
|
return await async_estimate_gas_for_function(
|
|
347
446
|
self.address,
|
|
348
447
|
self.w3,
|
|
349
|
-
|
|
448
|
+
abi_element_identifier,
|
|
350
449
|
setup_transaction,
|
|
351
450
|
self.contract_abi,
|
|
352
451
|
self.abi,
|
|
@@ -360,10 +459,11 @@ class AsyncContractFunction(BaseContractFunction):
|
|
|
360
459
|
self, transaction: Optional[TxParams] = None
|
|
361
460
|
) -> TxParams:
|
|
362
461
|
built_transaction = self._build_transaction(transaction)
|
|
462
|
+
abi_element_identifier = abi_to_signature(self.abi)
|
|
363
463
|
return await async_build_transaction_for_function(
|
|
364
464
|
self.address,
|
|
365
465
|
self.w3,
|
|
366
|
-
|
|
466
|
+
abi_element_identifier,
|
|
367
467
|
built_transaction,
|
|
368
468
|
self.contract_abi,
|
|
369
469
|
self.abi,
|
|
@@ -414,23 +514,45 @@ class AsyncContractFunctions(BaseContractFunctions):
|
|
|
414
514
|
) -> None:
|
|
415
515
|
super().__init__(abi, w3, AsyncContractFunction, address, decode_tuples)
|
|
416
516
|
|
|
517
|
+
def __iter__(self) -> Iterable["AsyncContractFunction"]:
|
|
518
|
+
if not hasattr(self, "_functions") or not self._functions:
|
|
519
|
+
return
|
|
520
|
+
|
|
521
|
+
for func in self._functions:
|
|
522
|
+
yield self[abi_to_signature(func)]
|
|
523
|
+
|
|
417
524
|
def __getattr__(self, function_name: str) -> "AsyncContractFunction":
|
|
418
|
-
if
|
|
525
|
+
if super().__getattribute__("abi") is None:
|
|
419
526
|
raise NoABIFound(
|
|
420
527
|
"There is no ABI found for this contract.",
|
|
421
528
|
)
|
|
422
|
-
|
|
529
|
+
elif "_functions" not in self.__dict__ or len(self._functions) == 0:
|
|
423
530
|
raise NoABIFunctionsFound(
|
|
424
531
|
"The abi for this contract contains no function definitions. ",
|
|
425
532
|
"Are you sure you provided the correct contract abi?",
|
|
426
533
|
)
|
|
427
|
-
elif function_name not in
|
|
534
|
+
elif get_name_from_abi_element_identifier(function_name) not in [
|
|
535
|
+
get_name_from_abi_element_identifier(function["name"])
|
|
536
|
+
for function in self._functions
|
|
537
|
+
]:
|
|
428
538
|
raise ABIFunctionNotFound(
|
|
429
|
-
f"The function '{function_name}' was not found in this contract's
|
|
430
|
-
" Are you sure you provided the correct contract abi?",
|
|
539
|
+
f"The function '{function_name}' was not found in this contract's "
|
|
540
|
+
"abi. Are you sure you provided the correct contract abi?",
|
|
431
541
|
)
|
|
432
|
-
|
|
433
|
-
|
|
542
|
+
|
|
543
|
+
function_identifier = function_name
|
|
544
|
+
|
|
545
|
+
if "(" not in function_name:
|
|
546
|
+
function_identifier = _get_any_abi_signature_with_name(
|
|
547
|
+
function_name, self._functions
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
return super().__getattribute__(
|
|
551
|
+
function_identifier,
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
def __getitem__(self, function_name: str) -> "AsyncContractFunction":
|
|
555
|
+
return getattr(self, function_name)
|
|
434
556
|
|
|
435
557
|
|
|
436
558
|
class AsyncContract(BaseContract):
|
|
@@ -498,6 +620,16 @@ class AsyncContract(BaseContract):
|
|
|
498
620
|
normalizers=normalizers,
|
|
499
621
|
),
|
|
500
622
|
)
|
|
623
|
+
|
|
624
|
+
if contract.abi:
|
|
625
|
+
for abi in contract.abi:
|
|
626
|
+
abi_name = abi.get("name")
|
|
627
|
+
if abi_name in ["abi", "address"]:
|
|
628
|
+
raise Web3AttributeError(
|
|
629
|
+
f"Contract contains a reserved word `{abi_name}` "
|
|
630
|
+
f"and could not be instantiated."
|
|
631
|
+
)
|
|
632
|
+
|
|
501
633
|
contract.functions = AsyncContractFunctions(
|
|
502
634
|
contract.abi, contract.w3, decode_tuples=contract.decode_tuples
|
|
503
635
|
)
|
|
@@ -556,6 +688,24 @@ class AsyncContract(BaseContract):
|
|
|
556
688
|
) -> "AsyncContractFunction":
|
|
557
689
|
return get_function_by_identifier(fns, identifier)
|
|
558
690
|
|
|
691
|
+
@combomethod
|
|
692
|
+
def find_events_by_identifier(
|
|
693
|
+
cls,
|
|
694
|
+
contract_abi: ABI,
|
|
695
|
+
w3: "AsyncWeb3",
|
|
696
|
+
address: ChecksumAddress,
|
|
697
|
+
callable_check: Callable[..., Any],
|
|
698
|
+
) -> List["AsyncContractEvent"]:
|
|
699
|
+
return find_events_by_identifier(
|
|
700
|
+
contract_abi, w3, address, callable_check, AsyncContractEvent
|
|
701
|
+
)
|
|
702
|
+
|
|
703
|
+
@combomethod
|
|
704
|
+
def get_event_by_identifier(
|
|
705
|
+
cls, events: Sequence["AsyncContractEvent"], identifier: str
|
|
706
|
+
) -> "AsyncContractEvent":
|
|
707
|
+
return get_event_by_identifier(events, identifier)
|
|
708
|
+
|
|
559
709
|
|
|
560
710
|
class AsyncContractCaller(BaseContractCaller):
|
|
561
711
|
# mypy types
|
|
@@ -580,12 +730,12 @@ class AsyncContractCaller(BaseContractCaller):
|
|
|
580
730
|
self._functions = get_all_function_abis(self.abi)
|
|
581
731
|
|
|
582
732
|
for func in self._functions:
|
|
733
|
+
abi_signature = abi_to_signature(func)
|
|
583
734
|
fn = AsyncContractFunction.factory(
|
|
584
|
-
|
|
735
|
+
abi_signature,
|
|
585
736
|
w3=w3,
|
|
586
737
|
contract_abi=self.abi,
|
|
587
738
|
address=self.address,
|
|
588
|
-
abi_element_identifier=func["name"],
|
|
589
739
|
decode_tuples=decode_tuples,
|
|
590
740
|
)
|
|
591
741
|
|
|
@@ -597,7 +747,7 @@ class AsyncContractCaller(BaseContractCaller):
|
|
|
597
747
|
ccip_read_enabled=ccip_read_enabled,
|
|
598
748
|
)
|
|
599
749
|
|
|
600
|
-
setattr(self,
|
|
750
|
+
setattr(self, abi_signature, caller_method)
|
|
601
751
|
|
|
602
752
|
def __call__(
|
|
603
753
|
self,
|