Skip to content

Commit b5d01ae

Browse files
authored
fix: adjust utils for BigNumber usage (#179)
1 parent bf05c3e commit b5d01ae

File tree

2 files changed

+52
-31
lines changed

2 files changed

+52
-31
lines changed

crypto/utils/unit_converter.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
11
# import numpy as np
2-
from decimal import Decimal
2+
from decimal import Decimal, getcontext
33
from typing import Union
44

5+
# Python's Decimal type defaults to 28 digits of precision, which is not enough
6+
# for blockchain math. The largest possible value (uint256) has 78 digits, so we
7+
# increase the precision to 78 to avoid rounding errors when working with big numbers.
8+
getcontext().prec = 78
9+
510
class UnitConverter:
611
WEI_MULTIPLIER = '1'
712
GWEI_MULTIPLIER = '1000000000' # 1e9
813
ARK_MULTIPLIER = '1000000000000000000' # 1e18
914

1015
@staticmethod
11-
def parse_units(value: Union[float, int, str, Decimal], unit='ark') -> int:
16+
def parse_units(value: Union[float, int, str, Decimal], unit='ark') -> Decimal:
1217
value = Decimal(str(value))
1318

1419
unit = unit.lower()
1520
if unit == 'wei':
16-
return int((value * Decimal(UnitConverter.WEI_MULTIPLIER)).normalize())
21+
return (value * Decimal(UnitConverter.WEI_MULTIPLIER)).normalize()
1722

1823
if unit == 'gwei':
19-
return int((value * Decimal(UnitConverter.GWEI_MULTIPLIER)).normalize())
24+
return (value * Decimal(UnitConverter.GWEI_MULTIPLIER)).normalize()
2025

2126
if unit == 'ark':
22-
return int((value * Decimal(UnitConverter.ARK_MULTIPLIER)).normalize())
27+
return (value * Decimal(UnitConverter.ARK_MULTIPLIER)).normalize()
2328

2429
raise ValueError(f"Unsupported unit: {unit}. Supported units are 'wei', 'gwei', and 'ark'.")
2530

tests/utils/test_unit_converter.py

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,47 @@
22
from decimal import Decimal
33

44
def test_it_should_parse_units_into_wei():
5-
assert UnitConverter.parse_units(1, 'wei') == 1
6-
assert UnitConverter.parse_units(1.0, 'wei') == 1
7-
assert UnitConverter.parse_units('1', 'wei') == 1
8-
assert UnitConverter.parse_units('1.0', 'wei') == 1
5+
assert UnitConverter.parse_units(1, 'wei') == Decimal('1')
6+
assert UnitConverter.parse_units(1.0, 'wei') == Decimal('1')
7+
assert UnitConverter.parse_units('1', 'wei') == Decimal('1')
8+
assert UnitConverter.parse_units('1.0', 'wei') == Decimal('1')
99

10-
assert UnitConverter.parse_units(Decimal(1), 'wei') == 1
11-
assert UnitConverter.parse_units(Decimal(1.0), 'wei') == 1
12-
assert UnitConverter.parse_units(Decimal('1'), 'wei') == 1
13-
assert UnitConverter.parse_units(Decimal('1.0'), 'wei') == 1
10+
assert UnitConverter.parse_units(Decimal(1), 'wei') == Decimal('1')
11+
assert UnitConverter.parse_units(Decimal(1.0), 'wei') == Decimal('1')
12+
assert UnitConverter.parse_units(Decimal('1'), 'wei') == Decimal('1')
13+
assert UnitConverter.parse_units(Decimal('1.0'), 'wei') == Decimal('1')
14+
15+
assert isinstance(UnitConverter.parse_units(1, 'wei'), Decimal)
1416

1517
def test_it_should_parse_units_into_gwei():
16-
assert UnitConverter.parse_units(1, 'gwei') == 1000000000
17-
assert UnitConverter.parse_units(1.0, 'gwei') == 1000000000
18-
assert UnitConverter.parse_units('1', 'gwei') == 1000000000
19-
assert UnitConverter.parse_units('1.0', 'gwei') == 1000000000
18+
assert UnitConverter.parse_units(1, 'gwei') == Decimal('1000000000')
19+
assert UnitConverter.parse_units(1.0, 'gwei') == Decimal('1000000000')
20+
assert UnitConverter.parse_units('1', 'gwei') == Decimal('1000000000')
21+
assert UnitConverter.parse_units('1.0', 'gwei') == Decimal('1000000000')
22+
23+
assert UnitConverter.parse_units(Decimal(1), 'gwei') == Decimal('1000000000')
24+
assert UnitConverter.parse_units(Decimal(1.0), 'gwei') == Decimal('1000000000')
25+
assert UnitConverter.parse_units(Decimal('1'), 'gwei') == Decimal('1000000000')
26+
assert UnitConverter.parse_units(Decimal('1.0'), 'gwei') == Decimal('1000000000')
2027

21-
assert UnitConverter.parse_units(Decimal(1), 'gwei') == 1000000000
22-
assert UnitConverter.parse_units(Decimal(1.0), 'gwei') == 1000000000
23-
assert UnitConverter.parse_units(Decimal('1'), 'gwei') == 1000000000
24-
assert UnitConverter.parse_units(Decimal('1.0'), 'gwei') == 1000000000
28+
assert isinstance(UnitConverter.parse_units(1, 'gwei'), Decimal)
2529

2630
def test_it_should_parse_units_into_ark():
27-
assert UnitConverter.parse_units(1, 'ark') == 1000000000000000000
28-
assert UnitConverter.parse_units(1.0, 'ark') == 1000000000000000000
29-
assert UnitConverter.parse_units('1', 'ark') == 1000000000000000000
30-
assert UnitConverter.parse_units('1.0', 'ark') == 1000000000000000000
31+
assert UnitConverter.parse_units(1, 'ark') == Decimal('1000000000000000000')
32+
assert UnitConverter.parse_units(1.0, 'ark') == Decimal('1000000000000000000')
33+
assert UnitConverter.parse_units('1', 'ark') == Decimal('1000000000000000000')
34+
assert UnitConverter.parse_units('1.0', 'ark') == Decimal('1000000000000000000')
3135

32-
assert UnitConverter.parse_units(Decimal(1), 'ark') == 1000000000000000000
33-
assert UnitConverter.parse_units(Decimal(1.0), 'ark') == 1000000000000000000
34-
assert UnitConverter.parse_units(Decimal('1'), 'ark') == 1000000000000000000
35-
assert UnitConverter.parse_units(Decimal('1.0'), 'ark') == 1000000000000000000
36+
assert UnitConverter.parse_units(Decimal(1), 'ark') == Decimal('1000000000000000000')
37+
assert UnitConverter.parse_units(Decimal(1.0), 'ark') == Decimal('1000000000000000000')
38+
assert UnitConverter.parse_units(Decimal('1'), 'ark') == Decimal('1000000000000000000')
39+
assert UnitConverter.parse_units(Decimal('1.0'), 'ark') == Decimal('1000000000000000000')
40+
41+
assert isinstance(UnitConverter.parse_units(1, 'ark'), Decimal)
3642

3743
def test_it_should_parse_decimal_units_into_ark():
38-
assert UnitConverter.parse_units(0.1, 'ark') == 100000000000000000
39-
assert UnitConverter.parse_units('0.1', 'ark') == 100000000000000000
44+
assert UnitConverter.parse_units(0.1, 'ark') == Decimal('100000000000000000')
45+
assert UnitConverter.parse_units('0.1', 'ark') == Decimal('100000000000000000')
4046

4147
def test_it_should_format_units_from_wei():
4248
assert UnitConverter.format_units(1, 'wei') == 1.0
@@ -120,3 +126,13 @@ def test_it_should_convert_gwei_to_ark():
120126
assert UnitConverter.gwei_to_ark(Decimal('1')) == '0.000000001'
121127
assert UnitConverter.gwei_to_ark(Decimal('1000000000'), 'DARK') == '1 DARK'
122128
assert UnitConverter.gwei_to_ark(Decimal('1000000000')) == '1'
129+
130+
def test_it_should_handle_large_token_supply():
131+
large_supply = '999999999999999999999999999999999999999'
132+
result = UnitConverter.format_units(large_supply, 'ark')
133+
assert isinstance(result, Decimal)
134+
assert result == Decimal('999999999999999999999.999999999999999999')
135+
136+
result = UnitConverter.parse_units(large_supply, 'wei')
137+
assert isinstance(result, Decimal)
138+
assert result == Decimal(large_supply)

0 commit comments

Comments
 (0)