web3 7.0.0b8__py3-none-any.whl → 7.0.0b9__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 +16 -7
- ens/base_ens.py +3 -1
- ens/exceptions.py +2 -7
- ens/utils.py +0 -17
- web3/_utils/abi.py +100 -257
- web3/_utils/compat/__init__.py +1 -0
- web3/_utils/contracts.py +116 -205
- web3/_utils/encoding.py +4 -5
- web3/_utils/events.py +28 -33
- web3/_utils/fee_utils.py +2 -2
- web3/_utils/filters.py +2 -5
- web3/_utils/http_session_manager.py +30 -7
- web3/_utils/method_formatters.py +3 -3
- web3/_utils/module_testing/eth_module.py +59 -37
- web3/_utils/module_testing/module_testing_utils.py +43 -1
- web3/_utils/module_testing/persistent_connection_provider.py +2 -0
- web3/_utils/module_testing/web3_module.py +8 -8
- web3/_utils/normalizers.py +10 -8
- web3/_utils/validation.py +5 -7
- web3/contract/async_contract.py +18 -17
- web3/contract/base_contract.py +116 -80
- web3/contract/contract.py +16 -17
- web3/contract/utils.py +86 -55
- web3/eth/async_eth.py +1 -2
- web3/eth/eth.py +1 -2
- web3/exceptions.py +22 -9
- web3/gas_strategies/time_based.py +4 -0
- web3/manager.py +34 -12
- web3/middleware/filter.py +3 -3
- web3/middleware/signing.py +6 -1
- web3/types.py +5 -45
- web3/utils/__init__.py +48 -4
- web3/utils/abi.py +575 -10
- {web3-7.0.0b8.dist-info → web3-7.0.0b9.dist-info}/METADATA +7 -5
- {web3-7.0.0b8.dist-info → web3-7.0.0b9.dist-info}/RECORD +39 -44
- {web3-7.0.0b8.dist-info → web3-7.0.0b9.dist-info}/WHEEL +1 -1
- web3/tools/benchmark/__init__.py +0 -0
- web3/tools/benchmark/main.py +0 -190
- web3/tools/benchmark/node.py +0 -120
- web3/tools/benchmark/reporting.py +0 -39
- web3/tools/benchmark/utils.py +0 -69
- /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
- {web3-7.0.0b8.dist-info → web3-7.0.0b9.dist-info}/LICENSE +0 -0
- {web3-7.0.0b8.dist-info → web3-7.0.0b9.dist-info}/top_level.txt +0 -0
web3/_utils/contracts.py
CHANGED
|
@@ -4,10 +4,10 @@ from typing import (
|
|
|
4
4
|
Any,
|
|
5
5
|
Callable,
|
|
6
6
|
Dict,
|
|
7
|
+
List,
|
|
7
8
|
Optional,
|
|
8
9
|
Sequence,
|
|
9
10
|
Tuple,
|
|
10
|
-
Type,
|
|
11
11
|
Union,
|
|
12
12
|
cast,
|
|
13
13
|
)
|
|
@@ -19,6 +19,14 @@ from eth_abi.registry import (
|
|
|
19
19
|
registry as default_registry,
|
|
20
20
|
)
|
|
21
21
|
from eth_typing import (
|
|
22
|
+
ABI,
|
|
23
|
+
ABICallable,
|
|
24
|
+
ABIConstructor,
|
|
25
|
+
ABIElement,
|
|
26
|
+
ABIEvent,
|
|
27
|
+
ABIFallback,
|
|
28
|
+
ABIFunction,
|
|
29
|
+
ABIReceive,
|
|
22
30
|
ChecksumAddress,
|
|
23
31
|
HexStr,
|
|
24
32
|
TypeStr,
|
|
@@ -26,11 +34,9 @@ from eth_typing import (
|
|
|
26
34
|
from eth_utils import (
|
|
27
35
|
add_0x_prefix,
|
|
28
36
|
encode_hex,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
is_list_like,
|
|
33
|
-
is_text,
|
|
37
|
+
filter_abi_by_name,
|
|
38
|
+
filter_abi_by_type,
|
|
39
|
+
get_abi_input_types,
|
|
34
40
|
)
|
|
35
41
|
from eth_utils.toolz import (
|
|
36
42
|
pipe,
|
|
@@ -40,31 +46,20 @@ from hexbytes import (
|
|
|
40
46
|
)
|
|
41
47
|
|
|
42
48
|
from web3._utils.abi import (
|
|
43
|
-
abi_to_signature,
|
|
44
|
-
check_if_arguments_can_be_encoded,
|
|
45
|
-
filter_by_argument_count,
|
|
46
49
|
filter_by_argument_name,
|
|
47
|
-
filter_by_encodability,
|
|
48
|
-
filter_by_name,
|
|
49
|
-
filter_by_type,
|
|
50
|
-
get_abi_input_types,
|
|
51
|
-
get_aligned_abi_inputs,
|
|
52
|
-
get_fallback_func_abi,
|
|
53
|
-
get_receive_func_abi,
|
|
54
50
|
map_abi_data,
|
|
55
|
-
merge_args_and_kwargs,
|
|
56
51
|
named_tree,
|
|
57
52
|
)
|
|
53
|
+
from web3._utils.abi_element_identifiers import (
|
|
54
|
+
FallbackFn,
|
|
55
|
+
ReceiveFn,
|
|
56
|
+
)
|
|
58
57
|
from web3._utils.blocks import (
|
|
59
58
|
is_hex_encoded_block_hash,
|
|
60
59
|
)
|
|
61
60
|
from web3._utils.encoding import (
|
|
62
61
|
to_hex,
|
|
63
62
|
)
|
|
64
|
-
from web3._utils.function_identifiers import (
|
|
65
|
-
FallbackFn,
|
|
66
|
-
ReceiveFn,
|
|
67
|
-
)
|
|
68
63
|
from web3._utils.method_formatters import (
|
|
69
64
|
to_integer_if_hex,
|
|
70
65
|
)
|
|
@@ -81,13 +76,16 @@ from web3.exceptions import (
|
|
|
81
76
|
Web3ValueError,
|
|
82
77
|
)
|
|
83
78
|
from web3.types import (
|
|
84
|
-
|
|
85
|
-
ABIEvent,
|
|
86
|
-
ABIFunction,
|
|
79
|
+
ABIElementIdentifier,
|
|
87
80
|
BlockIdentifier,
|
|
88
81
|
BlockNumber,
|
|
89
82
|
TxParams,
|
|
90
83
|
)
|
|
84
|
+
from web3.utils.abi import (
|
|
85
|
+
check_if_arguments_can_be_encoded,
|
|
86
|
+
get_abi_element,
|
|
87
|
+
get_abi_element_info,
|
|
88
|
+
)
|
|
91
89
|
|
|
92
90
|
if TYPE_CHECKING:
|
|
93
91
|
from web3 import ( # noqa: F401
|
|
@@ -96,44 +94,22 @@ if TYPE_CHECKING:
|
|
|
96
94
|
)
|
|
97
95
|
|
|
98
96
|
|
|
99
|
-
def extract_argument_types(*args: Sequence[Any]) -> str:
|
|
100
|
-
"""
|
|
101
|
-
Takes a list of arguments and returns a string representation of the argument types,
|
|
102
|
-
appropriately collapsing `tuple` types into the respective nested types.
|
|
103
|
-
"""
|
|
104
|
-
collapsed_args = []
|
|
105
|
-
|
|
106
|
-
for arg in args:
|
|
107
|
-
if is_list_like(arg):
|
|
108
|
-
collapsed_nested = []
|
|
109
|
-
for nested in arg:
|
|
110
|
-
if is_list_like(nested):
|
|
111
|
-
collapsed_nested.append(f"({extract_argument_types(nested)})")
|
|
112
|
-
else:
|
|
113
|
-
collapsed_nested.append(_get_argument_readable_type(nested))
|
|
114
|
-
collapsed_args.append(",".join(collapsed_nested))
|
|
115
|
-
else:
|
|
116
|
-
collapsed_args.append(_get_argument_readable_type(arg))
|
|
117
|
-
|
|
118
|
-
return ",".join(collapsed_args)
|
|
119
|
-
|
|
120
|
-
|
|
121
97
|
def find_matching_event_abi(
|
|
122
98
|
abi: ABI,
|
|
123
99
|
event_name: Optional[str] = None,
|
|
124
100
|
argument_names: Optional[Sequence[str]] = None,
|
|
125
101
|
) -> ABIEvent:
|
|
126
|
-
filters = [
|
|
127
|
-
functools.partial(
|
|
102
|
+
filters: List[functools.partial[Sequence[ABIElement]]] = [
|
|
103
|
+
functools.partial(filter_abi_by_type, "event"),
|
|
128
104
|
]
|
|
129
105
|
|
|
130
106
|
if event_name is not None:
|
|
131
|
-
filters.append(functools.partial(
|
|
107
|
+
filters.append(functools.partial(filter_abi_by_name, event_name))
|
|
132
108
|
|
|
133
109
|
if argument_names is not None:
|
|
134
110
|
filters.append(functools.partial(filter_by_argument_name, argument_names))
|
|
135
111
|
|
|
136
|
-
event_abi_candidates = pipe(abi, *filters)
|
|
112
|
+
event_abi_candidates: Sequence[ABIEvent] = pipe(abi, *filters)
|
|
137
113
|
|
|
138
114
|
if len(event_abi_candidates) == 1:
|
|
139
115
|
return event_abi_candidates[0]
|
|
@@ -143,82 +119,24 @@ def find_matching_event_abi(
|
|
|
143
119
|
raise Web3ValueError("Multiple events found")
|
|
144
120
|
|
|
145
121
|
|
|
146
|
-
def find_matching_fn_abi(
|
|
147
|
-
abi: ABI,
|
|
148
|
-
abi_codec: ABICodec,
|
|
149
|
-
fn_identifier: Optional[Union[str, Type[FallbackFn], Type[ReceiveFn]]] = None,
|
|
150
|
-
args: Optional[Sequence[Any]] = None,
|
|
151
|
-
kwargs: Optional[Any] = None,
|
|
152
|
-
) -> ABIFunction:
|
|
153
|
-
args = args or tuple()
|
|
154
|
-
kwargs = kwargs or dict()
|
|
155
|
-
num_arguments = len(args) + len(kwargs)
|
|
156
|
-
|
|
157
|
-
if fn_identifier is FallbackFn:
|
|
158
|
-
return get_fallback_func_abi(abi)
|
|
159
|
-
|
|
160
|
-
if fn_identifier is ReceiveFn:
|
|
161
|
-
return get_receive_func_abi(abi)
|
|
162
|
-
|
|
163
|
-
if not is_text(fn_identifier):
|
|
164
|
-
raise Web3TypeError("Unsupported function identifier")
|
|
165
|
-
|
|
166
|
-
name_filter = functools.partial(filter_by_name, fn_identifier)
|
|
167
|
-
arg_count_filter = functools.partial(filter_by_argument_count, num_arguments)
|
|
168
|
-
encoding_filter = functools.partial(filter_by_encodability, abi_codec, args, kwargs)
|
|
169
|
-
|
|
170
|
-
function_candidates = pipe(abi, name_filter, arg_count_filter, encoding_filter)
|
|
171
|
-
|
|
172
|
-
if len(function_candidates) == 1:
|
|
173
|
-
return function_candidates[0]
|
|
174
|
-
else:
|
|
175
|
-
matching_identifiers = name_filter(abi)
|
|
176
|
-
matching_function_signatures = [
|
|
177
|
-
abi_to_signature(func) for func in matching_identifiers
|
|
178
|
-
]
|
|
179
|
-
|
|
180
|
-
arg_count_matches = len(arg_count_filter(matching_identifiers))
|
|
181
|
-
encoding_matches = len(encoding_filter(matching_identifiers))
|
|
182
|
-
|
|
183
|
-
if arg_count_matches == 0:
|
|
184
|
-
diagnosis = (
|
|
185
|
-
"\nFunction invocation failed due to improper number of arguments."
|
|
186
|
-
)
|
|
187
|
-
elif encoding_matches == 0:
|
|
188
|
-
diagnosis = (
|
|
189
|
-
"\nFunction invocation failed due to no matching argument types."
|
|
190
|
-
)
|
|
191
|
-
elif encoding_matches > 1:
|
|
192
|
-
diagnosis = (
|
|
193
|
-
"\nAmbiguous argument encoding. "
|
|
194
|
-
"Provided arguments can be encoded to multiple functions "
|
|
195
|
-
"matching this call."
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
collapsed_args = extract_argument_types(args)
|
|
199
|
-
collapsed_kwargs = dict(
|
|
200
|
-
{(k, extract_argument_types([v])) for k, v in kwargs.items()}
|
|
201
|
-
)
|
|
202
|
-
message = (
|
|
203
|
-
f"\nCould not identify the intended function with name `{fn_identifier}`, "
|
|
204
|
-
f"positional arguments with type(s) `{collapsed_args}` and "
|
|
205
|
-
f"keyword arguments with type(s) `{collapsed_kwargs}`."
|
|
206
|
-
f"\nFound {len(matching_identifiers)} function(s) with "
|
|
207
|
-
f"the name `{fn_identifier}`: {matching_function_signatures}{diagnosis}"
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
raise Web3ValidationError(message)
|
|
211
|
-
|
|
212
|
-
|
|
213
122
|
def encode_abi(
|
|
214
123
|
w3: Union["AsyncWeb3", "Web3"],
|
|
215
|
-
abi:
|
|
124
|
+
abi: ABIElement,
|
|
216
125
|
arguments: Sequence[Any],
|
|
217
126
|
data: Optional[HexStr] = None,
|
|
218
127
|
) -> HexStr:
|
|
219
|
-
argument_types =
|
|
220
|
-
|
|
221
|
-
|
|
128
|
+
argument_types = []
|
|
129
|
+
try:
|
|
130
|
+
argument_types = get_abi_input_types(abi)
|
|
131
|
+
except ValueError:
|
|
132
|
+
# Use the default argument_types if the abi doesn't have inputs
|
|
133
|
+
pass
|
|
134
|
+
|
|
135
|
+
if not check_if_arguments_can_be_encoded(
|
|
136
|
+
abi,
|
|
137
|
+
*arguments,
|
|
138
|
+
abi_codec=w3.codec,
|
|
139
|
+
):
|
|
222
140
|
raise Web3TypeError(
|
|
223
141
|
"One or more arguments could not be encoded to the necessary "
|
|
224
142
|
f"ABI type. Expected types are: {', '.join(argument_types)}"
|
|
@@ -250,25 +168,33 @@ def encode_abi(
|
|
|
250
168
|
def prepare_transaction(
|
|
251
169
|
address: ChecksumAddress,
|
|
252
170
|
w3: Union["AsyncWeb3", "Web3"],
|
|
253
|
-
|
|
171
|
+
abi_element_identifier: ABIElementIdentifier,
|
|
254
172
|
contract_abi: Optional[ABI] = None,
|
|
255
|
-
|
|
173
|
+
abi_callable: Optional[ABICallable] = None,
|
|
256
174
|
transaction: Optional[TxParams] = None,
|
|
257
175
|
fn_args: Optional[Sequence[Any]] = None,
|
|
258
176
|
fn_kwargs: Optional[Any] = None,
|
|
259
177
|
) -> TxParams:
|
|
260
178
|
"""
|
|
261
|
-
:parameter `is_function_abi` is used to distinguish function abi from contract abi
|
|
262
179
|
Returns a dictionary of the transaction that could be used to call this
|
|
263
180
|
TODO: make this a public API
|
|
264
181
|
TODO: add new prepare_deploy_transaction API
|
|
265
182
|
"""
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
183
|
+
fn_args = fn_args or []
|
|
184
|
+
fn_kwargs = fn_kwargs or {}
|
|
185
|
+
if abi_callable is None:
|
|
186
|
+
abi_callable = cast(
|
|
187
|
+
ABICallable,
|
|
188
|
+
get_abi_element(
|
|
189
|
+
contract_abi,
|
|
190
|
+
abi_element_identifier,
|
|
191
|
+
*fn_args,
|
|
192
|
+
abi_codec=w3.codec,
|
|
193
|
+
**fn_kwargs,
|
|
194
|
+
),
|
|
269
195
|
)
|
|
270
196
|
|
|
271
|
-
validate_payable(transaction,
|
|
197
|
+
validate_payable(transaction, abi_callable)
|
|
272
198
|
|
|
273
199
|
if transaction is None:
|
|
274
200
|
prepared_transaction: TxParams = {}
|
|
@@ -283,9 +209,9 @@ def prepare_transaction(
|
|
|
283
209
|
|
|
284
210
|
prepared_transaction["data"] = encode_transaction_data(
|
|
285
211
|
w3,
|
|
286
|
-
|
|
212
|
+
abi_element_identifier,
|
|
287
213
|
contract_abi,
|
|
288
|
-
|
|
214
|
+
abi_callable,
|
|
289
215
|
fn_args,
|
|
290
216
|
fn_kwargs,
|
|
291
217
|
)
|
|
@@ -294,34 +220,36 @@ def prepare_transaction(
|
|
|
294
220
|
|
|
295
221
|
def encode_transaction_data(
|
|
296
222
|
w3: Union["AsyncWeb3", "Web3"],
|
|
297
|
-
|
|
223
|
+
abi_element_identifier: ABIElementIdentifier,
|
|
298
224
|
contract_abi: Optional[ABI] = None,
|
|
299
|
-
|
|
225
|
+
abi_callable: Optional[ABICallable] = None,
|
|
300
226
|
args: Optional[Sequence[Any]] = None,
|
|
301
227
|
kwargs: Optional[Any] = None,
|
|
302
228
|
) -> HexStr:
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
229
|
+
info_abi: ABIElement
|
|
230
|
+
if abi_element_identifier is FallbackFn:
|
|
231
|
+
info_abi, info_selector, info_arguments = get_fallback_function_info(
|
|
232
|
+
contract_abi, cast(ABIFallback, abi_callable)
|
|
306
233
|
)
|
|
307
|
-
elif
|
|
308
|
-
|
|
309
|
-
contract_abi,
|
|
234
|
+
elif abi_element_identifier is ReceiveFn:
|
|
235
|
+
info_abi, info_selector, info_arguments = get_receive_function_info(
|
|
236
|
+
contract_abi, cast(ABIReceive, abi_callable)
|
|
310
237
|
)
|
|
311
|
-
elif
|
|
312
|
-
|
|
313
|
-
# type ignored b/c fn_id here is always str b/c FallbackFn is handled above
|
|
314
|
-
fn_identifier, # type: ignore
|
|
315
|
-
w3.codec,
|
|
238
|
+
elif isinstance(abi_element_identifier, str):
|
|
239
|
+
fn_info = get_abi_element_info(
|
|
316
240
|
contract_abi,
|
|
317
|
-
|
|
318
|
-
args,
|
|
319
|
-
|
|
241
|
+
abi_element_identifier,
|
|
242
|
+
*args,
|
|
243
|
+
abi_codec=w3.codec,
|
|
244
|
+
**kwargs,
|
|
320
245
|
)
|
|
246
|
+
info_abi = fn_info["abi"]
|
|
247
|
+
info_selector = fn_info["selector"]
|
|
248
|
+
info_arguments = fn_info["arguments"]
|
|
321
249
|
else:
|
|
322
250
|
raise Web3TypeError("Unsupported function identifier")
|
|
323
251
|
|
|
324
|
-
return add_0x_prefix(encode_abi(w3,
|
|
252
|
+
return add_0x_prefix(encode_abi(w3, info_abi, info_arguments, info_selector))
|
|
325
253
|
|
|
326
254
|
|
|
327
255
|
def decode_transaction_data(
|
|
@@ -329,85 +257,67 @@ def decode_transaction_data(
|
|
|
329
257
|
data: HexStr,
|
|
330
258
|
normalizers: Sequence[Callable[[TypeStr, Any], Tuple[TypeStr, Any]]] = None,
|
|
331
259
|
) -> Dict[str, Any]:
|
|
332
|
-
|
|
260
|
+
data_bytes = HexBytes(data)
|
|
333
261
|
types = get_abi_input_types(fn_abi)
|
|
334
262
|
abi_codec = ABICodec(default_registry)
|
|
335
|
-
decoded = abi_codec.decode(types,
|
|
263
|
+
decoded = abi_codec.decode(types, data_bytes[4:])
|
|
336
264
|
if normalizers:
|
|
337
265
|
decoded = map_abi_data(normalizers, types, decoded)
|
|
338
266
|
return named_tree(fn_abi["inputs"], decoded)
|
|
339
267
|
|
|
340
268
|
|
|
341
|
-
def
|
|
342
|
-
contract_abi: Optional[ABI] = None,
|
|
343
|
-
) -> Tuple[
|
|
344
|
-
if
|
|
345
|
-
|
|
269
|
+
def get_constructor_function_info(
|
|
270
|
+
contract_abi: Optional[ABI] = None, constructor_abi: Optional[ABIConstructor] = None
|
|
271
|
+
) -> Tuple[ABIConstructor, HexStr, Tuple[Any, ...]]:
|
|
272
|
+
if constructor_abi is None:
|
|
273
|
+
constructor_abi = cast(
|
|
274
|
+
ABIConstructor, get_abi_element(contract_abi, "constructor")
|
|
275
|
+
)
|
|
346
276
|
fn_selector = encode_hex(b"")
|
|
347
277
|
fn_arguments: Tuple[Any, ...] = tuple()
|
|
348
|
-
return
|
|
278
|
+
return constructor_abi, fn_selector, fn_arguments
|
|
349
279
|
|
|
350
280
|
|
|
351
|
-
def
|
|
352
|
-
contract_abi: Optional[ABI] = None,
|
|
353
|
-
) -> Tuple[
|
|
354
|
-
if
|
|
355
|
-
|
|
281
|
+
def get_fallback_function_info(
|
|
282
|
+
contract_abi: Optional[ABI] = None, fallback_abi: Optional[ABIFallback] = None
|
|
283
|
+
) -> Tuple[ABIFallback, HexStr, Tuple[Any, ...]]:
|
|
284
|
+
if fallback_abi is None:
|
|
285
|
+
fallback_abi = cast(ABIFallback, get_abi_element(contract_abi, "fallback"))
|
|
356
286
|
fn_selector = encode_hex(b"")
|
|
357
287
|
fn_arguments: Tuple[Any, ...] = tuple()
|
|
358
|
-
return
|
|
288
|
+
return fallback_abi, fn_selector, fn_arguments
|
|
359
289
|
|
|
360
290
|
|
|
361
|
-
def
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
if args is None:
|
|
370
|
-
args = tuple()
|
|
371
|
-
if kwargs is None:
|
|
372
|
-
kwargs = {}
|
|
373
|
-
|
|
374
|
-
if fn_abi is None:
|
|
375
|
-
fn_abi = find_matching_fn_abi(contract_abi, abi_codec, fn_name, args, kwargs)
|
|
376
|
-
|
|
377
|
-
fn_selector = encode_hex(function_abi_to_4byte_selector(fn_abi))
|
|
378
|
-
|
|
379
|
-
fn_arguments = merge_args_and_kwargs(fn_abi, args, kwargs)
|
|
380
|
-
|
|
381
|
-
_, aligned_fn_arguments = get_aligned_abi_inputs(fn_abi, fn_arguments)
|
|
382
|
-
|
|
383
|
-
return fn_abi, fn_selector, aligned_fn_arguments
|
|
291
|
+
def get_receive_function_info(
|
|
292
|
+
contract_abi: Optional[ABI] = None, receive_abi: Optional[ABIReceive] = None
|
|
293
|
+
) -> Tuple[ABIReceive, HexStr, Tuple[Any, ...]]:
|
|
294
|
+
if receive_abi is None:
|
|
295
|
+
receive_abi = cast(ABIReceive, get_abi_element(contract_abi, "receive"))
|
|
296
|
+
fn_selector = encode_hex(b"")
|
|
297
|
+
fn_arguments: Tuple[Any, ...] = tuple()
|
|
298
|
+
return receive_abi, fn_selector, fn_arguments
|
|
384
299
|
|
|
385
300
|
|
|
386
|
-
def validate_payable(transaction: TxParams,
|
|
301
|
+
def validate_payable(transaction: TxParams, abi_callable: ABICallable) -> None:
|
|
387
302
|
"""
|
|
388
303
|
Raise Web3ValidationError if non-zero ether
|
|
389
304
|
is sent to a non-payable function.
|
|
390
305
|
"""
|
|
391
|
-
if
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
def _get_argument_readable_type(arg: Any) -> str:
|
|
407
|
-
if is_checksum_address(arg) or is_binary_address(arg):
|
|
408
|
-
return "address"
|
|
409
|
-
|
|
410
|
-
return arg.__class__.__name__
|
|
306
|
+
if (
|
|
307
|
+
"value" in transaction
|
|
308
|
+
and to_integer_if_hex(transaction["value"]) != 0
|
|
309
|
+
and (
|
|
310
|
+
"payable" in abi_callable
|
|
311
|
+
and not abi_callable["payable"]
|
|
312
|
+
or "stateMutability" in abi_callable
|
|
313
|
+
and abi_callable["stateMutability"] == "nonpayable"
|
|
314
|
+
)
|
|
315
|
+
):
|
|
316
|
+
raise Web3ValidationError(
|
|
317
|
+
"Sending non-zero ether to a contract function "
|
|
318
|
+
"with payable=False. Please ensure that "
|
|
319
|
+
"transaction's value is 0."
|
|
320
|
+
)
|
|
411
321
|
|
|
412
322
|
|
|
413
323
|
def parse_block_identifier(
|
|
@@ -468,3 +378,4 @@ async def async_parse_block_identifier_int(
|
|
|
468
378
|
if block_num < 0:
|
|
469
379
|
raise BlockNumberOutOfRange
|
|
470
380
|
return BlockNumber(block_num)
|
|
381
|
+
return BlockNumber(block_num)
|
web3/_utils/encoding.py
CHANGED
|
@@ -255,12 +255,11 @@ def to_4byte_hex(hex_or_str_or_bytes: Union[HexStr, str, bytes, int]) -> HexStr:
|
|
|
255
255
|
return pad_hex(hex_str, size_of_4bytes)
|
|
256
256
|
|
|
257
257
|
|
|
258
|
-
|
|
259
|
-
class DynamicArrayPackedEncoder(BaseArrayEncoder): # type: ignore[misc]
|
|
258
|
+
class DynamicArrayPackedEncoder(BaseArrayEncoder):
|
|
260
259
|
is_dynamic = True
|
|
261
260
|
|
|
262
261
|
def encode(self, value: Sequence[Any]) -> bytes:
|
|
263
|
-
encoded_elements = self.encode_elements(value)
|
|
262
|
+
encoded_elements = self.encode_elements(value) # type: ignore[no-untyped-call]
|
|
264
263
|
encoded_value = encoded_elements
|
|
265
264
|
|
|
266
265
|
return encoded_value
|
|
@@ -279,10 +278,10 @@ def encode_single_packed(_type: TypeStr, value: Any) -> bytes:
|
|
|
279
278
|
)
|
|
280
279
|
|
|
281
280
|
abi_type = abi_type_parser.parse(_type)
|
|
282
|
-
if has_arrlist(_type):
|
|
281
|
+
if has_arrlist(_type): # type: ignore[no-untyped-call]
|
|
283
282
|
item_encoder = registry.get_encoder(abi_type.item_type.to_type_str())
|
|
284
283
|
if abi_type.arrlist[-1] != 1:
|
|
285
|
-
return DynamicArrayPackedEncoder(item_encoder=item_encoder).encode(value)
|
|
284
|
+
return DynamicArrayPackedEncoder(item_encoder=item_encoder).encode(value) # type: ignore[no-untyped-call] # noqa: E501
|
|
286
285
|
else:
|
|
287
286
|
raise NotImplementedError(
|
|
288
287
|
"Fixed arrays are not implemented in this packed encoder prototype"
|
web3/_utils/events.py
CHANGED
|
@@ -27,6 +27,9 @@ from eth_abi.codec import (
|
|
|
27
27
|
ABICodec,
|
|
28
28
|
)
|
|
29
29
|
from eth_typing import (
|
|
30
|
+
ABIComponent,
|
|
31
|
+
ABIComponentIndexed,
|
|
32
|
+
ABIEvent,
|
|
30
33
|
ChecksumAddress,
|
|
31
34
|
HexStr,
|
|
32
35
|
Primitives,
|
|
@@ -34,7 +37,6 @@ from eth_typing import (
|
|
|
34
37
|
)
|
|
35
38
|
from eth_utils import (
|
|
36
39
|
encode_hex,
|
|
37
|
-
event_abi_to_log_topic,
|
|
38
40
|
is_list_like,
|
|
39
41
|
keccak,
|
|
40
42
|
to_bytes,
|
|
@@ -42,6 +44,11 @@ from eth_utils import (
|
|
|
42
44
|
to_hex,
|
|
43
45
|
to_tuple,
|
|
44
46
|
)
|
|
47
|
+
from eth_utils.abi import (
|
|
48
|
+
collapse_if_tuple,
|
|
49
|
+
event_abi_to_log_topic,
|
|
50
|
+
get_abi_input_names,
|
|
51
|
+
)
|
|
45
52
|
from eth_utils.curried import (
|
|
46
53
|
apply_formatter_if,
|
|
47
54
|
)
|
|
@@ -57,7 +64,6 @@ import web3
|
|
|
57
64
|
from web3._utils.abi import (
|
|
58
65
|
exclude_indexed_event_inputs,
|
|
59
66
|
get_indexed_event_inputs,
|
|
60
|
-
get_normalized_abi_arg_type,
|
|
61
67
|
map_abi_data,
|
|
62
68
|
named_tree,
|
|
63
69
|
normalize_event_input_types,
|
|
@@ -75,19 +81,16 @@ from web3.datastructures import (
|
|
|
75
81
|
from web3.exceptions import (
|
|
76
82
|
InvalidEventABI,
|
|
77
83
|
LogTopicError,
|
|
78
|
-
MismatchedABI,
|
|
79
84
|
Web3ValueError,
|
|
80
85
|
)
|
|
81
86
|
from web3.types import (
|
|
82
|
-
ABIEvent,
|
|
83
|
-
ABIEventParams,
|
|
84
87
|
BlockIdentifier,
|
|
85
88
|
EventData,
|
|
86
89
|
FilterParams,
|
|
87
90
|
LogReceipt,
|
|
88
91
|
)
|
|
89
|
-
from web3.utils import (
|
|
90
|
-
|
|
92
|
+
from web3.utils.abi import (
|
|
93
|
+
get_event_log_topics,
|
|
91
94
|
)
|
|
92
95
|
|
|
93
96
|
if TYPE_CHECKING:
|
|
@@ -110,11 +113,11 @@ def _log_entry_data_to_bytes(
|
|
|
110
113
|
def construct_event_topic_set(
|
|
111
114
|
event_abi: ABIEvent,
|
|
112
115
|
abi_codec: ABICodec,
|
|
113
|
-
arguments: Optional[Union[
|
|
116
|
+
arguments: Optional[Union[List[Any], Tuple[Any], Dict[str, Any]]] = None,
|
|
114
117
|
) -> List[HexStr]:
|
|
115
118
|
if arguments is None:
|
|
116
119
|
arguments = {}
|
|
117
|
-
|
|
120
|
+
elif isinstance(arguments, (list, tuple)):
|
|
118
121
|
if len(arguments) != len(event_abi["inputs"]):
|
|
119
122
|
raise Web3ValueError(
|
|
120
123
|
"When passing an argument list, the number of arguments must "
|
|
@@ -124,11 +127,9 @@ def construct_event_topic_set(
|
|
|
124
127
|
arg["name"]: [arg_value]
|
|
125
128
|
for arg, arg_value in zip(event_abi["inputs"], arguments)
|
|
126
129
|
}
|
|
127
|
-
|
|
128
130
|
normalized_args = {
|
|
129
131
|
key: value if is_list_like(value) else [value]
|
|
130
|
-
|
|
131
|
-
for key, value in arguments.items() # type: ignore
|
|
132
|
+
for key, value in arguments.items()
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
event_topic = encode_hex(event_abi_to_log_topic(event_abi))
|
|
@@ -206,7 +207,7 @@ def is_dynamic_sized_type(type_str: TypeStr) -> bool:
|
|
|
206
207
|
|
|
207
208
|
@to_tuple
|
|
208
209
|
def get_event_abi_types_for_decoding(
|
|
209
|
-
event_inputs: Sequence[
|
|
210
|
+
event_inputs: Sequence[Union[ABIComponent, ABIComponentIndexed]],
|
|
210
211
|
) -> Iterable[TypeStr]:
|
|
211
212
|
"""
|
|
212
213
|
Event logs use the `keccak(value)` for indexed inputs of type `bytes` or
|
|
@@ -214,10 +215,10 @@ def get_event_abi_types_for_decoding(
|
|
|
214
215
|
decode the log entries using the correct types.
|
|
215
216
|
"""
|
|
216
217
|
for input_abi in event_inputs:
|
|
217
|
-
if input_abi
|
|
218
|
+
if input_abi.get("indexed") and is_dynamic_sized_type(input_abi["type"]):
|
|
218
219
|
yield "bytes32"
|
|
219
220
|
else:
|
|
220
|
-
yield
|
|
221
|
+
yield collapse_if_tuple(input_abi)
|
|
221
222
|
|
|
222
223
|
|
|
223
224
|
@curry
|
|
@@ -230,22 +231,14 @@ def get_event_data(
|
|
|
230
231
|
Given an event ABI and a log entry for that event, return the decoded
|
|
231
232
|
event data
|
|
232
233
|
"""
|
|
233
|
-
|
|
234
|
-
log_topics = log_entry["topics"]
|
|
235
|
-
elif not log_entry["topics"]:
|
|
236
|
-
raise MismatchedABI("Expected non-anonymous event to have 1 or more topics")
|
|
237
|
-
elif event_abi_to_log_topic(dict(event_abi)) != _log_entry_data_to_bytes(
|
|
238
|
-
log_entry["topics"][0]
|
|
239
|
-
):
|
|
240
|
-
raise MismatchedABI("The event signature did not match the provided ABI")
|
|
241
|
-
else:
|
|
242
|
-
log_topics = log_entry["topics"][1:]
|
|
243
|
-
|
|
234
|
+
log_topics = get_event_log_topics(event_abi, log_entry["topics"])
|
|
244
235
|
log_topics_bytes = [_log_entry_data_to_bytes(topic) for topic in log_topics]
|
|
245
236
|
log_topics_abi = get_indexed_event_inputs(event_abi)
|
|
246
237
|
log_topic_normalized_inputs = normalize_event_input_types(log_topics_abi)
|
|
247
238
|
log_topic_types = get_event_abi_types_for_decoding(log_topic_normalized_inputs)
|
|
248
|
-
log_topic_names = get_abi_input_names(
|
|
239
|
+
log_topic_names = get_abi_input_names(
|
|
240
|
+
ABIEvent({"name": event_abi["name"], "type": "event", "inputs": log_topics_abi})
|
|
241
|
+
)
|
|
249
242
|
|
|
250
243
|
if len(log_topics_bytes) != len(log_topic_types):
|
|
251
244
|
raise LogTopicError(
|
|
@@ -256,7 +249,9 @@ def get_event_data(
|
|
|
256
249
|
log_data_abi = exclude_indexed_event_inputs(event_abi)
|
|
257
250
|
log_data_normalized_inputs = normalize_event_input_types(log_data_abi)
|
|
258
251
|
log_data_types = get_event_abi_types_for_decoding(log_data_normalized_inputs)
|
|
259
|
-
log_data_names = get_abi_input_names(
|
|
252
|
+
log_data_names = get_abi_input_names(
|
|
253
|
+
ABIEvent({"name": event_abi["name"], "type": "event", "inputs": log_data_abi})
|
|
254
|
+
)
|
|
260
255
|
|
|
261
256
|
# sanity check that there are not name intersections between the topic
|
|
262
257
|
# names and the data argument names.
|
|
@@ -462,8 +457,8 @@ class AsyncEventFilterBuilder(BaseEventFilterBuilder):
|
|
|
462
457
|
if not isinstance(async_w3, web3.AsyncWeb3):
|
|
463
458
|
raise Web3ValueError(f"Invalid web3 argument: got: {async_w3!r}")
|
|
464
459
|
|
|
465
|
-
for arg in
|
|
466
|
-
arg._immutable = True
|
|
460
|
+
for arg in self.args.values():
|
|
461
|
+
arg._immutable = True
|
|
467
462
|
self._immutable = True
|
|
468
463
|
|
|
469
464
|
log_filter = await async_w3.eth.filter(self.filter_params)
|
|
@@ -490,12 +485,12 @@ def _build_argument_filters_from_event_abi(
|
|
|
490
485
|
for item in event_abi["inputs"]:
|
|
491
486
|
key = item["name"]
|
|
492
487
|
value: "BaseArgumentFilter"
|
|
493
|
-
if item
|
|
488
|
+
if item.get("indexed") is True:
|
|
494
489
|
value = TopicArgumentFilter(
|
|
495
|
-
abi_codec=abi_codec, arg_type=
|
|
490
|
+
abi_codec=abi_codec, arg_type=collapse_if_tuple(item)
|
|
496
491
|
)
|
|
497
492
|
else:
|
|
498
|
-
value = DataArgumentFilter(arg_type=
|
|
493
|
+
value = DataArgumentFilter(arg_type=collapse_if_tuple(item))
|
|
499
494
|
yield key, value
|
|
500
495
|
|
|
501
496
|
|