-
Notifications
You must be signed in to change notification settings - Fork 82
Expand file tree
/
Copy pathcontracts.py
More file actions
162 lines (133 loc) · 4.74 KB
/
contracts.py
File metadata and controls
162 lines (133 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# --------------------------------------------------------------------
# Copyright (c) iEXBase. All rights reserved.
# Licensed under the MIT License.
# See License.txt in the project root for license information.
# --------------------------------------------------------------------
import functools
from hexbytes import HexBytes
from eth_utils import (
to_hex,
function_abi_to_4byte_selector
)
from trx_utils import is_text, encode_hex
from tronapi.common.abi import (
filter_by_name,
filter_by_encodability,
filter_by_argument_count,
get_fallback_func_abi,
abi_to_signature,
get_abi_input_types,
check_if_arguments_can_be_encoded,
map_abi_data,
merge_args_and_kwargs
)
from tronapi.common.normalizers import (
abi_address_to_hex,
abi_bytes_to_bytes,
abi_string_to_text
)
from tronapi.common.toolz import (
pipe,
valmap,
)
from eth_abi import (
encode as eth_abi_encode_abi,
)
from eth_abi.exceptions import (
EncodingError,
)
class FallbackFn:
pass
def find_matching_fn_abi(abi, fn_identifier=None, args=None, kwargs=None):
args = args or tuple()
kwargs = kwargs or dict()
filters = []
num_arguments = len(args) + len(kwargs)
diagnosis = None
if fn_identifier is FallbackFn:
return get_fallback_func_abi(abi)
if not is_text(fn_identifier):
raise TypeError("Unsupported function identifier")
name_filter = functools.partial(filter_by_name, fn_identifier)
arg_count_filter = functools.partial(filter_by_argument_count, num_arguments)
encoding_filter = functools.partial(filter_by_encodability, args, kwargs)
filters.extend([
name_filter,
arg_count_filter,
encoding_filter,
])
function_candidates = pipe(abi, *filters)
if len(function_candidates) == 1:
return function_candidates[0]
else:
matching_identifiers = name_filter(abi)
matching_function_signatures = [abi_to_signature(func) for func in matching_identifiers]
arg_count_matches = len(arg_count_filter(matching_identifiers))
encoding_matches = len(encoding_filter(matching_identifiers))
if arg_count_matches == 0:
diagnosis = "\nFunction invocation failed due to improper number of arguments."
elif encoding_matches == 0:
diagnosis = "\nFunction invocation failed due to no matching argument types."
elif encoding_matches > 1:
diagnosis = (
"\nAmbiguous argument encoding. "
"Provided arguments can be encoded to multiple functions matching this call."
)
message = (
"\nCould not identify the intended function with name `{name}`, "
"positional argument(s) of type `{arg_types}` and "
"keyword argument(s) of type `{kwarg_types}`."
"\nFound {num_candidates} function(s) with the name `{name}`: {candidates}"
"{diagnosis}"
).format(
name=fn_identifier,
arg_types=tuple(map(type, args)),
kwarg_types=valmap(type, kwargs),
num_candidates=len(matching_identifiers),
candidates=matching_function_signatures,
diagnosis=diagnosis,
)
raise ValueError(message)
def encode_abi(tron, abi, arguments, data=None):
argument_types = get_abi_input_types(abi)
if not check_if_arguments_can_be_encoded(abi, arguments, {}):
raise TypeError(
"One or more arguments could not be encoded to the necessary "
"ABI type. Expected types are: {0}".format(
', '.join(argument_types),
)
)
try:
normalizers = [
abi_address_to_hex,
abi_bytes_to_bytes,
abi_string_to_text,
]
normalized_arguments = map_abi_data(
normalizers,
argument_types,
arguments,
)
encoded_arguments = eth_abi_encode_abi(
argument_types,
normalized_arguments,
)
except EncodingError as e:
raise TypeError(
"One or more arguments could not be encoded to the necessary "
"ABI type: {0}".format(str(e))
)
if data:
return to_hex(HexBytes(data) + encoded_arguments)
else:
return encode_hex(encoded_arguments)
def get_function_info(fn_name, contract_abi=None, fn_abi=None, args=None, kwargs=None):
if args is None:
args = tuple()
if kwargs is None:
kwargs = {}
if fn_abi is None:
fn_abi = find_matching_fn_abi(contract_abi, fn_name, args, kwargs)
fn_selector = encode_hex(function_abi_to_4byte_selector(fn_abi))
fn_arguments = merge_args_and_kwargs(fn_abi, args, kwargs)
return fn_abi, fn_selector, fn_arguments