diff --git a/slither/slithir/variables/constant.py b/slither/slithir/variables/constant.py index 52cabf701..5da2d9cc0 100644 --- a/slither/slithir/variables/constant.py +++ b/slither/slithir/variables/constant.py @@ -1,4 +1,3 @@ -from fractions import Fraction from functools import total_ordering from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint @@ -33,7 +32,7 @@ class Constant(SlithIRVariable): else: if val.isdigit(): self._type = ElementaryType("uint256") - self._val = int(Fraction(val)) + self._val = convert_string_to_int(val) else: self._type = ElementaryType("string") self._val = val diff --git a/slither/utils/arithmetic.py b/slither/utils/arithmetic.py index 69684d103..d14958541 100644 --- a/slither/utils/arithmetic.py +++ b/slither/utils/arithmetic.py @@ -1,38 +1,35 @@ from fractions import Fraction from slither.exceptions import SlitherException +from slither.utils.integer_conversion import convert_string_to_int # pylint: disable=too-many-branches def convert_subdenomination( value: str, sub: str ) -> int: # pylint: disable=too-many-return-statements - # to allow 0.1 ether conversion - if value[0:2] == "0x": - decimal_value = Fraction(int(value, 16)) - else: - decimal_value = Fraction(value) + decimal_value = convert_string_to_int(value) if sub == "wei": - return int(decimal_value) + return decimal_value if sub == "gwei": - return int(decimal_value * int(1e9)) + return decimal_value * 1e9 if sub == "szabo": - return int(decimal_value * int(1e12)) + return decimal_value * 1e12 if sub == "finney": - return int(decimal_value * int(1e15)) + return decimal_value * 1e15 if sub == "ether": - return int(decimal_value * int(1e18)) + return decimal_value * 1e18 if sub == "seconds": - return int(decimal_value) + return decimal_value if sub == "minutes": - return int(decimal_value * 60) + return decimal_value * 60 if sub == "hours": - return int(decimal_value * 60 * 60) + return decimal_value * 60 * 60 if sub == "days": - return int(decimal_value * 60 * 60 * 24) + return decimal_value * 60 * 60 * 24 if sub == "weeks": - return int(decimal_value * 60 * 60 * 24 * 7) + return decimal_value * 60 * 60 * 24 * 7 if sub == "years": - return int(decimal_value * 60 * 60 * 24 * 7 * 365) + return decimal_value * 60 * 60 * 24 * 7 * 365 raise SlitherException(f"Subdemonination conversion impossible {decimal_value} {sub}") diff --git a/slither/utils/integer_conversion.py b/slither/utils/integer_conversion.py index a410a956b..b7e2e98ff 100644 --- a/slither/utils/integer_conversion.py +++ b/slither/utils/integer_conversion.py @@ -4,11 +4,14 @@ from typing import Union from slither.exceptions import SlitherError -def convert_string_to_int(val: Union[str, int]) -> int: +def convert_string_to_fraction(val: Union[str, int]) -> Fraction: if isinstance(val, int): - return val + return Fraction(val) if val.startswith(("0x", "0X")): - return int(val, 16) + return Fraction(int(val, 16)) + + # Fractions do not support underscore separators (on Python <3.11) + val = val.replace('_', '') if "e" in val or "E" in val: base, expo = val.split("e") if "e" in val else val.split("E") @@ -23,6 +26,9 @@ def convert_string_to_int(val: Union[str, int]) -> int: f"{base}e{expo} is too large to fit in any Solidity integer size" ) return 0 - return int(Fraction(base) * Fraction(10**expo)) + return Fraction(base) * Fraction(10**expo) - return int(Fraction(val)) + return Fraction(val) + +def convert_string_to_int(val: Union[str, int]) -> int: + return int(convert_string_to_fraction(val)) diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index 2da1d7304..34ab34ffd 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -1,6 +1,5 @@ -from fractions import Fraction from slither.core.expressions import BinaryOperationType, Literal, UnaryOperationType -from slither.utils.integer_conversion import convert_string_to_int +from slither.utils.integer_conversion import convert_string_to_fraction, convert_string_to_int from slither.visitors.expression.expression import ExpressionVisitor @@ -73,13 +72,13 @@ class ConstantFolding(ExpressionVisitor): cf = ConstantFolding(expr, self._type) expr = cf.result() assert isinstance(expr, Literal) - set_val(expression, int(expr.value)) + set_val(expression, -convert_string_to_fraction(expr.value)) else: raise NotConstant def _post_literal(self, expression): try: - set_val(expression, Fraction(expression.value)) + set_val(expression, convert_string_to_fraction(expression.value)) except ValueError: raise NotConstant @@ -116,7 +115,7 @@ class ConstantFolding(ExpressionVisitor): cf = ConstantFolding(expression.expressions[0], self._type) expr = cf.result() assert isinstance(expr, Literal) - set_val(expression, int(expr.value)) + set_val(expression, convert_string_to_fraction(expr.value)) return raise NotConstant