Format the transaction window fee rate with 1 decimal place (#4286)
* Fix format_satoshi to properly handle non-integer values Handling the integer and fraction parts together via string formatting simplifies the initial composition because the default behavior manages the - sign, and the incorporation of the fractional part. * Limit fee rate output to one decimal place Via a new precision arg * Introduce format_fee_satoshis and use it for all fee display
This commit is contained in:
@@ -671,7 +671,7 @@ class ElectrumWindow(App):
|
||||
return format_satoshis_plain(amount, self.decimal_point())
|
||||
|
||||
def format_amount(self, x, is_diff=False, whitespaces=False):
|
||||
return format_satoshis(x, is_diff, 0, self.decimal_point(), whitespaces)
|
||||
return format_satoshis(x, 0, self.decimal_point(), is_diff=is_diff, whitespaces=whitespaces)
|
||||
|
||||
def format_amount_and_units(self, x):
|
||||
return format_satoshis_plain(x, self.decimal_point()) + ' ' + self.base_unit
|
||||
|
||||
@@ -44,8 +44,8 @@ from electrum.bitcoin import COIN, is_address, TYPE_ADDRESS
|
||||
from electrum import constants
|
||||
from electrum.plugins import run_hook
|
||||
from electrum.i18n import _
|
||||
from electrum.util import (format_time, format_satoshis, PrintError,
|
||||
format_satoshis_plain, NotEnoughFunds,
|
||||
from electrum.util import (format_time, format_satoshis, format_fee_satoshis,
|
||||
format_satoshis_plain, NotEnoughFunds, PrintError,
|
||||
UserCancelled, NoDynamicFeeEstimates, profiler,
|
||||
export_meta, import_meta, bh2u, bfh, InvalidPassword)
|
||||
from electrum import Transaction
|
||||
@@ -639,7 +639,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
self.require_fee_update = False
|
||||
|
||||
def format_amount(self, x, is_diff=False, whitespaces=False):
|
||||
return format_satoshis(x, is_diff, self.num_zeros, self.decimal_point, whitespaces)
|
||||
return format_satoshis(x, self.num_zeros, self.decimal_point, is_diff=is_diff, whitespaces=whitespaces)
|
||||
|
||||
def format_amount_and_units(self, amount):
|
||||
text = self.format_amount(amount) + ' '+ self.base_unit()
|
||||
@@ -649,7 +649,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
return text
|
||||
|
||||
def format_fee_rate(self, fee_rate):
|
||||
return format_satoshis(fee_rate/1000, False, self.num_zeros, 0, False) + ' sat/byte'
|
||||
return format_fee_satoshis(fee_rate/1000, self.num_zeros) + ' sat/byte'
|
||||
|
||||
def get_decimal_point(self):
|
||||
return self.decimal_point
|
||||
@@ -3192,5 +3192,3 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
self.need_update.set()
|
||||
self.msg_box(QPixmap(":icons/offline_tx.png"), None, _('Success'), _("Transaction added to wallet history"))
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import stat
|
||||
from copy import deepcopy
|
||||
|
||||
from .util import (user_dir, print_error, PrintError,
|
||||
NoDynamicFeeEstimates, format_satoshis)
|
||||
NoDynamicFeeEstimates, format_fee_satoshis)
|
||||
from .i18n import _
|
||||
|
||||
FEE_ETA_TARGETS = [25, 10, 5, 2]
|
||||
@@ -367,7 +367,11 @@ class SimpleConfig(PrintError):
|
||||
text is what we target: static fee / num blocks to confirm in / mempool depth
|
||||
tooltip is the corresponding estimate (e.g. num blocks for a static fee)
|
||||
"""
|
||||
rate_str = (format_satoshis(fee_rate/1000, False, 0, 0, False) + ' sat/byte') if fee_rate is not None else 'unknown'
|
||||
if fee_rate is None:
|
||||
rate_str = 'unknown'
|
||||
else:
|
||||
rate_str = format_fee_satoshis(fee_rate/1000) + ' sat/byte'
|
||||
|
||||
if dyn:
|
||||
if mempool:
|
||||
depth = self.depth_target(pos)
|
||||
|
||||
@@ -8,6 +8,43 @@ class TestUtil(unittest.TestCase):
|
||||
expected = "0.00001234"
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_format_satoshis_negative(self):
|
||||
result = format_satoshis(-1234)
|
||||
expected = "-0.00001234"
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_format_fee(self):
|
||||
result = format_satoshis(1700/1000, 0, 0)
|
||||
expected = "1.7"
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_format_fee_precision(self):
|
||||
result = format_satoshis(1666/1000, 0, 0, precision=6)
|
||||
expected = "1.666"
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
result = format_satoshis(1666/1000, 0, 0, precision=1)
|
||||
expected = "1.7"
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_format_satoshis_whitespaces(self):
|
||||
result = format_satoshis(12340, whitespaces=True)
|
||||
expected = " 0.0001234 "
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
result = format_satoshis(1234, whitespaces=True)
|
||||
expected = " 0.00001234"
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_format_satoshis_whitespaces_negative(self):
|
||||
result = format_satoshis(-12340, whitespaces=True)
|
||||
expected = " -0.0001234 "
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
result = format_satoshis(-1234, whitespaces=True)
|
||||
expected = " -0.00001234"
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_format_satoshis_diff_positive(self):
|
||||
result = format_satoshis(1234, is_diff=True)
|
||||
expected = "+0.00001234"
|
||||
@@ -67,4 +104,3 @@ class TestUtil(unittest.TestCase):
|
||||
|
||||
def test_parse_URI_parameter_polution(self):
|
||||
self.assertRaises(Exception, parse_URI, 'bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?amount=0.0003&label=test&amount=30.0')
|
||||
|
||||
|
||||
21
lib/util.py
21
lib/util.py
@@ -412,20 +412,18 @@ def format_satoshis_plain(x, decimal_point = 8):
|
||||
return "{:.8f}".format(Decimal(x) / scale_factor).rstrip('0').rstrip('.')
|
||||
|
||||
|
||||
def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 8, whitespaces=False):
|
||||
def format_satoshis(x, num_zeros=0, decimal_point=8, precision=None, is_diff=False, whitespaces=False):
|
||||
from locale import localeconv
|
||||
if x is None:
|
||||
return 'unknown'
|
||||
x = int(x) # Some callers pass Decimal
|
||||
scale_factor = pow (10, decimal_point)
|
||||
integer_part = "{:d}".format(int(abs(x) / scale_factor))
|
||||
if x < 0:
|
||||
integer_part = '-' + integer_part
|
||||
elif is_diff:
|
||||
integer_part = '+' + integer_part
|
||||
if precision is None:
|
||||
precision = decimal_point
|
||||
decimal_format = ".0" + str(precision) if precision > 0 else ""
|
||||
if is_diff:
|
||||
decimal_format = '+' + decimal_format
|
||||
result = ("{:" + decimal_format + "f}").format(x / pow (10, decimal_point)).rstrip('0')
|
||||
integer_part, fract_part = result.split(".")
|
||||
dp = localeconv()['decimal_point']
|
||||
fract_part = ("{:0" + str(decimal_point) + "}").format(abs(x) % scale_factor)
|
||||
fract_part = fract_part.rstrip('0')
|
||||
if len(fract_part) < num_zeros:
|
||||
fract_part += "0" * (num_zeros - len(fract_part))
|
||||
result = integer_part + dp + fract_part
|
||||
@@ -434,6 +432,9 @@ def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 8, whitespa
|
||||
result = " " * (15 - len(result)) + result
|
||||
return result
|
||||
|
||||
def format_fee_satoshis(fee, num_zeros=0):
|
||||
return format_satoshis(fee, num_zeros, 0, precision=1)
|
||||
|
||||
def timestamp_to_datetime(timestamp):
|
||||
if timestamp is None:
|
||||
return None
|
||||
|
||||
@@ -45,8 +45,8 @@ import sys
|
||||
|
||||
from .i18n import _
|
||||
from .util import (NotEnoughFunds, PrintError, UserCancelled, profiler,
|
||||
format_satoshis, NoDynamicFeeEstimates, TimeoutException,
|
||||
WalletFileException, BitcoinException)
|
||||
format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
|
||||
TimeoutException, WalletFileException, BitcoinException)
|
||||
|
||||
from .bitcoin import *
|
||||
from .version import *
|
||||
@@ -1169,7 +1169,7 @@ class Abstract_Wallet(PrintError):
|
||||
if fee is not None:
|
||||
size = tx.estimated_size()
|
||||
fee_per_byte = fee / size
|
||||
extra.append('%.1f sat/b'%(fee_per_byte))
|
||||
extra.append(format_fee_satoshis(fee_per_byte) + ' sat/b')
|
||||
if fee is not None and height in (TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED) \
|
||||
and self.network and self.network.config.has_fee_mempool():
|
||||
exp_n = self.network.config.fee_to_depth(fee_per_byte)
|
||||
@@ -2362,4 +2362,3 @@ class Wallet(object):
|
||||
if wallet_type in wallet_constructors:
|
||||
return wallet_constructors[wallet_type]
|
||||
raise RuntimeError("Unknown wallet type: " + str(wallet_type))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user