diff --git a/electrum/fee_policy.py b/electrum/fee_policy.py index 33b7eb384..f02e545c8 100644 --- a/electrum/fee_policy.py +++ b/electrum/fee_policy.py @@ -2,6 +2,7 @@ from typing import Optional, Sequence, Tuple, Union, TYPE_CHECKING, Dict from decimal import Decimal from numbers import Real from enum import IntEnum +import math from .i18n import _ from .util import NoDynamicFeeEstimates, quantize_feerate, format_fee_satoshis @@ -257,11 +258,15 @@ class FeePolicy(Logger): else: raise NoDynamicFeeEstimates() - return self.estimate_fee_for_feerate(fee_per_kb, size) + return self.estimate_fee_for_feerate(fee_per_kb=fee_per_kb, size=size) @classmethod - def estimate_fee_for_feerate(cls, fee_per_kb: Union[int, float, Decimal], - size: Union[int, float, Decimal]) -> int: + def estimate_fee_for_feerate( + cls, + *, + fee_per_kb: Union[int, float, Decimal], + size: Union[int, float, Decimal], + ) -> int: # note: 'size' is in vbytes size = Decimal(size) fee_per_kb = Decimal(fee_per_kb) @@ -269,7 +274,7 @@ class FeePolicy(Logger): # to be consistent with what is displayed in the GUI, # the calculation needs to use the same precision: fee_per_byte = quantize_feerate(fee_per_byte) - return round(fee_per_byte * size) + return math.ceil(fee_per_byte * size) class FixedFeePolicy(FeePolicy): diff --git a/electrum/gui/qml/qetxfinalizer.py b/electrum/gui/qml/qetxfinalizer.py index 1b378d608..5e691732a 100644 --- a/electrum/gui/qml/qetxfinalizer.py +++ b/electrum/gui/qml/qetxfinalizer.py @@ -887,8 +887,8 @@ class QETxCpfpFeeBumper(TxFeeSlider, TxMonMixin): def get_child_fee_from_total_feerate(self, fee_per_kb: Optional[int]) -> Optional[int]: if fee_per_kb is None: return None - fee = fee_per_kb * self._total_size / 1000 - self._parent_fee - fee = round(fee) + package_fee = FeePolicy.estimate_fee_for_feerate(fee_per_kb=fee_per_kb, size=self._total_size) + fee = package_fee - self._parent_fee fee = min(self._max_fee, fee) fee = max(self._total_size, fee) # pay at least 1 sat/byte for combined size return fee diff --git a/electrum/gui/qt/confirm_tx_dialog.py b/electrum/gui/qt/confirm_tx_dialog.py index 6ab873331..d6047eb24 100644 --- a/electrum/gui/qt/confirm_tx_dialog.py +++ b/electrum/gui/qt/confirm_tx_dialog.py @@ -350,7 +350,10 @@ class TxEditor(WindowModalDialog): # fallback to actual fee displayed_feerate = quantize_feerate(fee / size) if fee is not None else None self.feerate_e.setAmount(displayed_feerate) - displayed_fee = round(displayed_feerate * size) if displayed_feerate is not None else None + if displayed_feerate is not None: + displayed_fee = FeePolicy.estimate_fee_for_feerate(fee_per_kb=displayed_feerate * 1000, size=size) + else: + displayed_fee = None self.fee_e.setAmount(displayed_fee) else: if freeze_fee: diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index ef69b7208..21c5c286e 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -2874,8 +2874,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): def get_child_fee_from_total_feerate(fee_per_kb: Optional[int]) -> Optional[int]: if fee_per_kb is None: return None - fee = fee_per_kb * total_size / 1000 - parent_fee - fee = round(fee) + package_fee = FeePolicy.estimate_fee_for_feerate(fee_per_kb=fee_per_kb, size=total_size) + fee = package_fee - parent_fee fee = min(max_fee, fee) fee = max(total_size, fee) # pay at least 1 sat/byte for combined size return fee