slither.utils.encoding

  1from typing import Union
  2
  3from slither.core import variables
  4from slither.core.declarations import (
  5    SolidityVariable,
  6    SolidityVariableComposed,
  7    Structure,
  8    Enum,
  9    Contract,
 10)
 11from slither.core import solidity_types
 12from slither.slithir import operations
 13from slither.slithir import variables as SlitherIRVariable
 14
 15
 16# pylint: disable=too-many-branches
 17def ntype(_type: Union[solidity_types.Type, str]) -> str:
 18    if isinstance(_type, solidity_types.ElementaryType):
 19        _type = str(_type)
 20    elif isinstance(_type, solidity_types.ArrayType):
 21        if isinstance(_type.type, solidity_types.ElementaryType):
 22            _type = str(_type)
 23        else:
 24            _type = "user_defined_array"
 25    elif isinstance(_type, Structure):
 26        _type = str(_type)
 27    elif isinstance(_type, Enum):
 28        _type = str(_type)
 29    elif isinstance(_type, solidity_types.MappingType):
 30        _type = str(_type)
 31    elif isinstance(_type, solidity_types.UserDefinedType):
 32        if isinstance(_type.type, Contract):
 33            _type = f"contract({_type.type.name})"
 34        elif isinstance(_type.type, Structure):
 35            _type = f"struct({_type.type.name})"
 36        elif isinstance(_type.type, Enum):
 37            _type = f"enum({_type.type.name})"
 38    else:
 39        _type = str(_type)
 40
 41    _type = _type.replace(" memory", "")
 42    _type = _type.replace(" storage ref", "")
 43
 44    if "struct" in _type:
 45        return "struct"
 46    if "enum" in _type:
 47        return "enum"
 48    if "tuple" in _type:
 49        return "tuple"
 50    if "contract" in _type:
 51        return "contract"
 52    if "mapping" in _type:
 53        return "mapping"
 54    return _type.replace(" ", "_")
 55
 56
 57# pylint: disable=too-many-branches
 58def encode_var_for_compare(var: Union[variables.Variable, SolidityVariable]) -> str:
 59
 60    # variables
 61    if isinstance(var, SlitherIRVariable.Constant):
 62        return f"constant({ntype(var.type)},{var.value})"
 63    if isinstance(var, SolidityVariableComposed):
 64        return f"solidity_variable_composed({var.name})"
 65    if isinstance(var, SolidityVariable):
 66        return f"solidity_variable{var.name}"
 67    if isinstance(var, SlitherIRVariable.TemporaryVariable):
 68        return "temporary_variable"
 69    if isinstance(var, SlitherIRVariable.ReferenceVariable):
 70        return f"reference({ntype(var.type)})"
 71    if isinstance(var, variables.LocalVariable):
 72        return f"local_solc_variable({ntype(var.type)},{var.location})"
 73    if isinstance(var, variables.StateVariable):
 74        if var.is_stored:
 75            try:
 76                slot, _ = var.contract.compilation_unit.storage_layout_of(var.contract, var)
 77            except KeyError:
 78                slot = var.name
 79        else:
 80            slot = var.name
 81        return f"state_solc_variable({ntype(var.type)},{slot})"
 82    if isinstance(var, variables.LocalVariableInitFromTuple):
 83        return "local_variable_init_tuple"
 84    if isinstance(var, SlitherIRVariable.TupleVariable):
 85        return "tuple_variable"
 86
 87    # default
 88    return ""
 89
 90
 91# pylint: disable=too-many-branches
 92def encode_ir_for_upgradeability_compare(ir: operations.Operation) -> str:
 93    # operations
 94    if isinstance(ir, operations.Assignment):
 95        return f"({encode_var_for_compare(ir.lvalue)}):=({encode_var_for_compare(ir.rvalue)})"
 96    if isinstance(ir, operations.Index):
 97        return f"index({ntype(ir.variable_right.type)})"
 98    if isinstance(ir, operations.Member):
 99        return "member"  # .format(ntype(ir._type))
