faster-eth-abi 5.2.3__cp310-cp310-win_amd64.whl → 5.2.20__cp310-cp310-win_amd64.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.
Potentially problematic release.
This version of faster-eth-abi might be problematic. Click here for more details.
- faster_eth_abi/_codec.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/_codec.py +83 -0
- faster_eth_abi/_decoding.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/_decoding.py +299 -0
- faster_eth_abi/_encoding.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/_encoding.py +251 -0
- faster_eth_abi/_grammar.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/_grammar.py +375 -0
- faster_eth_abi/abi.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/base.py +5 -1
- faster_eth_abi/codec.py +2694 -52
- faster_eth_abi/constants.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/decoding.py +263 -242
- faster_eth_abi/encoding.py +201 -154
- faster_eth_abi/exceptions.py +26 -14
- faster_eth_abi/from_type_str.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/from_type_str.py +7 -1
- faster_eth_abi/grammar.py +30 -325
- faster_eth_abi/io.py +5 -1
- faster_eth_abi/packed.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/packed.py +4 -0
- faster_eth_abi/registry.py +201 -83
- faster_eth_abi/tools/__init__.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/tools/_strategies.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/tools/_strategies.py +12 -6
- faster_eth_abi/typing.py +4627 -0
- faster_eth_abi/utils/__init__.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/utils/numeric.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/utils/numeric.py +51 -20
- faster_eth_abi/utils/padding.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/utils/string.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/utils/validation.cp310-win_amd64.pyd +0 -0
- faster_eth_abi/utils/validation.py +1 -5
- faster_eth_abi-5.2.20.dist-info/METADATA +136 -0
- faster_eth_abi-5.2.20.dist-info/RECORD +46 -0
- faster_eth_abi-5.2.20.dist-info/top_level.txt +2 -0
- faster_eth_abi__mypyc.cp310-win_amd64.pyd +0 -0
- a1f8aa123fabc88e2b56__mypyc.cp310-win_amd64.pyd +0 -0
- faster_eth_abi-5.2.3.dist-info/METADATA +0 -95
- faster_eth_abi-5.2.3.dist-info/RECORD +0 -38
- faster_eth_abi-5.2.3.dist-info/licenses/LICENSE +0 -21
- faster_eth_abi-5.2.3.dist-info/top_level.txt +0 -3
- {faster_eth_abi-5.2.3.dist-info → faster_eth_abi-5.2.20.dist-info}/WHEEL +0 -0
faster_eth_abi/encoding.py
CHANGED
|
@@ -1,18 +1,32 @@
|
|
|
1
|
+
"""Classes for ABI encoding logic.
|
|
2
|
+
|
|
3
|
+
Implements classes and functions for serializing Python values into binary data
|
|
4
|
+
according to ABI type specifications.
|
|
5
|
+
"""
|
|
1
6
|
import abc
|
|
2
7
|
import codecs
|
|
3
8
|
import decimal
|
|
4
|
-
from
|
|
5
|
-
|
|
9
|
+
from functools import (
|
|
10
|
+
cached_property,
|
|
11
|
+
lru_cache,
|
|
12
|
+
)
|
|
13
|
+
from types import (
|
|
14
|
+
MethodType,
|
|
6
15
|
)
|
|
7
16
|
from typing import (
|
|
8
17
|
Any,
|
|
18
|
+
Callable,
|
|
19
|
+
ClassVar,
|
|
20
|
+
Final,
|
|
21
|
+
NoReturn,
|
|
9
22
|
Optional,
|
|
23
|
+
Sequence,
|
|
10
24
|
Tuple,
|
|
11
25
|
Type,
|
|
26
|
+
final,
|
|
12
27
|
)
|
|
13
28
|
|
|
14
29
|
from faster_eth_utils import (
|
|
15
|
-
int_to_big_endian,
|
|
16
30
|
is_address,
|
|
17
31
|
is_boolean,
|
|
18
32
|
is_bytes,
|
|
@@ -22,7 +36,22 @@ from faster_eth_utils import (
|
|
|
22
36
|
is_text,
|
|
23
37
|
to_canonical_address,
|
|
24
38
|
)
|
|
39
|
+
from typing_extensions import (
|
|
40
|
+
Self,
|
|
41
|
+
)
|
|
25
42
|
|
|
43
|
+
from faster_eth_abi._encoding import (
|
|
44
|
+
encode_elements,
|
|
45
|
+
encode_elements_dynamic,
|
|
46
|
+
encode_fixed,
|
|
47
|
+
encode_signed,
|
|
48
|
+
encode_tuple,
|
|
49
|
+
encode_tuple_all_dynamic,
|
|
50
|
+
encode_tuple_no_dynamic,
|
|
51
|
+
encode_tuple_no_dynamic_funcs,
|
|
52
|
+
int_to_big_endian,
|
|
53
|
+
validate_tuple,
|
|
54
|
+
)
|
|
26
55
|
from faster_eth_abi.base import (
|
|
27
56
|
BaseCoder,
|
|
28
57
|
)
|
|
@@ -45,8 +74,6 @@ from faster_eth_abi.utils.numeric import (
|
|
|
45
74
|
compute_unsigned_integer_bounds,
|
|
46
75
|
)
|
|
47
76
|
from faster_eth_abi.utils.padding import (
|
|
48
|
-
fpad,
|
|
49
|
-
zpad,
|
|
50
77
|
zpad_right,
|
|
51
78
|
)
|
|
52
79
|
from faster_eth_abi.utils.string import (
|
|
@@ -69,7 +96,7 @@ class BaseEncoder(BaseCoder, metaclass=abc.ABCMeta):
|
|
|
69
96
|
"""
|
|
70
97
|
|
|
71
98
|
@abc.abstractmethod
|
|
72
|
-
def validate_value(self, value: Any) -> None:
|
|
99
|
+
def validate_value(self, value: Any) -> None:
|
|
73
100
|
"""
|
|
74
101
|
Checks whether or not the given value can be encoded by this encoder.
|
|
75
102
|
If the given value cannot be encoded, must raise
|
|
@@ -82,7 +109,7 @@ class BaseEncoder(BaseCoder, metaclass=abc.ABCMeta):
|
|
|
82
109
|
value: Any,
|
|
83
110
|
exc: Type[Exception] = EncodingTypeError,
|
|
84
111
|
msg: Optional[str] = None,
|
|
85
|
-
) ->
|
|
112
|
+
) -> NoReturn:
|
|
86
113
|
"""
|
|
87
114
|
Throws a standard exception for when a value is not encodable by an
|
|
88
115
|
encoder.
|
|
@@ -102,57 +129,51 @@ class TupleEncoder(BaseEncoder):
|
|
|
102
129
|
def __init__(self, encoders: Tuple[BaseEncoder, ...], **kwargs: Any) -> None:
|
|
103
130
|
super().__init__(encoders=encoders, **kwargs)
|
|
104
131
|
|
|
105
|
-
self.
|
|
132
|
+
self._is_dynamic: Final = tuple(
|
|
133
|
+
getattr(e, "is_dynamic", False) for e in self.encoders
|
|
134
|
+
)
|
|
135
|
+
self.is_dynamic = any(self._is_dynamic)
|
|
106
136
|
|
|
107
|
-
|
|
137
|
+
validators = []
|
|
138
|
+
for encoder in self.encoders:
|
|
139
|
+
try:
|
|
140
|
+
validator = encoder.validate_value
|
|
141
|
+
except AttributeError:
|
|
142
|
+
validators.append(encoder)
|
|
143
|
+
else:
|
|
144
|
+
validators.append(validator)
|
|
145
|
+
|
|
146
|
+
self.validators: Final[Callable[[Any], None]] = tuple(validators)
|
|
147
|
+
|
|
148
|
+
if type(self).encode is TupleEncoder.encode:
|
|
149
|
+
encode_func = (
|
|
150
|
+
encode_tuple_all_dynamic
|
|
151
|
+
if all(self._is_dynamic)
|
|
152
|
+
else encode_tuple_no_dynamic_funcs.get(
|
|
153
|
+
len(self.encoders),
|
|
154
|
+
encode_tuple_no_dynamic,
|
|
155
|
+
)
|
|
156
|
+
if not self.is_dynamic
|
|
157
|
+
else encode_tuple
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
self.encode = MethodType(encode_func, self)
|
|
161
|
+
|
|
162
|
+
def validate(self) -> None:
|
|
108
163
|
super().validate()
|
|
109
164
|
|
|
110
165
|
if self.encoders is None:
|
|
111
166
|
raise ValueError("`encoders` may not be none")
|
|
112
167
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
value,
|
|
117
|
-
msg="must be list-like object such as array or tuple",
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
if len(value) != len(self.encoders):
|
|
121
|
-
self.invalidate_value(
|
|
122
|
-
value,
|
|
123
|
-
exc=ValueOutOfBounds,
|
|
124
|
-
msg=f"value has {len(value)} items when {len(self.encoders)} "
|
|
125
|
-
"were expected",
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
for item, encoder in zip(value, self.encoders):
|
|
129
|
-
try:
|
|
130
|
-
encoder.validate_value(item)
|
|
131
|
-
except AttributeError:
|
|
132
|
-
encoder(item)
|
|
133
|
-
|
|
134
|
-
def encode(self, values):
|
|
135
|
-
self.validate_value(values)
|
|
168
|
+
@final
|
|
169
|
+
def validate_value(self, value: Sequence[Any]) -> None:
|
|
170
|
+
validate_tuple(self, value)
|
|
136
171
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
for value, encoder in zip(values, self.encoders):
|
|
140
|
-
if getattr(encoder, "is_dynamic", False):
|
|
141
|
-
raw_head_chunks.append(None)
|
|
142
|
-
tail_chunks.append(encoder(value))
|
|
143
|
-
else:
|
|
144
|
-
raw_head_chunks.append(encoder(value))
|
|
145
|
-
tail_chunks.append(b"")
|
|
146
|
-
|
|
147
|
-
head_length = sum(32 if item is None else len(item) for item in raw_head_chunks)
|
|
148
|
-
tail_offsets = (0,) + tuple(accumulate(map(len, tail_chunks[:-1])))
|
|
149
|
-
head_chunks = tuple(
|
|
150
|
-
encode_uint_256(head_length + offset) if chunk is None else chunk
|
|
151
|
-
for chunk, offset in zip(raw_head_chunks, tail_offsets)
|
|
152
|
-
)
|
|
172
|
+
def encode(self, values: Sequence[Any]) -> bytes:
|
|
173
|
+
return encode_tuple(self, values)
|
|
153
174
|
|
|
154
|
-
|
|
155
|
-
return
|
|
175
|
+
def __call__(self, values: Sequence[Any]) -> bytes:
|
|
176
|
+
return self.encode(values)
|
|
156
177
|
|
|
157
178
|
@parse_tuple_type_str
|
|
158
179
|
def from_type_str(cls, abi_type, registry):
|
|
@@ -170,42 +191,39 @@ class FixedSizeEncoder(BaseEncoder):
|
|
|
170
191
|
type_check_fn = None
|
|
171
192
|
is_big_endian = None
|
|
172
193
|
|
|
173
|
-
def validate(self):
|
|
194
|
+
def validate(self) -> None:
|
|
174
195
|
super().validate()
|
|
175
196
|
|
|
176
|
-
|
|
197
|
+
value_bit_size = self.value_bit_size
|
|
198
|
+
if value_bit_size is None:
|
|
177
199
|
raise ValueError("`value_bit_size` may not be none")
|
|
178
|
-
|
|
200
|
+
data_byte_size = self.data_byte_size
|
|
201
|
+
if data_byte_size is None:
|
|
179
202
|
raise ValueError("`data_byte_size` may not be none")
|
|
180
203
|
if self.encode_fn is None:
|
|
181
204
|
raise ValueError("`encode_fn` may not be none")
|
|
182
205
|
if self.is_big_endian is None:
|
|
183
206
|
raise ValueError("`is_big_endian` may not be none")
|
|
184
207
|
|
|
185
|
-
if
|
|
208
|
+
if value_bit_size % 8 != 0:
|
|
186
209
|
raise ValueError(
|
|
187
|
-
f"Invalid value bit size: {
|
|
188
|
-
"Must be a multiple of 8"
|
|
210
|
+
f"Invalid value bit size: {value_bit_size}. Must be a multiple of 8"
|
|
189
211
|
)
|
|
190
212
|
|
|
191
|
-
if
|
|
213
|
+
if value_bit_size > data_byte_size * 8:
|
|
192
214
|
raise ValueError("Value byte size exceeds data size")
|
|
193
215
|
|
|
194
|
-
def validate_value(self, value):
|
|
216
|
+
def validate_value(self, value: Any) -> None:
|
|
195
217
|
raise NotImplementedError("Must be implemented by subclasses")
|
|
196
218
|
|
|
197
|
-
def encode(self, value):
|
|
219
|
+
def encode(self, value: Any) -> bytes:
|
|
198
220
|
self.validate_value(value)
|
|
199
|
-
|
|
221
|
+
encode_fn = self.encode_fn
|
|
222
|
+
if encode_fn is None:
|
|
200
223
|
raise AssertionError("`encode_fn` is None")
|
|
201
|
-
|
|
224
|
+
return encode_fixed(value, encode_fn, self.is_big_endian, self.data_byte_size)
|
|
202
225
|
|
|
203
|
-
|
|
204
|
-
padded_encoded_value = zpad(base_encoded_value, self.data_byte_size)
|
|
205
|
-
else:
|
|
206
|
-
padded_encoded_value = zpad_right(base_encoded_value, self.data_byte_size)
|
|
207
|
-
|
|
208
|
-
return padded_encoded_value
|
|
226
|
+
__call__ = encode
|
|
209
227
|
|
|
210
228
|
|
|
211
229
|
class Fixed32ByteSizeEncoder(FixedSizeEncoder):
|
|
@@ -217,12 +235,12 @@ class BooleanEncoder(Fixed32ByteSizeEncoder):
|
|
|
217
235
|
is_big_endian = True
|
|
218
236
|
|
|
219
237
|
@classmethod
|
|
220
|
-
def validate_value(cls, value):
|
|
238
|
+
def validate_value(cls, value: Any) -> None:
|
|
221
239
|
if not is_boolean(value):
|
|
222
240
|
cls.invalidate_value(value)
|
|
223
241
|
|
|
224
242
|
@classmethod
|
|
225
|
-
def encode_fn(cls, value):
|
|
243
|
+
def encode_fn(cls, value: bool) -> bytes:
|
|
226
244
|
if value is True:
|
|
227
245
|
return b"\x01"
|
|
228
246
|
elif value is False:
|
|
@@ -245,7 +263,7 @@ class NumberEncoder(Fixed32ByteSizeEncoder):
|
|
|
245
263
|
illegal_value_fn = None
|
|
246
264
|
type_check_fn = None
|
|
247
265
|
|
|
248
|
-
def validate(self):
|
|
266
|
+
def validate(self) -> None:
|
|
249
267
|
super().validate()
|
|
250
268
|
|
|
251
269
|
if self.bounds_fn is None:
|
|
@@ -253,15 +271,15 @@ class NumberEncoder(Fixed32ByteSizeEncoder):
|
|
|
253
271
|
if self.type_check_fn is None:
|
|
254
272
|
raise ValueError("`type_check_fn` cannot be null")
|
|
255
273
|
|
|
256
|
-
def validate_value(self, value):
|
|
257
|
-
|
|
274
|
+
def validate_value(self, value: Any) -> None:
|
|
275
|
+
type_check_fn = self.type_check_fn
|
|
276
|
+
if type_check_fn is None:
|
|
258
277
|
raise AssertionError("`type_check_fn` is None")
|
|
259
|
-
if not
|
|
278
|
+
if not type_check_fn(value):
|
|
260
279
|
self.invalidate_value(value)
|
|
261
280
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
)
|
|
281
|
+
illegal_value_fn = self.illegal_value_fn
|
|
282
|
+
illegal_value = illegal_value_fn is not None and illegal_value_fn(value)
|
|
265
283
|
if illegal_value:
|
|
266
284
|
self.invalidate_value(value, exc=IllegalValue)
|
|
267
285
|
|
|
@@ -285,6 +303,16 @@ class UnsignedIntegerEncoder(NumberEncoder):
|
|
|
285
303
|
return cls(value_bit_size=abi_type.sub)
|
|
286
304
|
|
|
287
305
|
|
|
306
|
+
class UnsignedIntegerEncoderCached(UnsignedIntegerEncoder):
|
|
307
|
+
encode: Final[Callable[[int], bytes]]
|
|
308
|
+
maxsize: Final[Optional[int]]
|
|
309
|
+
|
|
310
|
+
def __init__(self, maxsize: Optional[int] = None, **kwargs: Any) -> None:
|
|
311
|
+
super().__init__(**kwargs)
|
|
312
|
+
self.maxsize = maxsize
|
|
313
|
+
self.encode = lru_cache(maxsize=maxsize)(self.encode)
|
|
314
|
+
|
|
315
|
+
|
|
288
316
|
encode_uint_256 = UnsignedIntegerEncoder(value_bit_size=256, data_byte_size=32)
|
|
289
317
|
|
|
290
318
|
|
|
@@ -297,29 +325,44 @@ class PackedUnsignedIntegerEncoder(UnsignedIntegerEncoder):
|
|
|
297
325
|
)
|
|
298
326
|
|
|
299
327
|
|
|
328
|
+
class PackedUnsignedIntegerEncoderCached(PackedUnsignedIntegerEncoder):
|
|
329
|
+
encode: Final[Callable[[int], bytes]]
|
|
330
|
+
maxsize: Final[Optional[int]]
|
|
331
|
+
|
|
332
|
+
def __init__(self, maxsize: Optional[int] = None, **kwargs: Any) -> None:
|
|
333
|
+
super().__init__(**kwargs)
|
|
334
|
+
self.maxsize = maxsize
|
|
335
|
+
self.encode = lru_cache(maxsize=maxsize)(self.encode)
|
|
336
|
+
|
|
337
|
+
|
|
300
338
|
class SignedIntegerEncoder(NumberEncoder):
|
|
301
339
|
bounds_fn = staticmethod(compute_signed_integer_bounds)
|
|
302
340
|
type_check_fn = staticmethod(is_integer)
|
|
303
341
|
|
|
304
|
-
def encode_fn(self, value):
|
|
342
|
+
def encode_fn(self, value: int) -> bytes:
|
|
305
343
|
return int_to_big_endian(value % (2**self.value_bit_size))
|
|
306
344
|
|
|
307
|
-
def encode(self, value):
|
|
345
|
+
def encode(self, value: int) -> bytes:
|
|
308
346
|
self.validate_value(value)
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if value >= 0:
|
|
312
|
-
padded_encoded_value = zpad(base_encoded_value, self.data_byte_size)
|
|
313
|
-
else:
|
|
314
|
-
padded_encoded_value = fpad(base_encoded_value, self.data_byte_size)
|
|
347
|
+
return encode_signed(value, self.encode_fn, self.data_byte_size)
|
|
315
348
|
|
|
316
|
-
|
|
349
|
+
__call__ = encode
|
|
317
350
|
|
|
318
351
|
@parse_type_str("int")
|
|
319
352
|
def from_type_str(cls, abi_type, registry):
|
|
320
353
|
return cls(value_bit_size=abi_type.sub)
|
|
321
354
|
|
|
322
355
|
|
|
356
|
+
class SignedIntegerEncoderCached(SignedIntegerEncoder):
|
|
357
|
+
encode: Final[Callable[[int], bytes]]
|
|
358
|
+
maxsize: Final[Optional[int]]
|
|
359
|
+
|
|
360
|
+
def __init__(self, maxsize: Optional[int] = None, **kwargs: Any) -> None:
|
|
361
|
+
super().__init__(**kwargs)
|
|
362
|
+
self.maxsize = maxsize
|
|
363
|
+
self.encode = lru_cache(maxsize=maxsize)(self.encode)
|
|
364
|
+
|
|
365
|
+
|
|
323
366
|
class PackedSignedIntegerEncoder(SignedIntegerEncoder):
|
|
324
367
|
@parse_type_str("int")
|
|
325
368
|
def from_type_str(cls, abi_type, registry):
|
|
@@ -329,6 +372,16 @@ class PackedSignedIntegerEncoder(SignedIntegerEncoder):
|
|
|
329
372
|
)
|
|
330
373
|
|
|
331
374
|
|
|
375
|
+
class PackedSignedIntegerEncoderCached(PackedSignedIntegerEncoder):
|
|
376
|
+
encode: Final[Callable[[int], bytes]]
|
|
377
|
+
maxsize: Final[Optional[int]]
|
|
378
|
+
|
|
379
|
+
def __init__(self, maxsize: Optional[int] = None, **kwargs: Any) -> None:
|
|
380
|
+
super().__init__(**kwargs)
|
|
381
|
+
self.maxsize = maxsize
|
|
382
|
+
self.encode = lru_cache(maxsize=maxsize)(self.encode)
|
|
383
|
+
|
|
384
|
+
|
|
332
385
|
class BaseFixedEncoder(NumberEncoder):
|
|
333
386
|
frac_places = None
|
|
334
387
|
|
|
@@ -343,27 +396,36 @@ class BaseFixedEncoder(NumberEncoder):
|
|
|
343
396
|
|
|
344
397
|
return False
|
|
345
398
|
|
|
399
|
+
@cached_property
|
|
400
|
+
def denominator(self) -> decimal.Decimal:
|
|
401
|
+
return TEN**self.frac_places
|
|
402
|
+
|
|
403
|
+
@cached_property
|
|
404
|
+
def precision(self) -> int:
|
|
405
|
+
return TEN**-self.frac_places
|
|
406
|
+
|
|
346
407
|
def validate_value(self, value):
|
|
347
408
|
super().validate_value(value)
|
|
348
409
|
|
|
349
410
|
with decimal.localcontext(abi_decimal_context):
|
|
350
|
-
residue = value %
|
|
411
|
+
residue = value % self.precision
|
|
351
412
|
|
|
352
413
|
if residue > 0:
|
|
353
414
|
self.invalidate_value(
|
|
354
415
|
value,
|
|
355
416
|
exc=IllegalValue,
|
|
356
|
-
msg=f"residue {
|
|
417
|
+
msg=f"residue {residue!r} outside allowed fractional precision of "
|
|
357
418
|
f"{self.frac_places}",
|
|
358
419
|
)
|
|
359
420
|
|
|
360
|
-
def validate(self):
|
|
421
|
+
def validate(self) -> None:
|
|
361
422
|
super().validate()
|
|
362
423
|
|
|
363
|
-
|
|
424
|
+
frac_places = self.frac_places
|
|
425
|
+
if frac_places is None:
|
|
364
426
|
raise ValueError("must specify `frac_places`")
|
|
365
427
|
|
|
366
|
-
if
|
|
428
|
+
if frac_places <= 0 or frac_places > 80:
|
|
367
429
|
raise ValueError("`frac_places` must be in range (0, 80]")
|
|
368
430
|
|
|
369
431
|
|
|
@@ -371,9 +433,9 @@ class UnsignedFixedEncoder(BaseFixedEncoder):
|
|
|
371
433
|
def bounds_fn(self, value_bit_size):
|
|
372
434
|
return compute_unsigned_fixed_bounds(self.value_bit_size, self.frac_places)
|
|
373
435
|
|
|
374
|
-
def encode_fn(self, value):
|
|
436
|
+
def encode_fn(self, value: decimal.Decimal) -> bytes:
|
|
375
437
|
with decimal.localcontext(abi_decimal_context):
|
|
376
|
-
scaled_value = value *
|
|
438
|
+
scaled_value = value * self.denominator
|
|
377
439
|
integer_value = int(scaled_value)
|
|
378
440
|
|
|
379
441
|
return int_to_big_endian(integer_value)
|
|
@@ -404,25 +466,20 @@ class SignedFixedEncoder(BaseFixedEncoder):
|
|
|
404
466
|
def bounds_fn(self, value_bit_size):
|
|
405
467
|
return compute_signed_fixed_bounds(self.value_bit_size, self.frac_places)
|
|
406
468
|
|
|
407
|
-
def encode_fn(self, value):
|
|
469
|
+
def encode_fn(self, value: decimal.Decimal) -> bytes:
|
|
408
470
|
with decimal.localcontext(abi_decimal_context):
|
|
409
|
-
scaled_value = value *
|
|
471
|
+
scaled_value = value * self.denominator
|
|
410
472
|
integer_value = int(scaled_value)
|
|
411
473
|
|
|
412
474
|
unsigned_integer_value = integer_value % (2**self.value_bit_size)
|
|
413
475
|
|
|
414
476
|
return int_to_big_endian(unsigned_integer_value)
|
|
415
477
|
|
|
416
|
-
def encode(self, value):
|
|
478
|
+
def encode(self, value: decimal.Decimal) -> bytes:
|
|
417
479
|
self.validate_value(value)
|
|
418
|
-
|
|
480
|
+
return encode_signed(value, self.encode_fn, self.data_byte_size)
|
|
419
481
|
|
|
420
|
-
|
|
421
|
-
padded_encoded_value = zpad(base_encoded_value, self.data_byte_size)
|
|
422
|
-
else:
|
|
423
|
-
padded_encoded_value = fpad(base_encoded_value, self.data_byte_size)
|
|
424
|
-
|
|
425
|
-
return padded_encoded_value
|
|
482
|
+
__call__ = encode
|
|
426
483
|
|
|
427
484
|
@parse_type_str("fixed")
|
|
428
485
|
def from_type_str(cls, abi_type, registry):
|
|
@@ -452,11 +509,11 @@ class AddressEncoder(Fixed32ByteSizeEncoder):
|
|
|
452
509
|
is_big_endian = True
|
|
453
510
|
|
|
454
511
|
@classmethod
|
|
455
|
-
def validate_value(cls, value):
|
|
512
|
+
def validate_value(cls, value: Any) -> None:
|
|
456
513
|
if not is_address(value):
|
|
457
514
|
cls.invalidate_value(value)
|
|
458
515
|
|
|
459
|
-
def validate(self):
|
|
516
|
+
def validate(self) -> None:
|
|
460
517
|
super().validate()
|
|
461
518
|
|
|
462
519
|
if self.value_bit_size != 20 * 8:
|
|
@@ -474,7 +531,7 @@ class PackedAddressEncoder(AddressEncoder):
|
|
|
474
531
|
class BytesEncoder(Fixed32ByteSizeEncoder):
|
|
475
532
|
is_big_endian = False
|
|
476
533
|
|
|
477
|
-
def validate_value(self, value):
|
|
534
|
+
def validate_value(self, value: Any) -> None:
|
|
478
535
|
if not is_bytes(value):
|
|
479
536
|
self.invalidate_value(value)
|
|
480
537
|
|
|
@@ -487,7 +544,7 @@ class BytesEncoder(Fixed32ByteSizeEncoder):
|
|
|
487
544
|
)
|
|
488
545
|
|
|
489
546
|
@staticmethod
|
|
490
|
-
def encode_fn(value):
|
|
547
|
+
def encode_fn(value: bytes) -> bytes:
|
|
491
548
|
return value
|
|
492
549
|
|
|
493
550
|
@parse_type_str("bytes")
|
|
@@ -508,12 +565,12 @@ class ByteStringEncoder(BaseEncoder):
|
|
|
508
565
|
is_dynamic = True
|
|
509
566
|
|
|
510
567
|
@classmethod
|
|
511
|
-
def validate_value(cls, value):
|
|
568
|
+
def validate_value(cls, value: Any) -> None:
|
|
512
569
|
if not is_bytes(value):
|
|
513
570
|
cls.invalidate_value(value)
|
|
514
571
|
|
|
515
572
|
@classmethod
|
|
516
|
-
def encode(cls, value):
|
|
573
|
+
def encode(cls, value: bytes) -> bytes:
|
|
517
574
|
cls.validate_value(value)
|
|
518
575
|
value_length = len(value)
|
|
519
576
|
|
|
@@ -522,30 +579,34 @@ class ByteStringEncoder(BaseEncoder):
|
|
|
522
579
|
|
|
523
580
|
return encoded_size + padded_value
|
|
524
581
|
|
|
582
|
+
__call__: ClassVar[Callable[[Type[Self], bytes], bytes]] = encode
|
|
583
|
+
|
|
525
584
|
@parse_type_str("bytes")
|
|
526
585
|
def from_type_str(cls, abi_type, registry):
|
|
527
|
-
return cls()
|
|
586
|
+
return cls() # type: ignore [misc]
|
|
528
587
|
|
|
529
588
|
|
|
530
589
|
class PackedByteStringEncoder(ByteStringEncoder):
|
|
531
590
|
is_dynamic = False
|
|
532
591
|
|
|
533
592
|
@classmethod
|
|
534
|
-
def encode(cls, value):
|
|
593
|
+
def encode(cls, value: bytes) -> bytes:
|
|
535
594
|
cls.validate_value(value)
|
|
536
595
|
return value
|
|
537
596
|
|
|
597
|
+
__call__ = encode
|
|
598
|
+
|
|
538
599
|
|
|
539
600
|
class TextStringEncoder(BaseEncoder):
|
|
540
601
|
is_dynamic = True
|
|
541
602
|
|
|
542
603
|
@classmethod
|
|
543
|
-
def validate_value(cls, value):
|
|
604
|
+
def validate_value(cls, value: Any) -> None:
|
|
544
605
|
if not is_text(value):
|
|
545
606
|
cls.invalidate_value(value)
|
|
546
607
|
|
|
547
608
|
@classmethod
|
|
548
|
-
def encode(cls, value):
|
|
609
|
+
def encode(cls, value: str) -> bytes:
|
|
549
610
|
cls.validate_value(value)
|
|
550
611
|
|
|
551
612
|
value_as_bytes = codecs.encode(value, "utf8")
|
|
@@ -556,57 +617,47 @@ class TextStringEncoder(BaseEncoder):
|
|
|
556
617
|
|
|
557
618
|
return encoded_size + padded_value
|
|
558
619
|
|
|
620
|
+
__call__: ClassVar[Callable[[Type[Self], str], bytes]] = encode
|
|
621
|
+
|
|
559
622
|
@parse_type_str("string")
|
|
560
623
|
def from_type_str(cls, abi_type, registry):
|
|
561
|
-
return cls()
|
|
624
|
+
return cls() # type: ignore [misc]
|
|
562
625
|
|
|
563
626
|
|
|
564
627
|
class PackedTextStringEncoder(TextStringEncoder):
|
|
565
628
|
is_dynamic = False
|
|
566
629
|
|
|
567
630
|
@classmethod
|
|
568
|
-
def encode(cls, value):
|
|
631
|
+
def encode(cls, value: str) -> bytes:
|
|
569
632
|
cls.validate_value(value)
|
|
570
633
|
return codecs.encode(value, "utf8")
|
|
571
634
|
|
|
635
|
+
__call__ = encode
|
|
636
|
+
|
|
572
637
|
|
|
573
638
|
class BaseArrayEncoder(BaseEncoder):
|
|
574
|
-
item_encoder = None
|
|
639
|
+
item_encoder: BaseEncoder = None
|
|
575
640
|
|
|
576
|
-
def validate(self):
|
|
641
|
+
def validate(self) -> None:
|
|
577
642
|
super().validate()
|
|
578
643
|
|
|
579
644
|
if self.item_encoder is None:
|
|
580
645
|
raise ValueError("`item_encoder` may not be none")
|
|
581
646
|
|
|
582
|
-
def validate_value(self, value):
|
|
647
|
+
def validate_value(self, value: Any) -> None:
|
|
583
648
|
if not is_list_like(value):
|
|
584
649
|
self.invalidate_value(
|
|
585
650
|
value,
|
|
586
651
|
msg="must be list-like such as array or tuple",
|
|
587
652
|
)
|
|
588
653
|
|
|
654
|
+
item_encoder = self.item_encoder
|
|
589
655
|
for item in value:
|
|
590
|
-
|
|
656
|
+
item_encoder.validate_value(item)
|
|
591
657
|
|
|
592
|
-
def encode_elements(self, value):
|
|
658
|
+
def encode_elements(self, value: Sequence[Any]) -> bytes:
|
|
593
659
|
self.validate_value(value)
|
|
594
|
-
|
|
595
|
-
item_encoder = self.item_encoder
|
|
596
|
-
if item_encoder is None:
|
|
597
|
-
raise AssertionError("`item_encoder` is None")
|
|
598
|
-
tail_chunks = tuple(item_encoder(i) for i in value)
|
|
599
|
-
|
|
600
|
-
items_are_dynamic = getattr(item_encoder, "is_dynamic", False)
|
|
601
|
-
if not items_are_dynamic or len(value) == 0:
|
|
602
|
-
return b"".join(tail_chunks)
|
|
603
|
-
|
|
604
|
-
head_length = 32 * len(value)
|
|
605
|
-
tail_offsets = (0,) + tuple(accumulate(map(len, tail_chunks[:-1])))
|
|
606
|
-
head_chunks = tuple(
|
|
607
|
-
encode_uint_256(head_length + offset) for offset in tail_offsets
|
|
608
|
-
)
|
|
609
|
-
return b"".join(head_chunks + tail_chunks)
|
|
660
|
+
return encode_elements(self.item_encoder, value)
|
|
610
661
|
|
|
611
662
|
@parse_type_str(with_arrlist=True)
|
|
612
663
|
def from_type_str(cls, abi_type, registry):
|
|
@@ -627,21 +678,21 @@ class BaseArrayEncoder(BaseEncoder):
|
|
|
627
678
|
class PackedArrayEncoder(BaseArrayEncoder):
|
|
628
679
|
array_size = None
|
|
629
680
|
|
|
630
|
-
def validate_value(self, value):
|
|
681
|
+
def validate_value(self, value: Any) -> None:
|
|
631
682
|
super().validate_value(value)
|
|
632
683
|
|
|
633
|
-
|
|
684
|
+
array_size = self.array_size
|
|
685
|
+
if array_size is not None and len(value) != array_size:
|
|
634
686
|
self.invalidate_value(
|
|
635
687
|
value,
|
|
636
688
|
exc=ValueOutOfBounds,
|
|
637
|
-
msg=f"value has {len(value)} items when {
|
|
638
|
-
"expected",
|
|
689
|
+
msg=f"value has {len(value)} items when {array_size} were expected",
|
|
639
690
|
)
|
|
640
691
|
|
|
641
|
-
def encode(self, value):
|
|
642
|
-
|
|
692
|
+
def encode(self, value: Sequence[Any]) -> bytes:
|
|
693
|
+
return encode_elements(self.item_encoder, value)
|
|
643
694
|
|
|
644
|
-
|
|
695
|
+
__call__ = encode
|
|
645
696
|
|
|
646
697
|
@parse_type_str(with_arrlist=True)
|
|
647
698
|
def from_type_str(cls, abi_type, registry):
|
|
@@ -660,18 +711,18 @@ class PackedArrayEncoder(BaseArrayEncoder):
|
|
|
660
711
|
class SizedArrayEncoder(BaseArrayEncoder):
|
|
661
712
|
array_size = None
|
|
662
713
|
|
|
663
|
-
def __init__(self, **kwargs):
|
|
714
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
664
715
|
super().__init__(**kwargs)
|
|
665
716
|
|
|
666
717
|
self.is_dynamic = self.item_encoder.is_dynamic
|
|
667
718
|
|
|
668
|
-
def validate(self):
|
|
719
|
+
def validate(self) -> None:
|
|
669
720
|
super().validate()
|
|
670
721
|
|
|
671
722
|
if self.array_size is None:
|
|
672
723
|
raise ValueError("`array_size` may not be none")
|
|
673
724
|
|
|
674
|
-
def validate_value(self, value):
|
|
725
|
+
def validate_value(self, value: Any) -> None:
|
|
675
726
|
super().validate_value(value)
|
|
676
727
|
|
|
677
728
|
if len(value) != self.array_size:
|
|
@@ -682,18 +733,14 @@ class SizedArrayEncoder(BaseArrayEncoder):
|
|
|
682
733
|
"expected",
|
|
683
734
|
)
|
|
684
735
|
|
|
685
|
-
def encode(self, value):
|
|
686
|
-
|
|
736
|
+
def encode(self, value: Sequence[Any]) -> bytes:
|
|
737
|
+
return encode_elements(self.item_encoder, value)
|
|
687
738
|
|
|
688
|
-
|
|
739
|
+
__call__ = encode
|
|
689
740
|
|
|
690
741
|
|
|
691
742
|
class DynamicArrayEncoder(BaseArrayEncoder):
|
|
692
743
|
is_dynamic = True
|
|
693
744
|
|
|
694
|
-
def encode(self, value):
|
|
695
|
-
|
|
696
|
-
encoded_elements = self.encode_elements(value)
|
|
697
|
-
encoded_value = encoded_size + encoded_elements
|
|
698
|
-
|
|
699
|
-
return encoded_value
|
|
745
|
+
def encode(self, value: Sequence[Any]) -> bytes:
|
|
746
|
+
return encode_elements_dynamic(self.item_encoder, value)
|