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/_utils/encoding.py
CHANGED
|
@@ -55,6 +55,10 @@ from web3._utils.validation import (
|
|
|
55
55
|
from web3.datastructures import (
|
|
56
56
|
AttributeDict,
|
|
57
57
|
)
|
|
58
|
+
from web3.exceptions import (
|
|
59
|
+
Web3TypeError,
|
|
60
|
+
Web3ValueError,
|
|
61
|
+
)
|
|
58
62
|
|
|
59
63
|
|
|
60
64
|
def hex_encode_abi_type(
|
|
@@ -90,7 +94,7 @@ def hex_encode_abi_type(
|
|
|
90
94
|
elif is_string_type(abi_type):
|
|
91
95
|
return to_hex(text=value)
|
|
92
96
|
else:
|
|
93
|
-
raise
|
|
97
|
+
raise Web3ValueError(f"Unsupported ABI type: {abi_type}")
|
|
94
98
|
|
|
95
99
|
|
|
96
100
|
def to_hex_twos_compliment(value: Any, bit_size: int) -> HexStr:
|
|
@@ -169,7 +173,7 @@ def hexstr_if_str(
|
|
|
169
173
|
if isinstance(hexstr_or_primitive, str):
|
|
170
174
|
(primitive, hexstr) = (None, hexstr_or_primitive)
|
|
171
175
|
if remove_0x_prefix(HexStr(hexstr)) and not is_hex(hexstr):
|
|
172
|
-
raise
|
|
176
|
+
raise Web3ValueError(
|
|
173
177
|
"when sending a str, it must be a hex string. "
|
|
174
178
|
f"Got: {hexstr_or_primitive!r}"
|
|
175
179
|
)
|
|
@@ -210,12 +214,12 @@ class FriendlyJsonSerde:
|
|
|
210
214
|
except TypeError as full_exception:
|
|
211
215
|
if hasattr(obj, "items"):
|
|
212
216
|
item_errors = "; ".join(self._json_mapping_errors(obj))
|
|
213
|
-
raise
|
|
217
|
+
raise Web3TypeError(
|
|
214
218
|
f"dict had unencodable value at keys: {{{item_errors}}}"
|
|
215
219
|
)
|
|
216
220
|
elif is_list_like(obj):
|
|
217
221
|
element_errors = "; ".join(self._json_list_errors(obj))
|
|
218
|
-
raise
|
|
222
|
+
raise Web3TypeError(
|
|
219
223
|
f"list had unencodable value at index: [{element_errors}]"
|
|
220
224
|
)
|
|
221
225
|
else:
|
|
@@ -237,14 +241,16 @@ class FriendlyJsonSerde:
|
|
|
237
241
|
try:
|
|
238
242
|
return self._friendly_json_encode(obj, cls=cls)
|
|
239
243
|
except TypeError as exc:
|
|
240
|
-
raise
|
|
244
|
+
raise Web3TypeError(f"Could not encode to JSON: {exc}")
|
|
241
245
|
|
|
242
246
|
|
|
243
247
|
def to_4byte_hex(hex_or_str_or_bytes: Union[HexStr, str, bytes, int]) -> HexStr:
|
|
244
248
|
size_of_4bytes = 4 * 8
|
|
245
249
|
byte_str = hexstr_if_str(to_bytes, hex_or_str_or_bytes)
|
|
246
250
|
if len(byte_str) > 4:
|
|
247
|
-
raise
|
|
251
|
+
raise Web3ValueError(
|
|
252
|
+
f"expected value of size 4 bytes. Got: {len(byte_str)} bytes"
|
|
253
|
+
)
|
|
248
254
|
hex_str = encode_hex(byte_str)
|
|
249
255
|
return pad_hex(hex_str, size_of_4bytes)
|
|
250
256
|
|
|
@@ -253,7 +259,7 @@ class DynamicArrayPackedEncoder(BaseArrayEncoder):
|
|
|
253
259
|
is_dynamic = True
|
|
254
260
|
|
|
255
261
|
def encode(self, value: Sequence[Any]) -> bytes:
|
|
256
|
-
encoded_elements = self.encode_elements(value)
|
|
262
|
+
encoded_elements = self.encode_elements(value) # type: ignore[no-untyped-call]
|
|
257
263
|
encoded_value = encoded_elements
|
|
258
264
|
|
|
259
265
|
return encoded_value
|
|
@@ -272,10 +278,10 @@ def encode_single_packed(_type: TypeStr, value: Any) -> bytes:
|
|
|
272
278
|
)
|
|
273
279
|
|
|
274
280
|
abi_type = abi_type_parser.parse(_type)
|
|
275
|
-
if has_arrlist(_type):
|
|
281
|
+
if has_arrlist(_type): # type: ignore[no-untyped-call]
|
|
276
282
|
item_encoder = registry.get_encoder(abi_type.item_type.to_type_str())
|
|
277
283
|
if abi_type.arrlist[-1] != 1:
|
|
278
|
-
return DynamicArrayPackedEncoder(item_encoder=item_encoder).encode(value)
|
|
284
|
+
return DynamicArrayPackedEncoder(item_encoder=item_encoder).encode(value) # type: ignore[no-untyped-call] # noqa: E501
|
|
279
285
|
else:
|
|
280
286
|
raise NotImplementedError(
|
|
281
287
|
"Fixed arrays are not implemented in this packed encoder prototype"
|
|
@@ -291,9 +297,7 @@ class Web3JsonEncoder(json.JSONEncoder):
|
|
|
291
297
|
def default(self, obj: Any) -> Union[Dict[Any, Any], HexStr]:
|
|
292
298
|
if isinstance(obj, AttributeDict):
|
|
293
299
|
return obj.__dict__
|
|
294
|
-
elif isinstance(obj, HexBytes):
|
|
295
|
-
return HexStr(obj.hex())
|
|
296
|
-
elif isinstance(obj, bytes):
|
|
300
|
+
elif isinstance(obj, (HexBytes, bytes)):
|
|
297
301
|
return to_hex(obj)
|
|
298
302
|
return json.JSONEncoder.default(self, obj)
|
|
299
303
|
|
|
@@ -13,6 +13,7 @@ from web3.exceptions import (
|
|
|
13
13
|
ContractPanicError,
|
|
14
14
|
OffchainLookup,
|
|
15
15
|
TransactionIndexingInProgress,
|
|
16
|
+
Web3ValueError,
|
|
16
17
|
)
|
|
17
18
|
from web3.types import (
|
|
18
19
|
RPCResponse,
|
|
@@ -76,7 +77,9 @@ def _parse_error_with_reverted_prefix(data: str) -> str:
|
|
|
76
77
|
try:
|
|
77
78
|
error = bytes.fromhex(error).decode("utf8")
|
|
78
79
|
except UnicodeDecodeError:
|
|
79
|
-
warnings.warn(
|
|
80
|
+
warnings.warn(
|
|
81
|
+
"Could not decode revert reason as UTF-8", RuntimeWarning, stacklevel=2
|
|
82
|
+
)
|
|
80
83
|
raise ContractLogicError("execution reverted", data=data)
|
|
81
84
|
|
|
82
85
|
return error
|
|
@@ -140,7 +143,7 @@ def raise_contract_logic_error_on_revert(response: RPCResponse) -> RPCResponse:
|
|
|
140
143
|
"""
|
|
141
144
|
error = response.get("error")
|
|
142
145
|
if error is None or isinstance(error, str):
|
|
143
|
-
raise
|
|
146
|
+
raise Web3ValueError(error)
|
|
144
147
|
|
|
145
148
|
message = error.get("message")
|
|
146
149
|
message_present = message is not None and message != ""
|
|
@@ -172,7 +175,6 @@ def raise_transaction_indexing_error_if_indexing(response: RPCResponse) -> RPCRe
|
|
|
172
175
|
Raise an error if ``eth_getTransactionReceipt`` returns an error indicating that
|
|
173
176
|
transactions are still being indexed.
|
|
174
177
|
"""
|
|
175
|
-
|
|
176
178
|
error = response.get("error")
|
|
177
179
|
if not isinstance(error, str) and error is not None:
|
|
178
180
|
message = error.get("message")
|
web3/_utils/events.py
CHANGED
|
@@ -27,13 +27,16 @@ 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,
|
|
35
|
+
Primitives,
|
|
32
36
|
TypeStr,
|
|
33
37
|
)
|
|
34
38
|
from eth_utils import (
|
|
35
39
|
encode_hex,
|
|
36
|
-
event_abi_to_log_topic,
|
|
37
40
|
is_list_like,
|
|
38
41
|
keccak,
|
|
39
42
|
to_bytes,
|
|
@@ -41,6 +44,11 @@ from eth_utils import (
|
|
|
41
44
|
to_hex,
|
|
42
45
|
to_tuple,
|
|
43
46
|
)
|
|
47
|
+
from eth_utils.abi import (
|
|
48
|
+
collapse_if_tuple,
|
|
49
|
+
event_abi_to_log_topic,
|
|
50
|
+
get_abi_input_names,
|
|
51
|
+
)
|
|
44
52
|
from eth_utils.curried import (
|
|
45
53
|
apply_formatter_if,
|
|
46
54
|
)
|
|
@@ -56,7 +64,6 @@ import web3
|
|
|
56
64
|
from web3._utils.abi import (
|
|
57
65
|
exclude_indexed_event_inputs,
|
|
58
66
|
get_indexed_event_inputs,
|
|
59
|
-
get_normalized_abi_arg_type,
|
|
60
67
|
map_abi_data,
|
|
61
68
|
named_tree,
|
|
62
69
|
normalize_event_input_types,
|
|
@@ -74,18 +81,16 @@ from web3.datastructures import (
|
|
|
74
81
|
from web3.exceptions import (
|
|
75
82
|
InvalidEventABI,
|
|
76
83
|
LogTopicError,
|
|
77
|
-
|
|
84
|
+
Web3ValueError,
|
|
78
85
|
)
|
|
79
86
|
from web3.types import (
|
|
80
|
-
ABIEvent,
|
|
81
|
-
ABIEventParams,
|
|
82
87
|
BlockIdentifier,
|
|
83
88
|
EventData,
|
|
84
89
|
FilterParams,
|
|
85
90
|
LogReceipt,
|
|
86
91
|
)
|
|
87
|
-
from web3.utils import (
|
|
88
|
-
|
|
92
|
+
from web3.utils.abi import (
|
|
93
|
+
get_event_log_topics,
|
|
89
94
|
)
|
|
90
95
|
|
|
91
96
|
if TYPE_CHECKING:
|
|
@@ -99,16 +104,22 @@ if TYPE_CHECKING:
|
|
|
99
104
|
)
|
|
100
105
|
|
|
101
106
|
|
|
107
|
+
def _log_entry_data_to_bytes(
|
|
108
|
+
log_entry_data: Union[Primitives, HexStr, str],
|
|
109
|
+
) -> bytes:
|
|
110
|
+
return hexstr_if_str(to_bytes, log_entry_data)
|
|
111
|
+
|
|
112
|
+
|
|
102
113
|
def construct_event_topic_set(
|
|
103
114
|
event_abi: ABIEvent,
|
|
104
115
|
abi_codec: ABICodec,
|
|
105
|
-
arguments: Optional[Union[
|
|
116
|
+
arguments: Optional[Union[List[Any], Tuple[Any], Dict[str, Any]]] = None,
|
|
106
117
|
) -> List[HexStr]:
|
|
107
118
|
if arguments is None:
|
|
108
119
|
arguments = {}
|
|
109
|
-
|
|
120
|
+
elif isinstance(arguments, (list, tuple)):
|
|
110
121
|
if len(arguments) != len(event_abi["inputs"]):
|
|
111
|
-
raise
|
|
122
|
+
raise Web3ValueError(
|
|
112
123
|
"When passing an argument list, the number of arguments must "
|
|
113
124
|
"match the event constructor."
|
|
114
125
|
)
|
|
@@ -116,16 +127,12 @@ def construct_event_topic_set(
|
|
|
116
127
|
arg["name"]: [arg_value]
|
|
117
128
|
for arg, arg_value in zip(event_abi["inputs"], arguments)
|
|
118
129
|
}
|
|
119
|
-
|
|
120
130
|
normalized_args = {
|
|
121
131
|
key: value if is_list_like(value) else [value]
|
|
122
|
-
|
|
123
|
-
for key, value in arguments.items() # type: ignore
|
|
132
|
+
for key, value in arguments.items()
|
|
124
133
|
}
|
|
125
134
|
|
|
126
|
-
|
|
127
|
-
# https://github.com/python/mypy/issues/4976
|
|
128
|
-
event_topic = encode_hex(event_abi_to_log_topic(event_abi)) # type: ignore
|
|
135
|
+
event_topic = encode_hex(event_abi_to_log_topic(event_abi))
|
|
129
136
|
indexed_args = get_indexed_event_inputs(event_abi)
|
|
130
137
|
zipped_abi_and_args = [
|
|
131
138
|
(arg, normalized_args.get(arg["name"], [None])) for arg in indexed_args
|
|
@@ -155,7 +162,7 @@ def construct_event_data_set(
|
|
|
155
162
|
arguments = {}
|
|
156
163
|
if isinstance(arguments, (list, tuple)):
|
|
157
164
|
if len(arguments) != len(event_abi["inputs"]):
|
|
158
|
-
raise
|
|
165
|
+
raise Web3ValueError(
|
|
159
166
|
"When passing an argument list, the number of arguments must "
|
|
160
167
|
"match the event constructor."
|
|
161
168
|
)
|
|
@@ -200,7 +207,7 @@ def is_dynamic_sized_type(type_str: TypeStr) -> bool:
|
|
|
200
207
|
|
|
201
208
|
@to_tuple
|
|
202
209
|
def get_event_abi_types_for_decoding(
|
|
203
|
-
event_inputs: Sequence[
|
|
210
|
+
event_inputs: Sequence[Union[ABIComponent, ABIComponentIndexed]],
|
|
204
211
|
) -> Iterable[TypeStr]:
|
|
205
212
|
"""
|
|
206
213
|
Event logs use the `keccak(value)` for indexed inputs of type `bytes` or
|
|
@@ -208,10 +215,10 @@ def get_event_abi_types_for_decoding(
|
|
|
208
215
|
decode the log entries using the correct types.
|
|
209
216
|
"""
|
|
210
217
|
for input_abi in event_inputs:
|
|
211
|
-
if input_abi
|
|
218
|
+
if input_abi.get("indexed") and is_dynamic_sized_type(input_abi["type"]):
|
|
212
219
|
yield "bytes32"
|
|
213
220
|
else:
|
|
214
|
-
yield
|
|
221
|
+
yield collapse_if_tuple(input_abi)
|
|
215
222
|
|
|
216
223
|
|
|
217
224
|
@curry
|
|
@@ -224,31 +231,27 @@ def get_event_data(
|
|
|
224
231
|
Given an event ABI and a log entry for that event, return the decoded
|
|
225
232
|
event data
|
|
226
233
|
"""
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
elif not log_entry["topics"]:
|
|
230
|
-
raise MismatchedABI("Expected non-anonymous event to have 1 or more topics")
|
|
231
|
-
# type ignored b/c event_abi_to_log_topic(event_abi: Dict[str, Any])
|
|
232
|
-
elif event_abi_to_log_topic(event_abi) != log_entry["topics"][0]: # type: ignore
|
|
233
|
-
raise MismatchedABI("The event signature did not match the provided ABI")
|
|
234
|
-
else:
|
|
235
|
-
log_topics = log_entry["topics"][1:]
|
|
236
|
-
|
|
234
|
+
log_topics = get_event_log_topics(event_abi, log_entry["topics"])
|
|
235
|
+
log_topics_bytes = [_log_entry_data_to_bytes(topic) for topic in log_topics]
|
|
237
236
|
log_topics_abi = get_indexed_event_inputs(event_abi)
|
|
238
237
|
log_topic_normalized_inputs = normalize_event_input_types(log_topics_abi)
|
|
239
238
|
log_topic_types = get_event_abi_types_for_decoding(log_topic_normalized_inputs)
|
|
240
|
-
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
|
+
)
|
|
241
242
|
|
|
242
|
-
if len(
|
|
243
|
+
if len(log_topics_bytes) != len(log_topic_types):
|
|
243
244
|
raise LogTopicError(
|
|
244
|
-
f"Expected {len(log_topic_types)} log topics. Got {len(
|
|
245
|
+
f"Expected {len(log_topic_types)} log topics. Got {len(log_topics_bytes)}"
|
|
245
246
|
)
|
|
246
247
|
|
|
247
|
-
log_data =
|
|
248
|
+
log_data = _log_entry_data_to_bytes(log_entry["data"])
|
|
248
249
|
log_data_abi = exclude_indexed_event_inputs(event_abi)
|
|
249
250
|
log_data_normalized_inputs = normalize_event_input_types(log_data_abi)
|
|
250
251
|
log_data_types = get_event_abi_types_for_decoding(log_data_normalized_inputs)
|
|
251
|
-
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
|
+
)
|
|
252
255
|
|
|
253
256
|
# sanity check that there are not name intersections between the topic
|
|
254
257
|
# names and the data argument names.
|
|
@@ -270,7 +273,7 @@ def get_event_data(
|
|
|
270
273
|
|
|
271
274
|
decoded_topic_data = [
|
|
272
275
|
abi_codec.decode([topic_type], topic_data)[0]
|
|
273
|
-
for topic_type, topic_data in zip(log_topic_types,
|
|
276
|
+
for topic_type, topic_data in zip(log_topic_types, log_topics_bytes)
|
|
274
277
|
]
|
|
275
278
|
normalized_topic_data = map_abi_data(
|
|
276
279
|
BASE_RETURN_NORMALIZERS, log_topic_types, decoded_topic_data
|
|
@@ -332,8 +335,8 @@ is_not_indexed = complement(is_indexed)
|
|
|
332
335
|
|
|
333
336
|
class BaseEventFilterBuilder:
|
|
334
337
|
formatter = None
|
|
335
|
-
|
|
336
|
-
|
|
338
|
+
_from_block = None
|
|
339
|
+
_to_block = None
|
|
337
340
|
_address = None
|
|
338
341
|
_immutable = False
|
|
339
342
|
|
|
@@ -353,30 +356,30 @@ class BaseEventFilterBuilder:
|
|
|
353
356
|
self._ordered_arg_names = tuple(arg["name"] for arg in event_abi["inputs"])
|
|
354
357
|
|
|
355
358
|
@property
|
|
356
|
-
def
|
|
357
|
-
return self.
|
|
359
|
+
def from_block(self) -> BlockIdentifier:
|
|
360
|
+
return self._from_block
|
|
358
361
|
|
|
359
|
-
@
|
|
360
|
-
def
|
|
361
|
-
if self.
|
|
362
|
-
self.
|
|
362
|
+
@from_block.setter
|
|
363
|
+
def from_block(self, value: BlockIdentifier) -> None:
|
|
364
|
+
if self._from_block is None and not self._immutable:
|
|
365
|
+
self._from_block = value
|
|
363
366
|
else:
|
|
364
|
-
raise
|
|
365
|
-
f"
|
|
367
|
+
raise Web3ValueError(
|
|
368
|
+
f"from_block is already set to {self._from_block!r}. "
|
|
366
369
|
"Resetting filter parameters is not permitted"
|
|
367
370
|
)
|
|
368
371
|
|
|
369
372
|
@property
|
|
370
|
-
def
|
|
371
|
-
return self.
|
|
373
|
+
def to_block(self) -> BlockIdentifier:
|
|
374
|
+
return self._to_block
|
|
372
375
|
|
|
373
|
-
@
|
|
374
|
-
def
|
|
375
|
-
if self.
|
|
376
|
-
self.
|
|
376
|
+
@to_block.setter
|
|
377
|
+
def to_block(self, value: BlockIdentifier) -> None:
|
|
378
|
+
if self._to_block is None and not self._immutable:
|
|
379
|
+
self._to_block = value
|
|
377
380
|
else:
|
|
378
|
-
raise
|
|
379
|
-
f"toBlock is already set to {self.
|
|
381
|
+
raise Web3ValueError(
|
|
382
|
+
f"toBlock is already set to {self._to_block!r}. "
|
|
380
383
|
"Resetting filter parameters is not permitted"
|
|
381
384
|
)
|
|
382
385
|
|
|
@@ -389,7 +392,7 @@ class BaseEventFilterBuilder:
|
|
|
389
392
|
if self._address is None and not self._immutable:
|
|
390
393
|
self._address = value
|
|
391
394
|
else:
|
|
392
|
-
raise
|
|
395
|
+
raise Web3ValueError(
|
|
393
396
|
f"address is already set to {self.address!r}. "
|
|
394
397
|
"Resetting filter parameters is not permitted"
|
|
395
398
|
)
|
|
@@ -424,8 +427,8 @@ class BaseEventFilterBuilder:
|
|
|
424
427
|
def filter_params(self) -> FilterParams:
|
|
425
428
|
params = {
|
|
426
429
|
"topics": self.topics,
|
|
427
|
-
"fromBlock": self.
|
|
428
|
-
"toBlock": self.
|
|
430
|
+
"fromBlock": self.from_block,
|
|
431
|
+
"toBlock": self.to_block,
|
|
429
432
|
"address": self.address,
|
|
430
433
|
}
|
|
431
434
|
return valfilter(lambda x: x is not None, params)
|
|
@@ -434,10 +437,10 @@ class BaseEventFilterBuilder:
|
|
|
434
437
|
class EventFilterBuilder(BaseEventFilterBuilder):
|
|
435
438
|
def deploy(self, w3: "Web3") -> "LogFilter":
|
|
436
439
|
if not isinstance(w3, web3.Web3):
|
|
437
|
-
raise
|
|
440
|
+
raise Web3ValueError(f"Invalid web3 argument: got: {w3!r}")
|
|
438
441
|
|
|
439
|
-
for arg in
|
|
440
|
-
arg._immutable = True
|
|
442
|
+
for arg in self.args.values():
|
|
443
|
+
arg._immutable = True
|
|
441
444
|
self._immutable = True
|
|
442
445
|
|
|
443
446
|
log_filter = cast("LogFilter", w3.eth.filter(self.filter_params))
|
|
@@ -452,10 +455,10 @@ class EventFilterBuilder(BaseEventFilterBuilder):
|
|
|
452
455
|
class AsyncEventFilterBuilder(BaseEventFilterBuilder):
|
|
453
456
|
async def deploy(self, async_w3: "AsyncWeb3") -> "AsyncLogFilter":
|
|
454
457
|
if not isinstance(async_w3, web3.AsyncWeb3):
|
|
455
|
-
raise
|
|
458
|
+
raise Web3ValueError(f"Invalid web3 argument: got: {async_w3!r}")
|
|
456
459
|
|
|
457
|
-
for arg in
|
|
458
|
-
arg._immutable = True
|
|
460
|
+
for arg in self.args.values():
|
|
461
|
+
arg._immutable = True
|
|
459
462
|
self._immutable = True
|
|
460
463
|
|
|
461
464
|
log_filter = await async_w3.eth.filter(self.filter_params)
|
|
@@ -470,8 +473,7 @@ class AsyncEventFilterBuilder(BaseEventFilterBuilder):
|
|
|
470
473
|
|
|
471
474
|
def initialize_event_topics(event_abi: ABIEvent) -> Union[bytes, List[Any]]:
|
|
472
475
|
if event_abi["anonymous"] is False:
|
|
473
|
-
|
|
474
|
-
return event_abi_to_log_topic(event_abi) # type: ignore
|
|
476
|
+
return event_abi_to_log_topic(event_abi)
|
|
475
477
|
else:
|
|
476
478
|
return list()
|
|
477
479
|
|
|
@@ -483,12 +485,12 @@ def _build_argument_filters_from_event_abi(
|
|
|
483
485
|
for item in event_abi["inputs"]:
|
|
484
486
|
key = item["name"]
|
|
485
487
|
value: "BaseArgumentFilter"
|
|
486
|
-
if item
|
|
488
|
+
if item.get("indexed") is True:
|
|
487
489
|
value = TopicArgumentFilter(
|
|
488
|
-
abi_codec=abi_codec, arg_type=
|
|
490
|
+
abi_codec=abi_codec, arg_type=collapse_if_tuple(item)
|
|
489
491
|
)
|
|
490
492
|
else:
|
|
491
|
-
value = DataArgumentFilter(arg_type=
|
|
493
|
+
value = DataArgumentFilter(arg_type=collapse_if_tuple(item))
|
|
492
494
|
yield key, value
|
|
493
495
|
|
|
494
496
|
|
|
@@ -510,19 +512,23 @@ class BaseArgumentFilter(ABC):
|
|
|
510
512
|
|
|
511
513
|
def match_single(self, value: Any) -> None:
|
|
512
514
|
if self._immutable:
|
|
513
|
-
raise
|
|
515
|
+
raise Web3ValueError(
|
|
516
|
+
"Setting values is forbidden after filter is deployed."
|
|
517
|
+
)
|
|
514
518
|
if self._match_values is None:
|
|
515
519
|
self._match_values = _normalize_match_values((value,))
|
|
516
520
|
else:
|
|
517
|
-
raise
|
|
521
|
+
raise Web3ValueError("An argument match value/s has already been set.")
|
|
518
522
|
|
|
519
523
|
def match_any(self, *values: Collection[Any]) -> None:
|
|
520
524
|
if self._immutable:
|
|
521
|
-
raise
|
|
525
|
+
raise Web3ValueError(
|
|
526
|
+
"Setting values is forbidden after filter is deployed."
|
|
527
|
+
)
|
|
522
528
|
if self._match_values is None:
|
|
523
529
|
self._match_values = _normalize_match_values(values)
|
|
524
530
|
else:
|
|
525
|
-
raise
|
|
531
|
+
raise Web3ValueError("An argument match value/s has already been set.")
|
|
526
532
|
|
|
527
533
|
@property
|
|
528
534
|
@abstractmethod
|
web3/_utils/fee_utils.py
CHANGED
|
@@ -53,7 +53,5 @@ async def async_fee_history_priority_fee(async_eth: "AsyncEth") -> Wei:
|
|
|
53
53
|
# This is a tested internal call so no need for type hinting. We can keep
|
|
54
54
|
# better consistency between the sync and async calls by unpacking
|
|
55
55
|
# PRIORITY_FEE_HISTORY_PARAMS as constants here.
|
|
56
|
-
fee_history = await async_eth.fee_history(
|
|
57
|
-
*PRIORITY_FEE_HISTORY_PARAMS # type: ignore
|
|
58
|
-
)
|
|
56
|
+
fee_history = await async_eth.fee_history(*PRIORITY_FEE_HISTORY_PARAMS) # type: ignore # noqa: E501
|
|
59
57
|
return _fee_history_priority_fee_estimate(fee_history)
|
web3/_utils/filters.py
CHANGED
|
@@ -19,6 +19,7 @@ from eth_abi.grammar import (
|
|
|
19
19
|
parse as parse_type_string,
|
|
20
20
|
)
|
|
21
21
|
from eth_typing import (
|
|
22
|
+
ABIEvent,
|
|
22
23
|
ChecksumAddress,
|
|
23
24
|
HexStr,
|
|
24
25
|
TypeStr,
|
|
@@ -50,10 +51,11 @@ from web3._utils.validation import (
|
|
|
50
51
|
validate_address,
|
|
51
52
|
)
|
|
52
53
|
from web3.exceptions import (
|
|
54
|
+
Web3TypeError,
|
|
53
55
|
Web3ValidationError,
|
|
56
|
+
Web3ValueError,
|
|
54
57
|
)
|
|
55
58
|
from web3.types import (
|
|
56
|
-
ABIEvent,
|
|
57
59
|
BlockIdentifier,
|
|
58
60
|
FilterParams,
|
|
59
61
|
LogReceipt,
|
|
@@ -71,8 +73,8 @@ def construct_event_filter_params(
|
|
|
71
73
|
contract_address: Optional[ChecksumAddress] = None,
|
|
72
74
|
argument_filters: Optional[Dict[str, Any]] = None,
|
|
73
75
|
topics: Optional[Sequence[HexStr]] = None,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
from_block: Optional[BlockIdentifier] = None,
|
|
77
|
+
to_block: Optional[BlockIdentifier] = None,
|
|
76
78
|
address: Optional[ChecksumAddress] = None,
|
|
77
79
|
) -> Tuple[List[List[Optional[HexStr]]], FilterParams]:
|
|
78
80
|
filter_params: FilterParams = {}
|
|
@@ -82,17 +84,13 @@ def construct_event_filter_params(
|
|
|
82
84
|
|
|
83
85
|
if topics is not None:
|
|
84
86
|
if len(topic_set) > 1:
|
|
85
|
-
raise
|
|
87
|
+
raise Web3TypeError(
|
|
86
88
|
"Merging the topics argument with topics generated "
|
|
87
89
|
"from argument_filters is not supported."
|
|
88
90
|
)
|
|
89
91
|
topic_set = topics
|
|
90
92
|
|
|
91
|
-
|
|
92
|
-
# type ignored b/c list-like check on line 88
|
|
93
|
-
filter_params["topics"] = topic_set[0] # type: ignore
|
|
94
|
-
else:
|
|
95
|
-
filter_params["topics"] = topic_set
|
|
93
|
+
filter_params["topics"] = topic_set
|
|
96
94
|
|
|
97
95
|
if address and contract_address:
|
|
98
96
|
if is_list_like(address):
|
|
@@ -104,7 +102,7 @@ def construct_event_filter_params(
|
|
|
104
102
|
else [address]
|
|
105
103
|
)
|
|
106
104
|
else:
|
|
107
|
-
raise
|
|
105
|
+
raise Web3ValueError(
|
|
108
106
|
f"Unsupported type for `address` parameter: {type(address)}"
|
|
109
107
|
)
|
|
110
108
|
elif address:
|
|
@@ -120,11 +118,11 @@ def construct_event_filter_params(
|
|
|
120
118
|
else:
|
|
121
119
|
validate_address(filter_params["address"])
|
|
122
120
|
|
|
123
|
-
if
|
|
124
|
-
filter_params["fromBlock"] =
|
|
121
|
+
if from_block is not None:
|
|
122
|
+
filter_params["fromBlock"] = from_block
|
|
125
123
|
|
|
126
|
-
if
|
|
127
|
-
filter_params["toBlock"] =
|
|
124
|
+
if to_block is not None:
|
|
125
|
+
filter_params["toBlock"] = to_block
|
|
128
126
|
|
|
129
127
|
data_filters_set = construct_event_data_set(event_abi, abi_codec, argument_filters)
|
|
130
128
|
|
|
@@ -178,7 +176,7 @@ class BaseFilter:
|
|
|
178
176
|
class Filter(BaseFilter):
|
|
179
177
|
def __init__(self, filter_id: HexStr, eth_module: "Eth") -> None:
|
|
180
178
|
self.eth_module = eth_module
|
|
181
|
-
super(
|
|
179
|
+
super().__init__(filter_id)
|
|
182
180
|
|
|
183
181
|
def get_new_entries(self) -> List[LogReceipt]:
|
|
184
182
|
log_entries = self._filter_valid_entries(
|
|
@@ -196,7 +194,7 @@ class Filter(BaseFilter):
|
|
|
196
194
|
class AsyncFilter(BaseFilter):
|
|
197
195
|
def __init__(self, filter_id: HexStr, eth_module: "AsyncEth") -> None:
|
|
198
196
|
self.eth_module = eth_module
|
|
199
|
-
super(
|
|
197
|
+
super().__init__(filter_id)
|
|
200
198
|
|
|
201
199
|
async def get_new_entries(self) -> List[LogReceipt]:
|
|
202
200
|
filter_changes = await self.eth_module.get_filter_changes(self.filter_id)
|
|
@@ -250,7 +248,8 @@ class LogFilter(Filter):
|
|
|
250
248
|
def set_data_filters(
|
|
251
249
|
self, data_filter_set: Collection[Tuple[TypeStr, Any]]
|
|
252
250
|
) -> None:
|
|
253
|
-
"""
|
|
251
|
+
"""
|
|
252
|
+
Sets the data filters (non indexed argument filters)
|
|
254
253
|
|
|
255
254
|
Expects a set of tuples with the type and value, e.g.:
|
|
256
255
|
(('uint256', [12345, 54321]), ('string', ('a-single-string',)))
|
|
@@ -292,7 +291,8 @@ class AsyncLogFilter(AsyncFilter):
|
|
|
292
291
|
def set_data_filters(
|
|
293
292
|
self, data_filter_set: Collection[Tuple[TypeStr, Any]]
|
|
294
293
|
) -> None:
|
|
295
|
-
"""
|
|
294
|
+
"""
|
|
295
|
+
Sets the data filters (non indexed argument filters)
|
|
296
296
|
|
|
297
297
|
Expects a set of tuples with the type and value, e.g.:
|
|
298
298
|
(('uint256', [12345, 54321]), ('string', ('a-single-string',)))
|
|
@@ -318,7 +318,8 @@ normalize_to_text = apply_formatter_if(not_text, decode_utf8_bytes)
|
|
|
318
318
|
|
|
319
319
|
|
|
320
320
|
def normalize_data_values(type_string: TypeStr, data_value: Any) -> Any:
|
|
321
|
-
"""
|
|
321
|
+
"""
|
|
322
|
+
Decodes utf-8 bytes to strings for abi string values.
|
|
322
323
|
|
|
323
324
|
eth-abi v1 returns utf-8 bytes for string values.
|
|
324
325
|
This can be removed once eth-abi v2 is required.
|
|
@@ -326,7 +327,7 @@ def normalize_data_values(type_string: TypeStr, data_value: Any) -> Any:
|
|
|
326
327
|
_type = parse_type_string(type_string)
|
|
327
328
|
if _type.base == "string":
|
|
328
329
|
if _type.arrlist is not None:
|
|
329
|
-
return tuple(
|
|
330
|
+
return tuple(normalize_to_text(value) for value in data_value)
|
|
330
331
|
else:
|
|
331
332
|
return normalize_to_text(data_value)
|
|
332
333
|
return data_value
|
|
@@ -336,7 +337,8 @@ def normalize_data_values(type_string: TypeStr, data_value: Any) -> Any:
|
|
|
336
337
|
def match_fn(
|
|
337
338
|
codec: ABICodec, match_values_and_abi: Collection[Tuple[str, Any]], data: Any
|
|
338
339
|
) -> bool:
|
|
339
|
-
"""
|
|
340
|
+
"""
|
|
341
|
+
Match function used for filtering non-indexed event arguments.
|
|
340
342
|
|
|
341
343
|
Values provided through the match_values_and_abi parameter are
|
|
342
344
|
compared to the abi decoded log data.
|
|
@@ -352,7 +354,7 @@ def match_fn(
|
|
|
352
354
|
normalized_data = normalize_data_values(abi_type, data_value)
|
|
353
355
|
for value in match_values:
|
|
354
356
|
if not codec.is_encodable(abi_type, value):
|
|
355
|
-
raise
|
|
357
|
+
raise Web3ValueError(
|
|
356
358
|
f"Value {value} is of the wrong abi type. "
|
|
357
359
|
f"Expected {abi_type} typed value."
|
|
358
360
|
)
|
web3/_utils/formatters.py
CHANGED
|
@@ -114,13 +114,13 @@ def apply_key_map(
|
|
|
114
114
|
def is_array_of_strings(value: Any) -> bool:
|
|
115
115
|
if not is_list_like(value):
|
|
116
116
|
return False
|
|
117
|
-
return all(
|
|
117
|
+
return all(is_string(item) for item in value)
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
def is_array_of_dicts(value: Any) -> bool:
|
|
121
121
|
if not is_list_like(value):
|
|
122
122
|
return False
|
|
123
|
-
return all(
|
|
123
|
+
return all(is_dict(item) for item in value)
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
@curry
|
web3/_utils/http.py
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
DEFAULT_HTTP_TIMEOUT = 30.0
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def construct_user_agent(
|
|
5
|
+
module: str,
|
|
6
|
+
class_name: str,
|
|
7
|
+
) -> str:
|
|
2
8
|
from web3 import (
|
|
3
9
|
__version__ as web3_version,
|
|
4
10
|
)
|
|
5
11
|
|
|
6
|
-
return f"web3.py/{web3_version}/{
|
|
12
|
+
return f"web3.py/{web3_version}/{module}.{class_name}"
|