Skip to content

Commit

Permalink
feat(base_types): Add Wei type (#825)
Browse files Browse the repository at this point in the history
* feat(base_types): Add Wei

* docs: changelog

* Apply suggestions from code review

Co-authored-by: danceratopz <[email protected]>

* fix(base_types): tox

---------

Co-authored-by: danceratopz <[email protected]>
  • Loading branch information
marioevz and danceratopz authored Sep 24, 2024
1 parent a90b001 commit 8fe6a4d
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Test fixtures for use by clients are available for each release on the [Github r
- 🐞 Fix erroneous fork message in pytest session header with development forks ([#806](https://github.com/ethereum/execution-spec-tests/pull/806)).
- 🐞 Fix `Conditional` code generator in EOF mode ([#821](https://github.com/ethereum/execution-spec-tests/pull/821))
- 🔀 `ethereum_test_rpc` library has been created with what was previously `ethereum_test_tools.rpc` ([#822](https://github.com/ethereum/execution-spec-tests/pull/822))
- ✨ Add `Wei` type to `ethereum_test_base_types` which allows parsing wei amounts from strings like "1 ether", "1000 wei", "10**2 gwei", etc ([#825](https://github.com/ethereum/execution-spec-tests/pull/825))

### 🔧 EVM Tools

Expand Down
2 changes: 2 additions & 0 deletions src/ethereum_test_base_types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
HexNumber,
Number,
NumberBoundTypeVar,
Wei,
ZeroPaddedHexNumber,
)
from .composite_types import Account, Alloc, Storage, StorageRootType
Expand Down Expand Up @@ -60,6 +61,7 @@
"TestAddress2",
"TestPrivateKey",
"TestPrivateKey2",
"Wei",
"ZeroPaddedHexNumber",
"to_bytes",
"to_hex",
Expand Down
50 changes: 50 additions & 0 deletions src/ethereum_test_base_types/base_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,56 @@ def or_none(cls: Type[N], input: N | NumberConvertible | None) -> N | None:
return cls(input)


class Wei(Number):
"""
Class that helps represent wei that can be parsed from strings
"""

def __new__(cls, input: NumberConvertible | N):
"""
Creates a new Number object.
"""
if isinstance(input, str):
words = input.split()
multiplier = 1
assert len(words) <= 2
value_str = words[0]
if len(words) > 1:
unit = words[1].lower()
multiplier = cls._get_multiplier(unit)
value: float
if "**" in value_str:
base, exp = value_str.split("**")
value = float(base) ** int(exp)
else:
value = float(value_str)
return super(Number, cls).__new__(cls, value * multiplier)
return super(Number, cls).__new__(cls, to_number(input))

@staticmethod
def _get_multiplier(unit: str) -> int:
"""
Returns the multiplier for the given unit of wei, handling synonyms.
"""
match unit:
case "wei":
return 1
case "kwei" | "babbage" | "femtoether":
return 10**3
case "mwei" | "lovelace" | "picoether":
return 10**6
case "gwei" | "shannon" | "nanoether" | "nano":
return 10**9
case "szabo" | "microether" | "micro":
return 10**12
case "finney" | "milliether" | "milli":
return 10**15
case "ether":
return 10**18
case _:
raise ValueError(f"Invalid unit {unit}")


class HexNumber(Number):
"""
Class that helps represent an hexadecimal numbers in tests.
Expand Down
41 changes: 40 additions & 1 deletion src/ethereum_test_base_types/tests/test_base_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import pytest

from ..base_types import Address, Hash
from ..base_types import Address, Hash, Wei


@pytest.mark.parametrize(
Expand Down Expand Up @@ -52,3 +52,42 @@ def test_comparisons(a: Any, b: Any, equal: bool):
else:
assert a != b
assert not a == b


@pytest.mark.parametrize(
"s, expected",
[
("0", 0),
("10**18", 10**18),
("1e18", 10**18),
("1 ether", 10**18),
("2 ether", 2 * 10**18),
("2.1 ether", 2.1 * 10**18),
("2.1 Ether", 2.1 * 10**18),
("2.1 ETHER", 2.1 * 10**18),
("1 wei", 1),
("10**9 wei", 10**9),
("1 gwei", 10**9),
("1 szabo", 10**12),
("1 finney", 10**15),
("1 kwei", 10**3),
("1 mwei", 10**6),
("1 babbage", 10**3),
("1 femtoether", 10**3),
("1 Lovelace", 10**6),
("1 Picoether", 10**6),
("1 gwei", 10**9),
("1 shannon", 10**9),
("1 nanoether", 10**9),
("1 nano", 10**9),
("1 microether", 10**12),
("1 micro", 10**12),
("1 milliether", 10**15),
("1 milli", 10**15),
],
)
def test_wei_parsing(s: str, expected: int):
"""
Test the parsing of wei values.
"""
assert Wei(s) == expected

0 comments on commit 8fe6a4d

Please sign in to comment.