100    if isinstance(ir, operations.Length):
101        return "length"
102    if isinstance(ir, operations.Binary):
103        return f"binary({encode_var_for_compare(ir.variable_left)}{ir.type}{encode_var_for_compare(ir.variable_right)})"
104    if isinstance(ir, operations.Unary):
105        return f"unary({str(ir.type)})"
106    if isinstance(ir, operations.Condition):
107        return f"condition({encode_var_for_compare(ir.value)})"
108    if isinstance(ir, operations.NewStructure):
109        return "new_structure"
110    if isinstance(ir, operations.NewContract):
111        return "new_contract"
112    if isinstance(ir, operations.NewArray):
113        return f"new_array({ntype(ir.array_type)})"
114    if isinstance(ir, operations.NewElementaryType):
115        return f"new_elementary({ntype(ir.type)})"
116    if isinstance(ir, operations.Delete):
117        return f"delete({encode_var_for_compare(ir.lvalue)},{encode_var_for_compare(ir.variable)})"
118    if isinstance(ir, operations.SolidityCall):
119        return f"solidity_call({ir.function.full_name})"
120    if isinstance(ir, operations.InternalCall):
121        return f"internal_call({ntype(ir.type_call)})"
122    if isinstance(ir, operations.EventCall):  # is this useful?
123        return "event"
124    if isinstance(ir, operations.LibraryCall):
125        return "library_call"
126    if isinstance(ir, operations.InternalDynamicCall):
127        return "internal_dynamic_call"
128    if isinstance(ir, operations.HighLevelCall):  # TODO: improve
129        return "high_level_call"
130    if isinstance(ir, operations.LowLevelCall):  # TODO: improve
131        return "low_level_call"
132    if isinstance(ir, operations.TypeConversion):
133        return f"type_conversion({ntype(ir.type)})"
134    if isinstance(ir, operations.Return):  # this can be improved using values
135        return "return"  # .format(ntype(ir.type))
136    if isinstance(ir, operations.Transfer):
137        return f"transfer({encode_var_for_compare(ir.call_value)})"
138    if isinstance(ir, operations.Send):
139        return f"send({encode_var_for_compare(ir.call_value)})"
140    if isinstance(ir, operations.Unpack):  # TODO: improve
141        return "unpack"
142    if isinstance(ir, operations.InitArray):  # TODO: improve
143        return "init_array"
144
145    # default
146    return ""
147
148
149def encode_ir_for_halstead(ir: operations.Operation) -> str:
150    # operations
151    if isinstance(ir, operations.Assignment):
152        return "assignment"
153    if isinstance(ir, operations.Index):
154        return "index"
155    if isinstance(ir, operations.Member):
156        return "member"  # .format(ntype(ir._type))
157    if isinstance(ir, operations.Length):
158        return "length"
159    if isinstance(ir, operations.Binary):
160        return f"binary({str(ir.type)})"
161    if isinstance(ir, operations.Unary):
162        return f"unary({str(ir.type)})"
163    if isinstance(ir, operations.Condition):
164        return f"condition({encode_var_for_compare(ir.value)})"
165    if isinstance(ir, operations.NewStructure):
166        return "new_structure"
167    if isinstance(ir, operations.NewContract):
168        return "new_contract"
169    if isinstance(ir, operations.NewArray):
170        return f"new_array({ntype(ir.array_type)})"
171    if isinstance(ir, operations.NewElementaryType):
172        return f"new_elementary({ntype(ir.type)})"
173    if isinstance(ir, operations.Delete):
174        return "delete"
175    if isinstance(ir, operations.SolidityCall):
176        return f"solidity_call({ir.function.full_name})"
177    if isinstance(ir, operations.InternalCall):
178        return f"internal_call({ntype(ir.type_call)})"
179    if isinstance(ir, operations.EventCall):  # is this useful?
180        return "event"
181    if isinstance(ir, operations.LibraryCall):
182        return "library_call"
183    if isinstance(ir, operations.InternalDynamicCall):
184        return "internal_dynamic_call"
185    if isinstance(ir, operations.HighLevelCall):  # TODO: improve
186        return "high_level_call"
187    if isinstance(ir, operations.LowLevelCall):  # TODO: improve
188        return "low_level_call"
189    if isinstance(ir, operations.TypeConversion):
190        return f"type_conversion({ntype(ir.type)})"
191    if isinstance(ir, operations.Return):  # this can be improved using values
192        return "return"  # .format(ntype(ir.type))
193    if isinstance(ir, operations.Transfer):
194        return "transfer"
195    if isinstance(ir, operations.Send):
196        return "send"
197    if isinstance(ir, operations.Unpack):  # TODO: improve
198        return "unpack"
199    if isinstance(ir, operations.InitArray):  # TODO: improve
200        return "init_array"
201    # default
202    raise NotImplementedError(f"encode_ir_for_halstead: {ir}")
def ntype(_type: Union[slither.core.solidity_types.type.Type, str]) -> str:
18def ntype(_type: Union[solidity_types.Type, str]) -> str:
19    if isinstance(_type, solidity_types.ElementaryType):
20        _type = str(_type)
21    elif isinstance(_type, solidity_types.ArrayType):
22        if isinstance(_type.type, solidity_types.ElementaryType):
23            _type = str(_type)
24        else:
25            _type = "user_defined_array"
26    elif isinstance(_type, Structure):
27        _type = str(_type)
28    elif isinstance(_type, Enum):
29        _type = str(_type)
30    elif isinstance(_type, solidity_types.MappingType):
31        _type = str(_type)
32    elif isinstance(_type, solidity_types.UserDefinedType):
33        if isinstance(_type.type, Contract):
34            _type = f"contract({_type.type.name})"
35        elif isinstance(_type.type, Structure):
36            _type = f"struct({_type.type.name})"
37        elif isinstance(_type.type, Enum):
38            _type = f"enum({_type.type.name})"
39    else:
40        _type = str(_type)
41
42    _type = _type.replace(" memory", "")
43    _type = _type.replace(" storage ref", "")
44
45    if "struct" in _type:
46        return "struct"
47    if "enum" in _type:
48        return "enum"
49    if "tuple" in _type:
50        return "tuple"
51    if "contract" in _type:
52        return "contract"
53    if "mapping" in _type:
54        return "mapping"
55    return _type.replace(" ", "_")
59def encode_var_for_compare(var: Union[variables.Variable, SolidityVariable]) -> str:
60
61    # variables
62    if isinstance(var, SlitherIRVariable.Constant):
63        return f"constant({ntype(var.type)},{var.value})"
64    if isinstance(var, SolidityVariableComposed):
65        return f"solidity_variable_composed({var.name})"
66    if isinstance(var, SolidityVariable):
67        return f"solidity_variable{var.name}"
68    if isinstance(var, SlitherIRVariable.TemporaryVariable):
69        return "temporary_variable"
70    if isinstance(var, SlitherIRVariable.ReferenceVariable):
71        return f"reference({ntype(var.type)})"
72    if isinstance(var, variables.LocalVariable):
73        return f"local_solc_variable({ntype(var.type)},{var.location})"
74    if isinstance(var, variables.StateVariable):
75        if var.is_stored:
76            try:
77                slot, _ = var.contract.compilation_unit.storage_layout_of(var.contract, var)
78            except KeyError:
79                slot = var.name
80        else:
81            slot = var.name
82        return f"state_solc_variable({ntype(var.type)},{slot})"
83    if isinstance(var, variables.LocalVariableInitFromTuple):
84        return "local_variable_init_tuple"
85    if isinstance(var, SlitherIRVariable.TupleVariable):
86        return "tuple_variable"
87
88    # default
89    return ""
def encode_ir_for_upgradeability_compare(ir: slither.slithir.operations.operation.Operation) -> str:
 93def encode_ir_for_upgradeability_compare(ir: operations.Operation) -> str:
 94    # operations
 95    if isinstance(ir, operations.Assignment):
 96        return f"({encode_var_for_compare(ir.lvalue)}):=({encode_var_for_compare(ir.rvalue)})"
 97    if isinstance(ir, operations.Index):
 98        return f"index({ntype(ir.variable_right.type)})"
 99    if isinstance(ir, operations.Member):
