feat: highlight high fees in PSBTOverview and PSBTMath Screen
What changed, and why it matters
This commit adds a visual warning (a red "(!)") next to the fee label when a Bitcoin transaction has unusually high fees. It is a user-interface safety improvement, not a fix for a software vulnerability. There is no change to how transactions are validated, signed, or rejected.
No security action required. Treat as a normal feature/improvement commit. Reviewers may optionally verify that `psbt_parser.has_high_fee()` uses a sensible threshold, but that logic is outside this commit.
Security signals we found
UI warning for high transaction fees to reduce user error
No change to transaction validation, signing, or parsing logic
No memory-safety, cryptographic, or authorization changes
Evidence from the diff
The patch introduces an is_high_fee_tx flag that is passed into PSBTOverviewScreen and PSBTMathScreen. When true, the fee label is suffixed with ” (!)” and rendered in DIRE_WARNING_COLOR. The underlying fee-detection logic (psbt_parser.has_high_fee()) is not part of this diff; this change only consumes that result for display purposes. No cryptographic, parsing, or signing behavior is modified.
Changed components
src/seedsigner/gui/screens/psbt_screens.pysrc/seedsigner/views/psbt_views.pyInspect captured patch +27 / −3
### src/seedsigner/gui/screens/psbt_screens.py
@@ -25,6 +25,10 @@ class PSBTOverviewScreen(ButtonListScreen):
num_change_outputs: int = 0
destination_addresses: list[str] = None
has_op_return: bool = False
+ is_high_fee_tx: bool = False
+
+ # Appended to a row that needs the user's attention, drawn in the dire warning color
+ WARNING_MARK = " (!)"
def __post_init__(self):
@@ -147,7 +151,13 @@ def truncate_destination_addr(addr):
# TRANSLATOR_NOTE: Inserts the recipient number (e.g. the fifth one is: "recipient 5")
destination_column.append(_("recipient {}").format(len(self.destination_addresses) + self.num_self_transfer_outputs))
- destination_column.append(_("fee"))
+ fee_label = _("fee")
+ if self.is_high_fee_tx:
+ # Part of the label, not something appended at render time: the column is
+ # measured from these strings, so a mark added later would be drawn
+ # outside the width that was reserved for the row.
+ fee_label += PSBTOverviewScreen.WARNING_MARK
+ destination_column.append(fee_label)
if self.has_op_return:
# TRANSLATOR_NOTE: Technical term, should probably NOT be translated in most languages
@@ -308,11 +318,15 @@ def truncate_destination_addr(addr):
output_curves = []
for destination in destination_column:
+ text_color = chart_font_color
+ if destination.endswith(PSBTOverviewScreen.WARNING_MARK):
+ text_color = GUIConstants.DIRE_WARNING_COLOR
+
draw.text(
(recipients_text_x, destination_y),
text=destination,
font=font,
- fill=chart_font_color,
+ fill=text_color,
anchor="lt"
)
@@ -471,6 +485,7 @@ class PSBTMathScreen(ButtonListScreen):
num_recipients: int = 0
fee_amount: int = 0
change_amount: int = 0
+ is_high_fee_tx: bool = False
def __post_init__(self):
@@ -569,10 +584,17 @@ def render_amount(cur_y, amount_str, info_text, info_text_color=GUIConstants.BOD
)
cur_y += digits_height + GUIConstants.BODY_LINE_SPACING * ssf
+
+ info_text = _("fee")
+ info_text_color = GUIConstants.BODY_FONT_COLOR
+ if self.is_high_fee_tx:
+ info_text += PSBTOverviewScreen.WARNING_MARK
+ info_text_color = GUIConstants.DIRE_WARNING_COLOR
render_amount(
cur_y,
f"-{self.fee_amount}",
- info_text=_("fee"),
+ info_text=info_text,
+ info_text_color=info_text_color,
)
cur_y += digits_height + GUIConstants.BODY_LINE_SPACING * ssf
### src/seedsigner/views/psbt_views.py
@@ -176,6 +176,7 @@ def run(self):
num_change_outputs=num_change_outputs,
destination_addresses=psbt_parser.destination_addresses,
has_op_return=psbt_parser.op_return_data is not None,
+ is_high_fee_tx=is_high_fee_tx,
)
if selected_menu_num == RET_CODE__BACK_BUTTON:
@@ -297,6 +298,7 @@ def run(self):
num_recipients=psbt_parser.num_destinations,
fee_amount=psbt_parser.fee_amount,
change_amount=psbt_parser.change_amount,
+ is_high_fee_tx=psbt_parser.has_high_fee(),
)
if selected_menu_num == RET_CODE__BACK_BUTTON:Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.