refactor(core): make SLIP-24 UI independent of ETH
What changed, and why it matters
This commit is a code cleanup that moves the user-confirmation screen for SLIP-24 payment requests out of Ethereum-specific code and into shared UI code. It does not change security checks or add new features; it only reorganizes how account, network, and token details are passed to the display layer. There is no clear security bug in the change itself.
No immediate action required. Treat as routine refactor. If auditing, verify that the new `account_items` list in `apps/ethereum/layout.py` still includes chain-id for all Ethereum payment-request confirmations and that optional `token_address` does not skip token-contract display when a token is involved.
Security signals we found
No new input validation added or removed
No cryptographic operations changed
No privilege boundary crossed
Refactor-only: function renamed and arguments repackaged
Optional token_address handling made explicit in confirm_trade
Evidence from the diff
The patch refactors confirm_ethereum_payment_request into a generic confirm_payment_request in three UI layout backends (caesar, delizia, eckhart). The Ethereum app now builds a list of account/derivation-path/chain-id items and passes it to the generic helper, instead of each UI backend constructing that list from separate arguments. confirm_trade now accepts an optional token_address. The logic flow and displayed data are essentially unchanged; this is an architectural decoupling of SLIP-24 UI from Ethereum.
Changed components
core/src/apps/ethereum/layout.pycore/src/trezor/ui/layouts/caesar/__init__.pycore/src/trezor/ui/layouts/delizia/__init__.pycore/src/trezor/ui/layouts/eckhart/__init__.pyInspect captured patch +322 / −343
diff --git a/core/src/apps/ethereum/layout.py b/core/src/apps/ethereum/layout.py
index 75c79398..f74405b8 100644
--- a/core/src/apps/ethereum/layout.py
+++ b/core/src/apps/ethereum/layout.py
@@ -120,9 +120,8 @@ async def require_confirm_payment_request(
token_address: str,
) -> None:
from trezor import wire
- from trezor.ui.layouts import confirm_ethereum_payment_request
+ from trezor.ui.layouts import confirm_payment_request
- account, account_path = get_account_and_path(address_n)
assert (
verified_payment_req.amount is not None
) # amount is required for non-CoinJoin transactions
@@ -159,15 +158,24 @@ async def require_confirm_payment_request(
else:
raise wire.DataError("Unrecognized memo type in payment request memo.")
- await confirm_ethereum_payment_request(
+ account, account_path = get_account_and_path(address_n)
+ account_items = []
+ if account:
+ account_items.append((TR.words__account, account))
+ if account_path:
+ account_items.append((TR.address_details__derivation_path, account_path))
+ if chain_id:
+ account_items.append(
+ (TR.ethereum__approve_chain_id, f"{network.name} ({chain_id})")
+ )
+
+ await confirm_payment_request(
verified_payment_req.recipient_name,
provider_address,
texts,
refunds,
trades,
- account,
- account_path,
- f"{network.name} ({chain_id})",
+ account_items,
maximum_fee,
fee_info_items,
token_address,
diff --git a/core/src/trezor/ui/layouts/caesar/__init__.py b/core/src/trezor/ui/layouts/caesar/__init__.py
index 2d93ad6d..d60e5acb 100644
--- a/core/src/trezor/ui/layouts/caesar/__init__.py
+++ b/core/src/trezor/ui/layouts/caesar/__init__.py
@@ -535,6 +535,95 @@ def show_continue_in_app(content: str) -> None:
return
+async def confirm_payment_request(
+ recipient_name: str,
+ recipient: str,
+ texts: Iterable[tuple[str | None, str]],
+ refunds: Iterable[tuple[str, str | None, str | None]],
+ trades: List[tuple[str, str, str, str | None, str | None]],
+ account_items: List[tuple[str, str]],
+ transaction_fee: str | None,
+ fee_info_items: Iterable[tuple[str, str]] | None,
+ token_address: str | None,
+) -> None:
+ from trezor.ui.layouts.menu import Menu, confirm_with_menu
+
+ # Note: we don't support "sales" (swap to fiat) yet,
+ # so if there is any trade, we assume it must be a swap
+ is_swap = len(trades) != 0
+
+ for title, text in texts:
+ await raise_if_cancelled(
+ trezorui_api.confirm_value(
+ title=title or (TR.words__swap if is_swap else TR.words__confirm),
+ value=text,
+ description=None,
+ ),
+ "confirm_payment_request",
+ )
+
+ main_layout = trezorui_api.confirm_with_info(
+ title=(TR.words__swap if is_swap else TR.words__confirm),
+ items=[(TR.words__provider, True), (recipient_name, False)],
+ verb=TR.buttons__continue,
+ verb_info=TR.buttons__info,
+ external_menu=True,
+ )
+
+ menu_items = [create_details(TR.address__title_provider_address, recipient)]
+ for r_address, r_account, r_account_path in refunds:
+ refund_account_items: list[tuple[str, str]] = [("", r_address)]
+ if r_account:
+ refund_account_items.append((TR.words__account, r_account))
+ if r_account_path:
+ refund_account_items.append(
+ (TR.address_details__derivation_path, r_account_path)
+ )
+ menu_items.append(
+ create_details(
+ TR.address__title_refund_address,
+ refund_account_items,
+ )
+ )
+ menu = Menu.root(menu_items)
+
+ await confirm_with_menu(main_layout, menu, "confirm_payment_request")
+
+ for sell_amount, buy_amount, t_address, t_account, t_account_path in trades:
+ await confirm_trade(
+ f"{TR.words__swap} {TR.words__assets}",
+ sell_amount,
+ buy_amount,
+ t_address,
+ t_account,
+ t_account_path,
+ token_address,
+ )
+
+ if transaction_fee is not None:
+ assert fee_info_items is not None
+
+ summary_layout = trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=transaction_fee,
+ fee_label=TR.words__transaction_fee,
+ title=TR.words__title_summary,
+ external_menu=True,
+ )
+
+ summary_menu_items = [
+ create_details(TR.confirm_total__title_fee, list(fee_info_items)),
+ create_details(TR.address_details__account_info, account_items),
+ ]
+
+ summary_menu = Menu.root(summary_menu_items)
+
+ await confirm_with_menu(
+ summary_layout, summary_menu, br_name="confirm_payment_request"
+ )
+
+
async def confirm_output(
address: str,
amount: str,
@@ -1065,7 +1154,7 @@ if not utils.BITCOIN_ONLY:
address: str,
account: str | None,
account_path: str | None,
- token_address: str,
+ token_address: str | None,
) -> None:
from trezor.ui.layouts.menu import Menu, confirm_with_menu
@@ -1081,111 +1170,14 @@ if not utils.BITCOIN_ONLY:
account_items.append((TR.words__account, account))
if account_path:
account_items.append((TR.address_details__derivation_path, account_path))
- menu = Menu.root(
- [
- create_details(
- TR.address__title_receive_address,
- account_items,
- ),
- create_details(TR.ethereum__token_contract, token_address),
- ]
- )
-
- await confirm_with_menu(trade_layout, menu, "confirm_trade")
-
- async def confirm_ethereum_payment_request(
- recipient_name: str,
- recipient: str,
- texts: Iterable[tuple[str | None, str]],
- refunds: Iterable[tuple[str, str | None, str | None]],
- trades: List[tuple[str, str, str, str | None, str | None]],
- account: str | None,
- account_path: str | None,
- chain_id: str,
- maximum_fee: str,
- fee_info_items: Iterable[tuple[str, str]],
- token_address: str,
- ) -> None:
- from trezor.ui.layouts.menu import Menu, confirm_with_menu
-
- # Note: we don't support "sales" (swap to fiat) yet,
- # so if there is any trade, we assume it must be a swap
- is_swap = len(trades) != 0
-
- for title, text in texts:
- await raise_if_cancelled(
- trezorui_api.confirm_value(
- title=title or (TR.words__swap if is_swap else TR.words__confirm),
- value=text,
- description=None,
- ),
- "confirm_payment_request",
- )
-
- main_layout = trezorui_api.confirm_with_info(
- title=(TR.words__swap if is_swap else TR.words__confirm),
- items=[(TR.words__provider, True), (recipient_name, False)],
- verb=TR.buttons__continue,
- verb_info=TR.buttons__info,
- external_menu=True,
- )
-
- menu_items = [create_details(TR.address__title_provider_address, recipient)]
- for r_address, r_account, r_account_path in refunds:
- refund_account_items: list[tuple[str, str]] = [("", r_address)]
- if r_account:
- refund_account_items.append((TR.words__account, r_account))
- if r_account_path:
- refund_account_items.append(
- (TR.address_details__derivation_path, r_account_path)
- )
+ menu_items = [create_details(TR.address__title_receive_address, account_items)]
+ if token_address is not None:
menu_items.append(
- create_details(
- TR.address__title_refund_address,
- refund_account_items,
- )
+ create_details(TR.ethereum__token_contract, token_address)
)
menu = Menu.root(menu_items)
- await confirm_with_menu(main_layout, menu, "confirm_payment_request")
-
- for sell_amount, buy_amount, t_address, t_account, t_account_path in trades:
- await confirm_trade(
- f"{TR.words__swap} {TR.words__assets}",
- sell_amount,
- buy_amount,
- t_address,
- t_account,
- t_account_path,
- token_address,
- )
-
- account_items = []
- if account:
- account_items.append((TR.words__account, account))
- if account_path:
- account_items.append((TR.address_details__derivation_path, account_path))
- account_items.append((TR.ethereum__approve_chain_id, chain_id))
-
- summary_layout = trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=TR.words__transaction_fee,
- title=TR.words__title_summary,
- external_menu=True,
- )
-
- summary_menu_items = [
- create_details(TR.confirm_total__title_fee, list(fee_info_items)),
- create_details(TR.address_details__account_info, account_items),
- ]
-
- summary_menu = Menu.root(summary_menu_items)
-
- await confirm_with_menu(
- summary_layout, summary_menu, br_name="confirm_payment_request"
- )
+ await confirm_with_menu(trade_layout, menu, "confirm_trade")
async def confirm_ethereum_staking_tx(
title: str,
diff --git a/core/src/trezor/ui/layouts/delizia/__init__.py b/core/src/trezor/ui/layouts/delizia/__init__.py
index 6625568d..8ca7d4eb 100644
--- a/core/src/trezor/ui/layouts/delizia/__init__.py
+++ b/core/src/trezor/ui/layouts/delizia/__init__.py
@@ -477,6 +477,90 @@ def show_continue_in_app(content: str) -> None:
workflow.spawn(task)
+async def confirm_payment_request(
+ recipient_name: str,
+ recipient: str,
+ texts: Iterable[tuple[str | None, str]],
+ refunds: Iterable[tuple[str, str | None, str | None]],
+ trades: List[tuple[str, str, str, str | None, str | None]],
+ account_items: List[tuple[str, str]],
+ transaction_fee: str | None,
+ fee_info_items: Iterable[tuple[str, str]] | None,
+ token_address: str | None,
+) -> None:
+ from trezor.ui.layouts.menu import Menu, confirm_with_menu
+
+ # Note: we don't support "sales" (swap to fiat) yet,
+ # so if there is any trade, we assume it must be a swap
+ is_swap = len(trades) != 0
+
+ for title, text in texts:
+ await raise_if_cancelled(
+ trezorui_api.confirm_value(
+ title=(title or (TR.words__swap if is_swap else TR.words__confirm)),
+ value=text,
+ is_data=False,
+ description=None,
+ ),
+ "confirm_payment_request",
+ )
+
+ main_layout = trezorui_api.confirm_value(
+ title=(TR.words__swap if is_swap else TR.words__confirm),
+ subtitle=TR.words__provider,
+ value=recipient_name,
+ description=None,
+ verb=TR.instructions__tap_to_continue,
+ verb_cancel=None,
+ chunkify=False,
+ external_menu=True,
+ )
+
+ menu_items = [create_details(TR.address__title_provider_address, recipient)]
+ for r_address, r_account, r_account_path in refunds:
+ refund_account_items: list[tuple[str, str]] = [("", r_address)]
+ if r_account:
+ refund_account_items.append((TR.words__account, r_account))
+ if r_account_path:
+ refund_account_items.append(
+ (TR.address_details__derivation_path, r_account_path)
+ )
+ menu_items.append(
+ create_details(
+ TR.address__title_refund_address,
+ refund_account_items,
+ )
+ )
+ menu = Menu.root(menu_items, TR.send__cancel_sign)
+
+ await confirm_with_menu(main_layout, menu, "confirm_payment_request")
+
+ for sell_amount, buy_amount, t_address, t_account, t_account_path in trades:
+ await confirm_trade(
+ TR.words__swap,
+ TR.words__assets,
+ sell_amount,
+ buy_amount,
+ t_address,
+ t_account,
+ t_account_path,
+ token_address,
+ )
+
+ if transaction_fee is not None:
+ await _confirm_summary(
+ None,
+ None,
+ transaction_fee,
+ TR.words__transaction_fee,
+ TR.words__title_summary,
+ account_items,
+ fee_info_items,
+ TR.confirm_total__title_fee,
+ "confirm_payment_request",
+ )
+
+
async def confirm_output(
address: str,
amount: str | None = None,
@@ -1045,7 +1129,7 @@ if not utils.BITCOIN_ONLY:
address: str,
account: str | None,
account_path: str | None,
- token_address: str,
+ token_address: str | None,
) -> None:
from trezor.ui.layouts.menu import Menu, confirm_with_menu
@@ -1061,108 +1145,14 @@ if not utils.BITCOIN_ONLY:
account_items.append((TR.words__account, account))
if account_path:
account_items.append((TR.address_details__derivation_path, account_path))
- menu = Menu.root(
- [
- create_details(
- TR.address__title_receive_address,
- account_items,
- ),
- create_details(TR.ethereum__token_contract, token_address),
- ],
- TR.send__cancel_sign,
- )
-
- await confirm_with_menu(trade_layout, menu, "confirm_trade")
-
- async def confirm_ethereum_payment_request(
- recipient_name: str,
- recipient: str,
- texts: Iterable[tuple[str | None, str]],
- refunds: Iterable[tuple[str, str | None, str | None]],
- trades: List[tuple[str, str, str, str | None, str | None]],
- account: str | None,
- account_path: str | None,
- chain_id: str,
- maximum_fee: str,
- fee_info_items: Iterable[tuple[str, str]],
- token_address: str,
- ) -> None:
- from trezor.ui.layouts.menu import Menu, confirm_with_menu
-
- # Note: we don't support "sales" (swap to fiat) yet,
- # so if there is any trade, we assume it must be a swap
- is_swap = len(trades) != 0
-
- for title, text in texts:
- await raise_if_cancelled(
- trezorui_api.confirm_value(
- title=(title or (TR.words__swap if is_swap else TR.words__confirm)),
- value=text,
- description=None,
- ),
- "confirm_payment_request",
- )
-
- main_layout = trezorui_api.confirm_value(
- title=(TR.words__swap if is_swap else TR.words__confirm),
- subtitle=TR.words__provider,
- value=recipient_name,
- description=None,
- verb=TR.instructions__tap_to_continue,
- verb_cancel=None,
- chunkify=False,
- external_menu=True,
- )
-
- menu_items = [create_details(TR.address__title_provider_address, recipient)]
- for r_address, r_account, r_account_path in refunds:
- refund_account_items: list[tuple[str, str]] = [("", r_address)]
- if r_account:
- refund_account_items.append((TR.words__account, r_account))
- if r_account_path:
- refund_account_items.append(
- (TR.address_details__derivation_path, r_account_path)
- )
+ menu_items = [create_details(TR.address__title_receive_address, account_items)]
+ if token_address is not None:
menu_items.append(
- create_details(
- TR.address__title_refund_address,
- refund_account_items,
- )
+ create_details(TR.ethereum__token_contract, token_address)
)
menu = Menu.root(menu_items, TR.send__cancel_sign)
- await confirm_with_menu(main_layout, menu, "confirm_payment_request")
-
- for sell_amount, buy_amount, t_address, t_account, t_account_path in trades:
- await confirm_trade(
- TR.words__swap,
- TR.words__assets,
- sell_amount,
- buy_amount,
- t_address,
- t_account,
- t_account_path,
- token_address,
- )
-
- account_items = []
- if account:
- account_items.append((TR.words__account, account))
- if account_path:
- account_items.append((TR.address_details__derivation_path, account_path))
- account_items.append((TR.ethereum__approve_chain_id, chain_id))
-
- await _confirm_summary(
- None,
- None,
- maximum_fee,
- TR.words__transaction_fee,
- TR.words__title_summary,
- account_items,
- fee_info_items,
- TR.confirm_total__title_fee,
- "confirm_payment_request",
- )
+ await confirm_with_menu(trade_layout, menu, "confirm_trade")
async def confirm_ethereum_staking_tx(
title: str,
diff --git a/core/src/trezor/ui/layouts/eckhart/__init__.py b/core/src/trezor/ui/layouts/eckhart/__init__.py
index 5dc21616..57f470f5 100644
--- a/core/src/trezor/ui/layouts/eckhart/__init__.py
+++ b/core/src/trezor/ui/layouts/eckhart/__init__.py
@@ -464,6 +464,125 @@ def show_continue_in_app(content: str) -> None:
workflow.spawn(task)
+async def confirm_payment_request(
+ recipient_name: str,
+ recipient: str,
+ texts: Iterable[tuple[str | None, str]],
+ refunds: Iterable[tuple[str, str | None, str | None]],
+ trades: List[tuple[str, str, str, str | None, str | None]],
+ account_items: List[tuple[str, str]],
+ transaction_fee: str | None,
+ fee_info_items: Iterable[tuple[str, str]] | None,
+ token_address: str | None,
+) -> None:
+ from trezor.ui.layouts.menu import Menu, confirm_with_menu
+
+ # Note: we don't support "sales" (swap to fiat) yet,
+ # so if there is any trade, we assume it must be a swap
+ is_swap = len(trades) != 0
+
+ for title, text in texts:
+ await raise_if_cancelled(
+ trezorui_api.confirm_value(
+ title=(title or (TR.words__swap if is_swap else TR.words__confirm)),
+ value=text,
+ description=None,
+ verb=TR.buttons__confirm,
+ ),
+ "confirm_payment_request",
+ )
+
+ main_layout = trezorui_api.confirm_value(
+ title=(TR.words__swap if is_swap else TR.words__confirm),
+ subtitle=TR.words__provider,
+ value=recipient_name,
+ description=None,
+ verb=TR.buttons__continue,
+ verb_cancel=None,
+ chunkify=False,
+ external_menu=True,
+ )
+
+ menu_items = [create_details(TR.address__title_provider_address, recipient)]
+ for r_address, r_account, r_account_path in refunds:
+ refund_account_info = [(str(""), r_address)]
+ if r_account:
+ refund_account_info.append((TR.words__account, r_account))
+ if r_account_path:
+ refund_account_info.append(
+ (TR.address_details__derivation_path, r_account_path)
+ )
+ menu_items.append(
+ create_details(
+ TR.address__title_refund_address,
+ refund_account_info,
+ )
+ )
+ menu = Menu.root(menu_items, TR.send__cancel_sign)
+
+ while True:
+ back_from_confirm_trade = False
+ await confirm_with_menu(main_layout, menu, "confirm_payment_request")
+
+ while True:
+ back_from_confirm_trade = False
+
+ # HACK: if we have multiple trades to confirm, we disable the back button
+ # to simplify the mechanism we use here to handle it.
+ # In practice, this should never happen, since normally there is only one trade in a transaction,
+ # but in theory it can (since SLIP-24 supports multiple CoinPurchaseMemos...)
+ can_go_back_from_trade = len(trades) == 1
+
+ for (
+ sell_amount,
+ buy_amount,
+ t_address,
+ t_account,
+ t_account_path,
+ ) in trades:
+ res = await confirm_trade(
+ TR.words__swap,
+ TR.words__assets,
+ sell_amount,
+ buy_amount,
+ t_address,
+ t_account,
+ t_account_path,
+ token_address,
+ can_go_back_from_trade,
+ )
+ if res is BACK:
+ back_from_confirm_trade = True
+ break
+
+ if back_from_confirm_trade:
+ break
+
+ if transaction_fee is not None:
+ res = await _confirm_summary(
+ None,
+ None,
+ transaction_fee,
+ TR.words__transaction_fee,
+ TR.words__swap if is_swap else TR.words__title_summary,
+ account_items,
+ fee_info_items,
+ TR.confirm_total__title_fee,
+ True,
+ "confirm_payment_request",
+ )
+ if res is BACK:
+ continue
+ else:
+ break
+ else:
+ break
+ if back_from_confirm_trade:
+ continue
+ else:
+ break
+
+
async def confirm_output(
address: str,
amount: str | None = None,
@@ -1068,7 +1187,7 @@ if not utils.BITCOIN_ONLY:
address: str,
account: str | None,
account_path: str | None,
- token_address: str,
+ token_address: str | None,
back_button: bool,
) -> Awaitable[ui.UiResult]:
from trezor.ui.layouts.menu import Menu, interact_with_menu
@@ -1081,149 +1200,19 @@ if not utils.BITCOIN_ONLY:
back_button=back_button,
)
- account_info = [(str(""), address)]
+ account_info: list[tuple[str, str]] = [("", address)]
if account:
account_info.append((TR.words__account, account))
if account_path:
account_info.append((TR.address_details__derivation_path, account_path))
- menu = Menu.root(
- [
- create_details(
- TR.address__title_receive_address,
- account_info,
- ),
- create_details(TR.ethereum__token_contract, token_address),
- ],
- TR.send__cancel_sign,
- )
-
- return interact_with_menu(trade_layout, menu, "confirm_trade")
-
- async def confirm_ethereum_payment_request(
- recipient_name: str,
- recipient: str,
- texts: Iterable[tuple[str | None, str]],
- refunds: Iterable[tuple[str, str | None, str | None]],
- trades: List[tuple[str, str, str, str | None, str | None]],
- account: str | None,
- account_path: str | None,
- chain_id: str,
- maximum_fee: str,
- fee_info_items: Iterable[tuple[str, str]],
- token_address: str,
- ) -> None:
- from trezor.ui.layouts.menu import Menu, confirm_with_menu
-
- # Note: we don't support "sales" (swap to fiat) yet,
- # so if there is any trade, we assume it must be a swap
- is_swap = len(trades) != 0
-
- for title, text in texts:
- await raise_if_cancelled(
- trezorui_api.confirm_value(
- title=(title or (TR.words__swap if is_swap else TR.words__confirm)),
- value=text,
- description=None,
- verb=TR.buttons__confirm,
- ),
- "confirm_payment_request",
- )
-
- main_layout = trezorui_api.confirm_value(
- title=(TR.words__swap if is_swap else TR.words__confirm),
- subtitle=TR.words__provider,
- value=recipient_name,
- description=None,
- verb=TR.buttons__continue,
- verb_cancel=None,
- chunkify=False,
- external_menu=True,
- )
-
- menu_items = [create_details(TR.address__title_provider_address, recipient)]
- for r_address, r_account, r_account_path in refunds:
- refund_account_info = [(str(""), r_address)]
- if r_account:
- refund_account_info.append((TR.words__account, r_account))
- if r_account_path:
- refund_account_info.append(
- (TR.address_details__derivation_path, r_account_path)
- )
+ menu_items = [create_details(TR.address__title_receive_address, account_info)]
+ if token_address is not None:
menu_items.append(
- create_details(
- TR.address__title_refund_address,
- refund_account_info,
- )
+ create_details(TR.ethereum__token_contract, token_address)
)
menu = Menu.root(menu_items, TR.send__cancel_sign)
- while True:
- back_from_confirm_trade = False
- await confirm_with_menu(main_layout, menu, "confirm_payment_request")
-
- while True:
- back_from_confirm_trade = False
-
- # HACK: if we have multiple trades to confirm, we disable the back button
- # to simplify the mechanism we use here to handle it.
- # In practice, this should never happen, since normally there is only one trade in a transaction,
- # but in theory it can (since SLIP-24 supports multiple CoinPurchaseMemos...)
- can_go_back_from_trade = len(trades) == 1
-
- for (
- sell_amount,
- buy_amount,
- t_address,
- t_account,
- t_account_path,
- ) in trades:
- res = await confirm_trade(
- TR.words__swap,
- TR.words__assets,
- sell_amount,
- buy_amount,
- t_address,
- t_account,
- t_account_path,
- token_address,
- can_go_back_from_trade,
- )
- if res is BACK:
- back_from_confirm_trade = True
- break
-
- if back_from_confirm_trade:
- break
-
- account_items = []
- if account:
- account_items.append((TR.words__account, account))
- if account_path:
- account_items.append(
- (TR.address_details__derivation_path, account_path)
- )
- account_items.append((TR.ethereum__approve_chain_id, chain_id))
-
- res = await _confirm_summary(
- None,
- None,
- maximum_fee,
- TR.words__transaction_fee,
- TR.words__swap if is_swap else TR.words__title_summary,
- account_items,
- fee_info_items,
- TR.confirm_total__title_fee,
- True,
- "confirm_payment_request",
- )
- if res is BACK:
- continue
- else:
- break
- if back_from_confirm_trade:
- continue
- else:
- break
+ return interact_with_menu(trade_layout, menu, "confirm_trade")
async def confirm_ethereum_staking_tx(
title: str,
Why this scored 17/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.