diff --git a/src/ape_ethereum/_converters.py b/src/ape_ethereum/_converters.py index ca308ce77b..9e0ad6572a 100644 --- a/src/ape_ethereum/_converters.py +++ b/src/ape_ethereum/_converters.py @@ -1,3 +1,4 @@ +import re from decimal import Decimal from ape.api.convert import ConverterAPI @@ -18,6 +19,7 @@ "babbage": int(1e3), "wei": 1, } +NUMBER_PATTERN = re.compile(r"^-?\d{1,3}(?:[,_]?\d{3})*(?:\.\d+)?(?:[eE][+-]?\d+)?$") class WeiConversions(ConverterAPI): @@ -30,11 +32,12 @@ def is_convertible(self, value: str) -> bool: if " " not in value or len(value.split(" ")) > 2: return False - _, unit = value.split(" ") - - return unit.lower() in ETHER_UNITS + val, unit = value.split(" ") + return unit.lower() in ETHER_UNITS and bool(NUMBER_PATTERN.match(val)) def convert(self, value: str) -> int: value, unit = value.split(" ") - converted_value = int(Decimal(value) * ETHER_UNITS[unit.lower()]) + converted_value = int( + Decimal(value.replace("_", "").replace(",", "")) * ETHER_UNITS[unit.lower()] + ) return CurrencyValue(converted_value) diff --git a/tests/functional/conversion/test_ether.py b/tests/functional/conversion/test_ether.py index 0da615b648..ccb55de65a 100644 --- a/tests/functional/conversion/test_ether.py +++ b/tests/functional/conversion/test_ether.py @@ -6,6 +6,8 @@ from ape.exceptions import ConversionError from ape_ethereum._converters import ETHER_UNITS +TEN_THOUSAND_ETHER_IN_WEI = 10_000_000_000_000_000_000_000 + @pytest.mark.fuzzing @given( @@ -41,3 +43,15 @@ def test_no_registered_converter(convert): convert("something", ChecksumAddress) assert str(err.value) == "No conversion registered to handle 'something'." + + +@pytest.mark.parametrize("sep", (",", "_")) +def test_separaters(convert, sep): + """ + Show that separates, such as commands and underscores, are OK + in currency-string values, e.g. "10,000 ETH" is valid. + """ + currency_str = f"10{sep}000 ETHER" + actual = convert(currency_str, int) + expected = TEN_THOUSAND_ETHER_IN_WEI + assert actual == expected