100        return "member"  # .format(ntype(ir._type))
101    if isinstance(ir, operations.Length):
102        return "length"
103    if isinstance(ir, operations.Binary):
104        return f"binary({encode_var_for_compare(ir.variable_left)}{ir.type}{encode_var_for_compare(ir.variable_right)})"
105    if isinstance(ir, operations.Unary):
106        return f"unary({str(ir.type)})"
107    if isinstance(ir, operations.Condition):
108        return f"condition({encode_var_for_compare(ir.value)})"
109    if isinstance(ir, operations.NewStructure):
110        return "new_structure"
111    if isinstance(ir, operations.NewContract):
112        return "new_contract"
113    if isinstance(ir, operations.NewArray):
114        return f"new_array({ntype(ir.array_type)})"
115    if isinstance(ir, operations.NewElementaryType):
116        return f"new_elementary({ntype(ir.type)})"
117    if isinstance(ir, operations.Delete):
118        return f"delete({encode_var_for_compare(ir.lvalue)},{encode_var_for_compare(ir.variable)})"
119    if isinstance(ir, operations.SolidityCall):
120        return f"solidity_call({ir.function.full_name})"
121    if isinstance(ir, operations.InternalCall):
122        return f"internal_call({ntype(ir.type_call)})"
123    if isinstance(ir, operations.EventCall):  # is this useful?
124        return "event"
125    if isinstance(ir, operations.LibraryCall):
126        return "library_call"
127    if isinstance(ir, operations.InternalDynamicCall):
128        return "internal_dynamic_call"
129    if isinstance(ir, operations.HighLevelCall):  # TODO: improve
130        return "high_level_call"
131    if isinstance(ir, operations.LowLevelCall):  # TODO: improve
132        return "low_level_call"
133    if isinstance(ir, operations.TypeConversion):
134        return f"type_conversion({ntype(ir.type)})"
135    if isinstance(ir, operations.Return):  # this can be improved using values
136        return "return"  # .format(ntype(ir.type))
137    if isinstance(ir, operations.Transfer):
138        return f"transfer({encode_var_for_compare(ir.call_value)})"
139    if isinstance(ir, operations.Send):
140        return f"send({encode_var_for_compare(ir.call_value)})"
141    if isinstance(ir, operations.Unpack):  # TODO: improve
142        return "unpack"
143    if isinstance(ir, operations.InitArray):  # TODO: improve
144        return "init_array"
145
146    # default
147    return ""
def encode_ir_for_halstead(ir: slither.slithir.operations.operation.Operation) -> str:
150def encode_ir_for_halstead(ir: operations.Operation) -> str:
151    # operations
152    if isinstance(ir, operations.Assignment):
153        return "assignment"
154    if isinstance(ir, operations.Index):
155        return "index"
156    if isinstance(ir, operations.Member):
157        return "member"  # .format(ntype(ir._type))
158    if isinstance(ir, operations.Length):
159        return "length"
160    if isinstance(ir, operations.Binary):
161        return f"binary({str(ir.type)})"
162    if isinstance(ir, operations.Unary):
163        return f"unary({str(ir.type)})"
164    if isinstance(ir, operations.Condition):
165        return f"condition({encode_var_for_compare(ir.value)})"
166    if isinstance(ir, operations.NewStructure):
167        return "new_structure"
168    if isinstance(ir, operations.NewContract):
169        return "new_contract"
170    if isinstance(ir, operations.NewArray):
171        return f"new_array({ntype(ir.array_type)})"
172    if isinstance(ir, operations.NewElementaryType):
173        return f"new_elementary({ntype(ir.type)})"
174    if isinstance(ir, operations.Delete):
175        return "delete"
176    if isinstance(ir, operations.SolidityCall):
177        return f"solidity_call({ir.function.full_name})"
178    if isinstance(ir, operations.InternalCall):
179        return f"internal_call({ntype(ir.type_call)})"
180    if isinstance(ir, operations.EventCall):  # is this useful?
181        return "event"
182    if isinstance(ir, operations.LibraryCall):
183        return "library_call"
184    if isinstance(ir, operations.InternalDynamicCall):
185        return "internal_dynamic_call"
186    if isinstance(ir, operations.HighLevelCall):  # TODO: improve
187        return "high_level_call"
188    if isinstance(ir, operations.LowLevelCall):  # TODO: improve
189        return "low_level_call"
190    if isinstance(ir, operations.TypeConversion):
191        return f"type_conversion({ntype(ir.type)})"
192    if isinstance(ir, operations.Return):  # this can be improved using values
193        return "return"  # .format(ntype(ir.type))
194    if isinstance(ir, operations.Transfer):
195        return "transfer"
196    if isinstance(ir, operations.Send):
197        return "send"
198    if isinstance(ir, operations.Unpack):  # TODO: improve
199        return "unpack"
200    if isinstance(ir, operations.InitArray):  # TODO: improve
201        return "init_array"
202    # default
203    raise NotImplementedError(f"encode_ir_for_halstead: {ir}")