Browse Source

util.format_satoshis: fix for amounts with higher than sat precision

Previously, msat precision was leaking through format_satoshis if the
user's base unit was set to "sat". This was a bug.
Some features of format_satoshis did not work well with such values, such
as the "whitespaces" param.

Old code:

>>> util.format_satoshis(Decimal('45831275.748'), decimal_point=2)
'458312.76'
>>> util.format_satoshis(Decimal('45831275.748'), decimal_point=0)
'45831275.748'

New code:

>>> util.format_satoshis(Decimal('45831275.748'), decimal_point=2)
'458312.76'
>>> util.format_satoshis(Decimal('45831275.748'), decimal_point=0)
'45831276.'
patch-4
SomberNight 4 years ago
parent
commit
5c80293696
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 21
      electrum/tests/test_util.py
  2. 26
      electrum/util.py

21
electrum/tests/test_util.py

@ -23,6 +23,22 @@ class TestUtil(ElectrumTestCase):
def test_format_satoshis_decimal(self):
self.assertEqual("0.00001234", format_satoshis(Decimal(1234)))
def test_format_satoshis_msat_resolution(self):
self.assertEqual("45831276.", format_satoshis(Decimal("45831276"), decimal_point=0))
self.assertEqual("45831276.", format_satoshis(Decimal("45831275.748"), decimal_point=0))
self.assertEqual("45831275.75", format_satoshis(Decimal("45831275.748"), decimal_point=0, precision=2))
self.assertEqual("45831275.748", format_satoshis(Decimal("45831275.748"), decimal_point=0, precision=3))
self.assertEqual("458312.76", format_satoshis(Decimal("45831276"), decimal_point=2))
self.assertEqual("458312.76", format_satoshis(Decimal("45831275.748"), decimal_point=2))
self.assertEqual("458312.7575", format_satoshis(Decimal("45831275.748"), decimal_point=2, precision=2))
self.assertEqual("458312.75748", format_satoshis(Decimal("45831275.748"), decimal_point=2, precision=3))
self.assertEqual("458.31276", format_satoshis(Decimal("45831276"), decimal_point=5))
self.assertEqual("458.31276", format_satoshis(Decimal("45831275.748"), decimal_point=5))
self.assertEqual("458.3127575", format_satoshis(Decimal("45831275.748"), decimal_point=5, precision=2))
self.assertEqual("458.31275748", format_satoshis(Decimal("45831275.748"), decimal_point=5, precision=3))
def test_format_fee_float(self):
self.assertEqual("1.7", format_fee_satoshis(1700/1000))
@ -48,11 +64,12 @@ class TestUtil(ElectrumTestCase):
format_satoshis(-1234, whitespaces=True))
def test_format_satoshis_diff_positive(self):
self.assertEqual("+0.00001234",
format_satoshis(1234, is_diff=True))
self.assertEqual("+0.00001234", format_satoshis(1234, is_diff=True))
self.assertEqual("+456789.00001234", format_satoshis(45678900001234, is_diff=True))
def test_format_satoshis_diff_negative(self):
self.assertEqual("-0.00001234", format_satoshis(-1234, is_diff=True))
self.assertEqual("-456789.00001234", format_satoshis(-45678900001234, is_diff=True))
def test_format_satoshis_plain(self):
self.assertEqual("0.00001234", format_satoshis_plain(1234))

26
electrum/util.py

@ -647,37 +647,37 @@ DECIMAL_POINT = localeconv()['decimal_point'] # type: str
def format_satoshis(
x, # in satoshis
x: Union[int, float, Decimal, str, None], # amount in satoshis
*,
num_zeros=0,
decimal_point=8,
precision=None,
is_diff=False,
whitespaces=False,
num_zeros: int = 0,
decimal_point: int = 8, # how much to shift decimal point to left (default: sat->BTC)
precision: int = 0, # extra digits after satoshi precision
is_diff: bool = False, # if True, enforce a leading sign (+/-)
whitespaces: bool = False, # if True, add whitespaces, to align numbers in a column
) -> str:
if x is None:
return 'unknown'
if x == '!':
return 'max'
if precision is None:
precision = decimal_point
assert isinstance(x, (int, float, Decimal)), f"{x!r} should be a number"
# lose redundant precision
x = Decimal(x).quantize(Decimal(10) ** (-precision))
# format string
decimal_format = "." + str(precision) if precision > 0 else ""
overall_precision = decimal_point + precision # max digits after final decimal point
decimal_format = "." + str(overall_precision) if overall_precision > 0 else ""
if is_diff:
decimal_format = '+' + decimal_format
# initial result
scale_factor = pow(10, decimal_point)
if not isinstance(x, Decimal):
x = Decimal(x).quantize(Decimal('1E-8'))
result = ("{:" + decimal_format + "f}").format(x / scale_factor)
if "." not in result: result += "."
result = result.rstrip('0')
# extra decimal places
# add extra decimal places (zeros)
integer_part, fract_part = result.split(".")
if len(fract_part) < num_zeros:
fract_part += "0" * (num_zeros - len(fract_part))
result = integer_part + DECIMAL_POINT + fract_part
# leading/trailing whitespaces
# add leading/trailing whitespaces
if whitespaces:
result += " " * (decimal_point - len(fract_part))
result = " " * (15 - len(result)) + result

Loading…
Cancel
Save