Skip to content

Commit b15da63

Browse files
committed
added solidity_sha3()
1 parent 9f3d2d1 commit b15da63

File tree

4 files changed

+97
-4
lines changed

4 files changed

+97
-4
lines changed

tronapi/base/abi.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
"$"
8787
).format(sub_type=SUB_TYPE_REGEX)
8888

89+
8990
def filter_by_argument_name(argument_names, contract_abi):
9091
return [
9192
abi
@@ -187,6 +188,19 @@ def get_abi_input_names(abi):
187188
return [arg['name'] for arg in abi['inputs']]
188189

189190

191+
def length_of_array_type(abi_type):
192+
if not is_array_type(abi_type):
193+
raise ValueError(
194+
"Cannot parse length of nonarray abi-type: {0}".format(abi_type)
195+
)
196+
197+
inner_brackets = re.search(END_BRACKETS_OF_ARRAY_TYPE_REGEX, abi_type).group(0).strip("[]")
198+
if not inner_brackets:
199+
return None
200+
else:
201+
return int(inner_brackets)
202+
203+
190204
def get_fallback_func_abi(contract_abi):
191205
fallback_abis = filter_by_type('fallback', contract_abi)
192206
if fallback_abis:
@@ -438,6 +452,7 @@ def normalizer(datatype, data):
438452
2. Recursively mapping each of the normalizers to the data
439453
3. Stripping the types back out of the tree
440454
"""
455+
441456
pipeline = itertools.chain(
442457
[abi_data_tree(types)],
443458
map(data_tree_map, normalizers),
@@ -448,7 +463,7 @@ def normalizer(datatype, data):
448463

449464

450465
@curry
451-
def abi_data_tree(types, data=None):
466+
def abi_data_tree(types, data):
452467
"""Decorate the data tree with pairs of (type, data). The pair tuple is actually an
453468
ABITypedData, but can be accessed as a tuple.
454469
@@ -458,6 +473,7 @@ def abi_data_tree(types, data=None):
458473
Returns:
459474
[("bool[2]", [("bool", True), ("bool", False)]), ("uint256", 0)]
460475
"""
476+
461477
return [
462478
abi_sub_tree(data_type, data_value)
463479
for data_type, data_value

tronapi/base/encoding.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
int_to_big_endian
1212
)
1313

14+
from tronapi.base.abi import size_of_type, sub_type_of_array_type, is_array_type, is_bool_type, is_uint_type, \
15+
is_int_type, is_address_type, is_bytes_type, is_string_type
16+
from tronapi.base.validation import validate_abi_type, validate_abi_value
1417
from tronapi.utils.hexadecimal import (
1518
remove_0x_prefix,
1619
decode_hex,
@@ -25,13 +28,45 @@
2528
from tronapi.utils.types import (
2629
is_boolean,
2730
is_integer,
28-
is_list_like
29-
)
31+
is_list_like,
32+
is_bytes)
3033

3134
from tronapi.base.datastructures import AttributeDict
3235
from tronapi.utils.validation import assert_one_val
3336

3437

38+
def hex_encode_abi_type(abi_type, value, force_size=None):
39+
"""
40+
Encodes value into a hex string in format of abi_type
41+
"""
42+
validate_abi_type(abi_type)
43+
validate_abi_value(abi_type, value)
44+
45+
data_size = force_size or size_of_type(abi_type)
46+
if is_array_type(abi_type):
47+
sub_type = sub_type_of_array_type(abi_type)
48+
return "".join([remove_0x_prefix(hex_encode_abi_type(sub_type, v, 256)) for v in value])
49+
elif is_bool_type(abi_type):
50+
return to_hex_with_size(value, data_size)
51+
elif is_uint_type(abi_type):
52+
return to_hex_with_size(value, data_size)
53+
elif is_int_type(abi_type):
54+
return to_hex_twos_compliment(value, data_size)
55+
elif is_address_type(abi_type):
56+
return pad_hex(value, data_size)
57+
elif is_bytes_type(abi_type):
58+
if is_bytes(value):
59+
return encode_hex(value)
60+
else:
61+
return value
62+
elif is_string_type(abi_type):
63+
return to_hex(text=value)
64+
else:
65+
raise ValueError(
66+
"Unsupported ABI type: {0}".format(abi_type)
67+
)
68+
69+
3570
def to_hex_twos_compliment(value, bit_size):
3671
"""
3772
Converts integer value to twos compliment hex representation with given bit_size

tronapi/base/normalizers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import functools
22
import json
33

4+
45
from eth_utils import is_binary_address, to_hex, hexstr_if_str
56
from hexbytes import HexBytes
7+
from toolz import curry
68

79
from tronapi.base.abi import process_type
810
from tronapi.base.encoding import to_bytes, text_if_str, to_text
@@ -55,3 +57,8 @@ def abi_bytes_to_bytes(abi_type, data):
5557
base, sub, arrlist = process_type(abi_type)
5658
if base == 'bytes' and not arrlist:
5759
return abi_type, hexstr_if_str(to_bytes, data)
60+
61+
62+
@curry
63+
def abi_resolver(abi_type, val):
64+
return abi_type, val

tronapi/main.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,17 @@
1818
import ecdsa
1919
from eth_utils import apply_to_return_value, to_hex
2020
from hexbytes import HexBytes
21+
from tronapi.base.abi import map_abi_data
2122

2223
from tronapi.base.account import Account, PrivateKey
2324
from tronapi.base.datastructures import AttributeDict
25+
from tronapi.base.normalizers import abi_resolver
2426
from tronapi.base.encoding import (
2527
to_bytes,
2628
to_int,
2729
to_text,
28-
to_json
30+
to_json,
31+
hex_encode_abi_type
2932
)
3033

3134
from tronapi.exceptions import InvalidTronError, TronError
@@ -36,6 +39,7 @@
3639
from tronapi.base.validation import is_address
3740
from tronapi.utils.crypto import keccak
3841
from tronapi.utils.currency import to_sun, from_sun
42+
from tronapi.utils.hexadecimal import remove_0x_prefix, add_0x_prefix
3943
from tronapi.utils.types import is_integer
4044

4145
DEFAULT_MODULES = {
@@ -268,6 +272,37 @@ def is_valid_provider(provider) -> bool:
268272
"""
269273
return isinstance(provider, HttpProvider)
270274

275+
def solidity_sha3(self, abi_types, values):
276+
"""
277+
Executes keccak256 exactly as Solidity does.
278+
Takes list of abi_types as inputs -- `[uint24, int8[], bool]`
279+
and list of corresponding values -- `[20, [-1, 5, 0], True]`
280+
281+
Args:
282+
abi_types (any): types abi
283+
values (any): values
284+
285+
Examples:
286+
>>> tron = Tron()
287+
>>> sol = tron.solidity_sha3(['uint8[]'], [[1, 2, 3, 4, 5]])
288+
>>> assert sol.hex() == '0x5917e5a395fb9b454434de59651d36822a9e29c5ec57474df3e67937b969460c'
289+
290+
"""
291+
if len(abi_types) != len(values):
292+
raise ValueError(
293+
"Length mismatch between provided abi types and values. Got "
294+
"{0} types and {1} values.".format(len(abi_types), len(values))
295+
)
296+
297+
normalized_values = map_abi_data([abi_resolver()], abi_types, values)
298+
299+
hex_string = add_0x_prefix(''.join(
300+
remove_0x_prefix(hex_encode_abi_type(abi_type, value))
301+
for abi_type, value
302+
in zip(abi_types, normalized_values)
303+
))
304+
return self.sha3(hexstr=hex_string)
305+
271306
@staticmethod
272307
@apply_to_return_value(HexBytes)
273308
def sha3(primitive=None, text=None, hexstr=None):

0 commit comments

Comments
 (0)