refactor(core): enforce layout scoping for more Rust layouts
What changed, and why it matters
This commit is a code cleanup that changes how user-interface layouts are managed in the Trezor firmware. It wraps layout objects in explicit context managers (using `with ... as layout:`) and converts several synchronous-looking helper functions into proper async functions. There is no direct evidence in the commit that this fixes an exploitable security bug; it appears to be a defensive refactoring to enforce clearer scoping of UI resources.
No immediate security action required. Treat as normal code-quality refactoring. If reviewing for security, verify that the context-manager scoping does not change the timing or ordering of button-request events compared to the previous implementation, as that could affect user-confirmation semantics.
Security signals we found
Refactoring of UI layout lifecycle management
Introduction/consistent use of context managers for layout scoping
Type annotation change from LayoutObj to LayoutContext
Conversion of Awaitable-returning functions to async functions
No changelog entry, consistent with internal cleanup
Evidence from the diff
The patch continues the refactoring started in PR #6812 by replacing bare LayoutObj[UiResult] return annotations with LayoutContext[UiResult] and wrapping layout creation in with statements across Bolt, Caesar, Delizia, and Eckhart UI layouts. It also converts many def ... -> Awaitable[...] helpers into async def ... -> ... and awaits the inner calls. This enforces that layout contexts are entered and exited cleanly, reducing the risk of resource leaks or accidental use of unscoped layouts. The change is purely architectural/refactoring; no vulnerability is described or directly observable in the diff.
Changed components
core/embed/rust/src/ui/api/firmware_micropython.rscore/mocks/generated/trezorui_api.pyicore/src/trezor/ui/layouts/bolt/__init__.pycore/src/trezor/ui/layouts/bolt/fido.pycore/src/trezor/ui/layouts/caesar/__init__.pycore/src/trezor/ui/layouts/caesar/fido.pycore/src/trezor/ui/layouts/delizia/__init__.pycore/src/trezor/ui/layouts/delizia/fido.pycore/src/trezor/ui/layouts/eckhart/__init__.pyInspect captured patch +864 / −793
diff --git a/core/embed/rust/src/ui/api/firmware_micropython.rs b/core/embed/rust/src/ui/api/firmware_micropython.rs
index 870ed40e..697bf393 100644
--- a/core/embed/rust/src/ui/api/firmware_micropython.rs
+++ b/core/embed/rust/src/ui/api/firmware_micropython.rs
@@ -1525,7 +1525,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// prompt_screen: bool = False,
/// prompt_title: str | None = None,
/// external_menu: bool = False,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Confirm action."""
Qstr::MP_QSTR_confirm_action => obj_fn_kw!(0, new_confirm_action).as_obj(),
@@ -1537,7 +1537,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// verb: str | None = None,
/// info_button: bool = False,
/// chunkify: bool = False,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Confirm address."""
Qstr::MP_QSTR_confirm_address => obj_fn_kw!(0, new_confirm_address).as_obj(),
@@ -1548,7 +1548,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// sell_amount: str | None,
/// buy_amount: str,
/// back_button: bool = False,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """A general way to confirm a "trade", which consists of
/// two amounts - one that is sold and what that is bought."""
Qstr::MP_QSTR_confirm_trade => obj_fn_kw!(0, new_confirm_trade).as_obj(),
@@ -1670,7 +1670,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// button_style_confirm: bool = False,
/// hold: bool = False,
/// items: Iterable[tuple[StrOrBytes, bool]],
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Confirm long content with the possibility to go back from any page.
/// Meant to be used with confirm_with_info on UI Bolt and Caesar."""
Qstr::MP_QSTR_confirm_more => obj_fn_kw!(0, new_confirm_more).as_obj(),
@@ -1683,7 +1683,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// hold: bool = False,
/// verb: str | None = None,
/// external_menu: bool = False,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Confirm list of key-value pairs. The third component in the tuple should be True if
/// the value is to be rendered as binary with monospace font, False otherwise."""
Qstr::MP_QSTR_confirm_properties => obj_fn_kw!(0, new_confirm_properties).as_obj(),
@@ -1706,7 +1706,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// verb_cancel: str | None = None,
/// back_button: bool = False,
/// external_menu: bool = False,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Confirm summary of a transaction.
///
/// account_items and extra_items need to be:
@@ -1727,7 +1727,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// verb_info: str | None = None,
/// verb_cancel: str | None = None,
/// external_menu: bool = False,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Confirm given items but with third button. Always single page
/// without scrolling. In Delizia, the button is placed in
/// context menu."""
diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi
index 7f0bc3db..98c73ffe 100644
--- a/core/mocks/generated/trezorui_api.pyi
+++ b/core/mocks/generated/trezorui_api.pyi
@@ -148,7 +148,7 @@ def confirm_action(
prompt_screen: bool = False,
prompt_title: str | None = None,
external_menu: bool = False,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Confirm action."""
@@ -161,7 +161,7 @@ def confirm_address(
verb: str | None = None,
info_button: bool = False,
chunkify: bool = False,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Confirm address."""
@@ -173,7 +173,7 @@ def confirm_trade(
sell_amount: str | None,
buy_amount: str,
back_button: bool = False,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""A general way to confirm a "trade", which consists of
two amounts - one that is sold and what that is bought."""
@@ -304,7 +304,7 @@ def confirm_more(
button_style_confirm: bool = False,
hold: bool = False,
items: Iterable[tuple[StrOrBytes, bool]],
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Confirm long content with the possibility to go back from any page.
Meant to be used with confirm_with_info on UI Bolt and Caesar."""
@@ -318,7 +318,7 @@ def confirm_properties(
hold: bool = False,
verb: str | None = None,
external_menu: bool = False,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Confirm list of key-value pairs. The third component in the tuple should be True if
the value is to be rendered as binary with monospace font, False otherwise."""
@@ -343,7 +343,7 @@ def confirm_summary(
verb_cancel: str | None = None,
back_button: bool = False,
external_menu: bool = False,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Confirm summary of a transaction.
account_items and extra_items need to be:
* a list (on Eckhart and Caesar)
@@ -363,7 +363,7 @@ def confirm_with_info(
verb_info: str | None = None,
verb_cancel: str | None = None,
external_menu: bool = False,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Confirm given items but with third button. Always single page
without scrolling. In Delizia, the button is placed in
context menu."""
diff --git a/core/src/trezor/ui/layouts/bolt/__init__.py b/core/src/trezor/ui/layouts/bolt/__init__.py
index e29265f4..23d6d2eb 100644
--- a/core/src/trezor/ui/layouts/bolt/__init__.py
+++ b/core/src/trezor/ui/layouts/bolt/__init__.py
@@ -28,7 +28,7 @@ INFO = trezorui_api.INFO
DOWN_ARROW = "V"
-def confirm_action(
+async def confirm_action(
br_name: str,
title: str,
action: str | None = None,
@@ -44,26 +44,27 @@ def confirm_action(
br_code: ButtonRequestType = BR_CODE_OTHER,
prompt_screen: bool = False, # unused on bolt
prompt_title: str | None = None,
-) -> Awaitable[None]:
+) -> None:
if description is not None and description_param is not None:
description = description.format(description_param)
- return raise_if_not_confirmed(
- trezorui_api.confirm_action(
- title=title,
- action=action,
- description=description,
- subtitle=subtitle,
- verb=verb,
- verb_cancel=verb_cancel,
- hold=hold,
- hold_danger=hold_danger,
- reverse=reverse,
- ),
- br_name,
- br_code,
- exc,
- )
+ with trezorui_api.confirm_action(
+ title=title,
+ action=action,
+ description=description,
+ subtitle=subtitle,
+ verb=verb,
+ verb_cancel=verb_cancel,
+ hold=hold,
+ hold_danger=hold_danger,
+ reverse=reverse,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ exc,
+ )
async def confirm_single(
@@ -126,33 +127,35 @@ async def show_wallet_created_success() -> None:
# TODO cleanup @ redesign
async def prompt_backup() -> bool:
- result = await interact(
- trezorui_api.confirm_action(
- title=TR.words__title_success,
- action=TR.backup__new_wallet_successfully_created,
- description=TR.backup__it_should_be_backed_up,
- verb=TR.buttons__back_up,
- verb_cancel=TR.buttons__skip,
- ),
- "backup_device",
- ButtonRequestType.ResetDevice,
- raise_on_cancel=None,
- )
+ with trezorui_api.confirm_action(
+ title=TR.words__title_success,
+ action=TR.backup__new_wallet_successfully_created,
+ description=TR.backup__it_should_be_backed_up,
+ verb=TR.buttons__back_up,
+ verb_cancel=TR.buttons__skip,
+ ) as layout:
+ result = await interact(
+ layout,
+ "backup_device",
+ ButtonRequestType.ResetDevice,
+ raise_on_cancel=None,
+ )
if result is CONFIRMED:
return True
- result = await interact(
- trezorui_api.confirm_action(
- title=TR.words__warning,
- action=TR.backup__want_to_skip,
- description=TR.backup__can_back_up_anytime,
- verb=TR.buttons__back_up,
- verb_cancel=TR.buttons__skip,
- ),
- "backup_device",
- ButtonRequestType.ResetDevice,
- raise_on_cancel=None,
- )
+ with trezorui_api.confirm_action(
+ title=TR.words__warning,
+ action=TR.backup__want_to_skip,
+ description=TR.backup__can_back_up_anytime,
+ verb=TR.buttons__back_up,
+ verb_cancel=TR.buttons__skip,
+ ) as layout:
+ result = await interact(
+ layout,
+ "backup_device",
+ ButtonRequestType.ResetDevice,
+ raise_on_cancel=None,
+ )
return result is CONFIRMED
@@ -597,18 +600,19 @@ async def confirm_output(
while True:
# if the user cancels here, raise ActionCancelled (by default)
- await interact(
- trezorui_api.confirm_address(
- title=recipient_title,
- address=address,
- address_label=address_label,
- verb=TR.buttons__continue,
- info_button=False,
- chunkify=chunkify,
- ),
- "confirm_output",
- br_code,
- )
+ with trezorui_api.confirm_address(
+ title=recipient_title,
+ address=address,
+ address_label=address_label,
+ verb=TR.buttons__continue,
+ info_button=False,
+ chunkify=chunkify,
+ ) as layout:
+ await interact(
+ layout,
+ "confirm_output",
+ br_code,
+ )
try:
with trezorui_api.confirm_value(
@@ -674,46 +678,46 @@ async def _confirm_ask_pagination(
) -> None:
data = utils.hexlify_if_bytes(data)
- confirm_more_layout = trezorui_api.confirm_more(
+ with trezorui_api.confirm_more(
title=title,
button=TR.buttons__confirm,
button_style_confirm=True,
items=[(data, True)],
hold=hold,
- )
- while True:
- if not await should_show_more(
- title,
- [(description, False), (data, True)],
- button_text=TR.buttons__show_all,
- br_name=br_name,
- br_code=br_code,
- confirm=DOWN_ARROW if extra_confirmation_if_not_read else None,
- ):
- if extra_confirmation_if_not_read:
- try:
- await confirm_value(
- title,
- TR.sign_message__confirm_without_review,
- None,
- br_name=br_name,
- br_code=br_code,
- verb=TR.buttons__confirm,
- verb_cancel="^",
- hold=True,
- is_data=False,
- )
- except ActionCancelled:
- continue
- return
+ ) as confirm_more_layout:
+ while True:
+ if not await should_show_more(
+ title,
+ [(description, False), (data, True)],
+ button_text=TR.buttons__show_all,
+ br_name=br_name,
+ br_code=br_code,
+ confirm=DOWN_ARROW if extra_confirmation_if_not_read else None,
+ ):
+ if extra_confirmation_if_not_read:
+ try:
+ await confirm_value(
+ title,
+ TR.sign_message__confirm_without_review,
+ None,
+ br_name=br_name,
+ br_code=br_code,
+ verb=TR.buttons__confirm,
+ verb_cancel="^",
+ hold=True,
+ is_data=False,
+ )
+ except ActionCancelled:
+ continue
+ return
- result = await interact(
- confirm_more_layout, br_name, br_code, raise_on_cancel=None
- )
- if result is CONFIRMED:
- return
+ result = await interact(
+ confirm_more_layout, br_name, br_code, raise_on_cancel=None
+ )
+ if result is CONFIRMED:
+ return
- assert False
+ assert False
async def confirm_blob_intro(
@@ -893,7 +897,7 @@ async def confirm_value(
)
-def confirm_properties(
+async def confirm_properties(
br_name: str,
title: str,
props: Iterable[PropertyType],
@@ -901,7 +905,7 @@ def confirm_properties(
hold: bool = False,
br_code: ButtonRequestType = ButtonRequestType.ConfirmOutput,
verb: str | None = None,
-) -> Awaitable[None]:
+) -> None:
from ..properties import with_colon
items = with_colon(
@@ -916,15 +920,16 @@ def confirm_properties(
if subtitle:
title += ": " + subtitle
- return raise_if_not_confirmed(
- trezorui_api.confirm_properties(
- title=title,
- items=items,
- hold=hold,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.confirm_properties(
+ title=title,
+ items=items,
+ hold=hold,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ )
def confirm_total(
@@ -975,7 +980,7 @@ async def _confirm_summary(
account_items_colon = with_colon(account_items)
extra_items_colon = with_colon(extra_items)
- total_layout = trezorui_api.confirm_summary(
+ total_ctx = trezorui_api.confirm_summary(
amount=amount,
amount_label=with_colon(amount_label),
fee=fee,
@@ -992,10 +997,11 @@ async def _confirm_summary(
info_props_colon.extend(account_items_colon)
if extra_items_colon:
info_props_colon.extend(extra_items_colon)
- with trezorui_api.show_info_with_cancel(
+ info_ctx = trezorui_api.show_info_with_cancel(
title=extra_title if extra_title else TR.words__title_information,
items=info_props_colon,
- ) as info_layout:
+ )
+ with total_ctx as total_layout, info_ctx as info_layout:
return await with_info(total_layout, info_layout, br_name, br_code)
@@ -1020,18 +1026,21 @@ async def confirm_trade(
if trade.sell_amount is not None:
items.append(("", trade.sell_amount, None))
items.append(("", trade.buy_amount, None))
- await with_info(
- trezorui_api.confirm_properties(
- title=title,
- items=items,
- external_menu=True,
- ),
- trezorui_api.confirm_properties(
- title="", items=menu_items, verb=TR.buttons__close
- ),
- "confirm_trade",
- ButtonRequestType.SignTx,
+ main_ctx = trezorui_api.confirm_properties(
+ title=title,
+ items=items,
+ external_menu=True,
+ )
+ info_ctx = trezorui_api.confirm_properties(
+ title="", items=menu_items, verb=TR.buttons__close
)
+ with main_ctx as main_layout, info_ctx as info_layout:
+ await with_info(
+ main_layout,
+ info_layout,
+ "confirm_trade",
+ ButtonRequestType.SignTx,
+ )
if not utils.BITCOIN_ONLY:
@@ -1286,17 +1295,18 @@ if not utils.BITCOIN_ONLY:
TR.ethereum__confirm_contract,
properties,
)
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=with_colon(TR.send__maximum_fee),
- extra_items=None,
- extra_title=None,
- ),
- br_name="confirm_ethereum_tx",
- )
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=with_colon(TR.send__maximum_fee),
+ extra_items=None,
+ extra_title=None,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name="confirm_ethereum_tx",
+ )
async def confirm_ethereum_staking_tx(
title: str,
@@ -1861,33 +1871,35 @@ if not utils.BITCOIN_ONLY:
)
async def confirm_tron_voting(voting_list: list[tuple[int, str]]) -> None:
- await raise_if_not_confirmed(
- trezorui_api.confirm_properties(
- title=TR.words__review,
- items=[
- (f"{TR.words__votes}: {vote[0]}", f"{vote[1]}\n", True)
- for vote in voting_list
- ],
- hold=True,
- ),
- br_name="tron/vote",
- br_code=ButtonRequestType.SignTx,
- )
+ with trezorui_api.confirm_properties(
+ title=TR.words__review,
+ items=[
+ (f"{TR.words__votes}: {vote[0]}", f"{vote[1]}\n", True)
+ for vote in voting_list
+ ],
+ hold=True,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name="tron/vote",
+ br_code=ButtonRequestType.SignTx,
+ )
-def confirm_joint_total(spending_amount: str, total_amount: str) -> Awaitable[None]:
- return raise_if_not_confirmed(
- # FIXME: arguments for amount/fee are misused here
- trezorui_api.confirm_summary(
- amount=spending_amount,
- amount_label=TR.send__you_are_contributing,
- fee=total_amount,
- fee_label=TR.send__to_the_total_amount,
- title=TR.send__title_joint_transaction,
- ),
- "confirm_joint_total",
- ButtonRequestType.SignTx,
- )
+async def confirm_joint_total(spending_amount: str, total_amount: str) -> None:
+ # FIXME: arguments for amount/fee are misused here
+ with trezorui_api.confirm_summary(
+ amount=spending_amount,
+ amount_label=TR.send__you_are_contributing,
+ fee=total_amount,
+ fee_label=TR.send__to_the_total_amount,
+ title=TR.send__title_joint_transaction,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ "confirm_joint_total",
+ ButtonRequestType.SignTx,
+ )
def confirm_metadata(
diff --git a/core/src/trezor/ui/layouts/bolt/fido.py b/core/src/trezor/ui/layouts/bolt/fido.py
index b7e64022..e011c65f 100644
--- a/core/src/trezor/ui/layouts/bolt/fido.py
+++ b/core/src/trezor/ui/layouts/bolt/fido.py
@@ -50,15 +50,14 @@ async def confirm_fido(
async def confirm_fido_reset() -> bool:
from trezor import TR
- confirm = ui.Layout(
- trezorui_api.confirm_action(
- title=TR.fido__title_reset,
- action=TR.fido__erase_credentials,
- description=TR.words__really_wanna,
- reverse=True,
- )
- )
- return (await confirm.get_result()) is trezorui_api.CONFIRMED
+ with trezorui_api.confirm_action(
+ title=TR.fido__title_reset,
+ action=TR.fido__erase_credentials,
+ description=TR.words__really_wanna,
+ reverse=True,
+ ) as layout:
+ confirm = ui.Layout(layout)
+ return (await confirm.get_result()) is trezorui_api.CONFIRMED
async def credential_warning(br_name: str, content: str) -> None:
diff --git a/core/src/trezor/ui/layouts/caesar/__init__.py b/core/src/trezor/ui/layouts/caesar/__init__.py
index d8800fbf..a84788c7 100644
--- a/core/src/trezor/ui/layouts/caesar/__init__.py
+++ b/core/src/trezor/ui/layouts/caesar/__init__.py
@@ -55,7 +55,7 @@ def _placeholder_confirm(
)
-def confirm_action(
+async def confirm_action(
br_name: str,
title: str,
action: str | None = None,
@@ -71,26 +71,27 @@ def confirm_action(
br_code: ButtonRequestType = BR_CODE_OTHER,
prompt_screen: bool = False, # unused on caesar
prompt_title: str | None = None,
-) -> Awaitable[None]:
+) -> None:
verb = verb or TR.buttons__confirm # def_arg
if description is not None and description_param is not None:
description = description.format(description_param)
- return raise_if_not_confirmed(
- trezorui_api.confirm_action(
- title=title,
- action=action,
- description=description,
- subtitle=subtitle,
- verb=verb,
- verb_cancel=verb_cancel,
- hold=hold,
- reverse=reverse,
- ),
- br_name,
- br_code,
- exc,
- )
+ with trezorui_api.confirm_action(
+ title=title,
+ action=action,
+ description=description,
+ subtitle=subtitle,
+ verb=verb,
+ verb_cancel=verb_cancel,
+ hold=hold,
+ reverse=reverse,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ exc,
+ )
def confirm_single(
@@ -158,19 +159,20 @@ async def prompt_backup() -> bool:
if result is CONFIRMED:
return True
- result = await interact(
- trezorui_api.confirm_action(
- title=TR.backup__title_skip,
- action=None,
- description=TR.backup__want_to_skip,
- verb=TR.buttons__back_up,
- verb_cancel=TR.buttons__skip,
- hold=False,
- ),
- br_name,
- br_code,
- raise_on_cancel=None,
- )
+ with trezorui_api.confirm_action(
+ title=TR.backup__title_skip,
+ action=None,
+ description=TR.backup__want_to_skip,
+ verb=TR.buttons__back_up,
+ verb_cancel=TR.buttons__skip,
+ hold=False,
+ ) as layout:
+ result = await interact(
+ layout,
+ br_name,
+ br_code,
+ raise_on_cancel=None,
+ )
return result is CONFIRMED
@@ -338,18 +340,19 @@ async def show_address(
title = f"{title} (MULTISIG)" # TODO translation?
while True:
- result = await interact(
- trezorui_api.confirm_address(
- title=title,
- address=address,
- address_label=None,
- info_button=True,
- chunkify=chunkify,
- ),
- br_name if send_button_request else None,
- br_code,
- raise_on_cancel=None,
- )
+ with trezorui_api.confirm_address(
+ title=title,
+ address=address,
+ address_label=None,
+ info_button=True,
+ chunkify=chunkify,
+ ) as layout:
+ result = await interact(
+ layout,
+ br_name if send_button_request else None,
+ br_code,
+ raise_on_cancel=None,
+ )
send_button_request = False
# User confirmed with middle button.
@@ -596,15 +599,14 @@ async def confirm_payment_request(
if menu_items:
menu = Menu.root(menu_items)
- main_layout = trezorui_api.confirm_with_info(
+ with trezorui_api.confirm_with_info(
title=title,
items=[(TR.words__provider, True), (recipient_name, False)],
verb=TR.buttons__continue,
verb_info=INFO_ICON,
external_menu=True,
- )
-
- await confirm_with_menu(main_layout, menu, "confirm_payment_request")
+ ) as main_layout:
+ await confirm_with_menu(main_layout, menu, "confirm_payment_request")
else:
await confirm_properties(
"confirm_payment_request",
@@ -622,7 +624,7 @@ async def confirm_payment_request(
if transaction_fee is not None:
assert fee_info_items is not None
- summary_layout = trezorui_api.confirm_summary(
+ summary_ctx = trezorui_api.confirm_summary(
amount=None,
amount_label=None,
fee=transaction_fee,
@@ -638,9 +640,10 @@ async def confirm_payment_request(
summary_menu = Menu.root(summary_menu_items)
- await confirm_with_menu(
- summary_layout, summary_menu, br_name="confirm_payment_request"
- )
+ with summary_ctx as summary_layout:
+ await confirm_with_menu(
+ summary_layout, summary_menu, br_name="confirm_payment_request"
+ )
async def confirm_output(
@@ -664,18 +667,19 @@ async def confirm_output(
amount_title += f" #{output_index + 1}"
while True:
- await interact(
- trezorui_api.confirm_address(
- title=address_title,
- address=address,
- address_label=address_label or None,
- verb=TR.buttons__continue,
- info_button=False,
- chunkify=chunkify,
- ),
- "confirm_output",
- br_code,
- )
+ with trezorui_api.confirm_address(
+ title=address_title,
+ address=address,
+ address_label=address_label or None,
+ verb=TR.buttons__continue,
+ info_button=False,
+ chunkify=chunkify,
+ ) as layout:
+ await interact(
+ layout,
+ "confirm_output",
+ br_code,
+ )
try:
with trezorui_api.confirm_value(
@@ -803,41 +807,41 @@ async def _confirm_ask_pagination(
) -> None:
data = utils.hexlify_if_bytes(data)
- confirm_more_layout = trezorui_api.confirm_more(
+ with trezorui_api.confirm_more(
title=title,
button=TR.buttons__confirm,
items=[(description, False), (data, True)],
- )
-
- while True:
- if not await should_show_more(
- title,
- para=[(description, False), (data, True)],
- br_name=br_name,
- br_code=br_code,
- ):
- if extra_confirmation_if_not_read:
- try:
- await confirm_value(
- title,
- TR.sign_message__confirm_without_review,
- None,
- br_name=br_name,
- br_code=br_code,
- verb=TR.buttons__confirm,
- verb_cancel="^",
- hold=True,
- is_data=False,
- )
- except ActionCancelled:
- continue
- return
+ ) as confirm_more_layout:
- result = await interact(confirm_more_layout, br_name, br_code, None)
- if result is trezorui_api.CANCELLED:
- continue
- else:
- break
+ while True:
+ if not await should_show_more(
+ title,
+ para=[(description, False), (data, True)],
+ br_name=br_name,
+ br_code=br_code,
+ ):
+ if extra_confirmation_if_not_read:
+ try:
+ await confirm_value(
+ title,
+ TR.sign_message__confirm_without_review,
+ None,
+ br_name=br_name,
+ br_code=br_code,
+ verb=TR.buttons__confirm,
+ verb_cancel="^",
+ hold=True,
+ is_data=False,
+ )
+ except ActionCancelled:
+ continue
+ return
+
+ result = await interact(confirm_more_layout, br_name, br_code, None)
+ if result is trezorui_api.CANCELLED:
+ continue
+ else:
+ break
def confirm_address(
@@ -900,7 +904,7 @@ def confirm_amount(
)
-def confirm_properties(
+async def confirm_properties(
br_name: str,
title: str,
props: Iterable[PropertyType], # TODO: replace with StrPropertyType
@@ -908,7 +912,7 @@ def confirm_properties(
hold: bool = False,
br_code: ButtonRequestType = ButtonRequestType.ConfirmOutput,
verb: str | None = None,
-) -> Awaitable[None]:
+) -> None:
from ..properties import with_colon
items = with_colon(
@@ -923,15 +927,16 @@ def confirm_properties(
if subtitle:
title += ": " + subtitle
- return raise_if_not_confirmed(
- trezorui_api.confirm_properties(
- title=title,
- items=items,
- hold=hold,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.confirm_properties(
+ title=title,
+ items=items,
+ hold=hold,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ )
async def confirm_value(
@@ -976,7 +981,7 @@ async def confirm_value(
from trezor.ui.layouts.menu import Details, Menu, confirm_with_menu
- main = trezorui_api.confirm_with_info(
+ main_ctx = trezorui_api.confirm_with_info(
title=title,
items=((value, False),),
verb=verb or TR.buttons__confirm,
@@ -1001,10 +1006,11 @@ async def confirm_value(
Details.from_layout(name or "", item_factory(name or "", value or ""))
for name, value, _is_data in info_items
)
- return await confirm_with_menu(main, menu, br_name, br_code)
+ with main_ctx as main:
+ return await confirm_with_menu(main, menu, br_name, br_code)
-def confirm_total(
+async def confirm_total(
total_amount: str,
fee_amount: str,
title: str | None = None,
@@ -1015,26 +1021,27 @@ def confirm_total(
fee_items: Iterable[StrPropertyType] | None = None,
br_name: str = "confirm_total",
br_code: ButtonRequestType = ButtonRequestType.SignTx,
-) -> Awaitable[None]:
+) -> None:
total_label = total_label or TR.send__total_amount # def_arg
fee_label = fee_label or TR.send__including_fee # def_arg
from ..properties import with_colon
- return raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=total_amount,
- amount_label=with_colon(total_label),
- fee=fee_amount,
- fee_label=with_colon(fee_label),
- account_title=account_title,
- account_items=with_colon(account_items),
- extra_items=with_colon(fee_items),
- extra_title=TR.confirm_total__title_fee,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.confirm_summary(
+ amount=total_amount,
+ amount_label=with_colon(total_label),
+ fee=fee_amount,
+ fee_label=with_colon(fee_label),
+ account_title=account_title,
+ account_items=with_colon(account_items),
+ extra_items=with_colon(fee_items),
+ extra_title=TR.confirm_total__title_fee,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ )
async def confirm_trade(
@@ -1048,7 +1055,7 @@ async def confirm_trade(
if trade.sell_amount is not None:
items.append(("", trade.sell_amount, True))
items.append(("", trade.buy_amount, True))
- trade_layout = trezorui_api.confirm_properties(
+ trade_ctx = trezorui_api.confirm_properties(
title=title,
items=items,
verb=TR.buttons__continue,
@@ -1067,7 +1074,8 @@ async def confirm_trade(
menu_items.append(create_details(k, v))
menu = Menu.root(menu_items)
- await confirm_with_menu(trade_layout, menu, "confirm_trade")
+ with trade_ctx as trade_layout:
+ await confirm_with_menu(trade_layout, menu, "confirm_trade")
if not utils.BITCOIN_ONLY:
@@ -1218,20 +1226,21 @@ if not utils.BITCOIN_ONLY:
if account_path:
account_items = ((TR.address_details__derivation_path, account_path, None),)
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=with_colon(TR.send__maximum_fee),
- title=TR.words__title_summary,
- account_items=with_colon(account_items),
- account_title=TR.address_details__account_info,
- extra_items=with_colon(fee_info_items),
- extra_title=TR.confirm_total__title_fee,
- ),
- br_name="confirm_ethereum_approve",
- )
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=with_colon(TR.send__maximum_fee),
+ title=TR.words__title_summary,
+ account_items=with_colon(account_items),
+ account_title=TR.address_details__account_info,
+ extra_items=with_colon(fee_info_items),
+ extra_title=TR.confirm_total__title_fee,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name="confirm_ethereum_approve",
+ )
async def confirm_ethereum_clear_signing(
recipient_str: str,
@@ -1248,17 +1257,19 @@ if not utils.BITCOIN_ONLY:
TR.ethereum__confirm_contract,
properties,
)
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=with_colon(TR.send__maximum_fee),
- extra_items=None,
- extra_title=None,
- ),
- br_name="confirm_ethereum_tx",
- )
+
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=with_colon(TR.send__maximum_fee),
+ extra_items=None,
+ extra_title=None,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name="confirm_ethereum_tx",
+ )
async def confirm_ethereum_staking_tx(
title: str,
@@ -1295,18 +1306,20 @@ if not utils.BITCOIN_ONLY:
else:
amount_title = f"{TR.words__amount}:"
amount_value = total_amount
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=amount_value,
- amount_label=amount_title,
- fee=maximum_fee,
- fee_label=with_colon(TR.send__maximum_fee),
- extra_items=with_colon(info_items),
- extra_title=TR.confirm_total__title_fee,
- ),
- br_name=br_name,
- br_code=br_code,
- )
+
+ with trezorui_api.confirm_summary(
+ amount=amount_value,
+ amount_label=amount_title,
+ fee=maximum_fee,
+ fee_label=with_colon(TR.send__maximum_fee),
+ extra_items=with_colon(info_items),
+ extra_title=TR.confirm_total__title_fee,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name=br_name,
+ br_code=br_code,
+ )
async def confirm_ethereum_vault_tx(
title: str,
@@ -1378,19 +1391,20 @@ if not utils.BITCOIN_ONLY:
br_code=br_code,
)
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=with_colon(TR.send__maximum_fee),
- extra_title=TR.confirm_total__title_fee,
- extra_items=with_colon(info_items),
- title=title,
- ),
- br_name=f"{br_name}/summary",
- br_code=br_code,
- )
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=with_colon(TR.send__maximum_fee),
+ extra_title=TR.confirm_total__title_fee,
+ extra_items=with_colon(info_items),
+ title=title,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name=f"{br_name}/summary",
+ br_code=br_code,
+ )
async def confirm_ethereum_vault_claim(
title: str,
@@ -1436,19 +1450,20 @@ if not utils.BITCOIN_ONLY:
br_code=br_code,
)
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=with_colon(TR.send__maximum_fee),
- extra_title=TR.confirm_total__title_fee,
- extra_items=with_colon(info_items),
- title=title,
- ),
- br_name=f"{br_name}/summary",
- br_code=br_code,
- )
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=with_colon(TR.send__maximum_fee),
+ extra_title=TR.confirm_total__title_fee,
+ extra_items=with_colon(info_items),
+ title=title,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name=f"{br_name}/summary",
+ br_code=br_code,
+ )
def confirm_solana_unknown_token_warning() -> Awaitable[None]:
return show_danger(
@@ -1474,7 +1489,7 @@ if not utils.BITCOIN_ONLY:
info_items=items,
)
- def confirm_solana_tx(
+ async def confirm_solana_tx(
amount: str,
fee: str,
items: Iterable[StrPropertyType],
@@ -1482,25 +1497,26 @@ if not utils.BITCOIN_ONLY:
fee_title: str | None = None,
br_name: str = "confirm_solana_tx",
br_code: ButtonRequestType = ButtonRequestType.SignTx,
- ) -> Awaitable[None]:
+ ) -> None:
from ..properties import with_colon
amount_title = (
amount_title if amount_title is not None else TR.words__amount
) # def_arg
fee_title = fee_title or TR.words__fee # def_arg
- return raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=amount,
- amount_label=with_colon(amount_title),
- fee=fee,
- fee_label=with_colon(fee_title),
- extra_items=with_colon(items),
- extra_title=TR.words__title_information,
- ),
- br_name=br_name,
- br_code=br_code,
- )
+ with trezorui_api.confirm_summary(
+ amount=amount,
+ amount_label=with_colon(amount_title),
+ fee=fee,
+ fee_label=with_colon(fee_title),
+ extra_items=with_colon(items),
+ extra_title=TR.words__title_information,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name=br_name,
+ br_code=br_code,
+ )
async def confirm_solana_staking_tx(
title: str | None,
@@ -1543,7 +1559,7 @@ if not utils.BITCOIN_ONLY:
else:
description = f"\n{description}"
- main = trezorui_api.confirm_summary(
+ main_ctx = trezorui_api.confirm_summary(
title=title,
amount=vote_account,
amount_label=description,
@@ -1554,9 +1570,10 @@ if not utils.BITCOIN_ONLY:
menu = Menu.root(
create_details(name or "", value or "") for name, value, _is_data in items
)
- await confirm_with_menu(main, menu, br_name, br_code)
+ with main_ctx as main:
+ await confirm_with_menu(main, menu, br_name, br_code)
- main = trezorui_api.confirm_summary(
+ main_ctx = trezorui_api.confirm_summary(
amount=amount,
amount_label=with_colon(amount_label),
fee=fee,
@@ -1574,30 +1591,32 @@ if not utils.BITCOIN_ONLY:
(TR.address_details__account_info, account_details),
]
menu = Menu.root(create_details(name, props) for name, props in iter)
- await confirm_with_menu(main, menu, br_name, br_code)
+ with main_ctx as main:
+ await confirm_with_menu(main, menu, br_name, br_code)
- def confirm_cardano_tx(
+ async def confirm_cardano_tx(
amount: str,
fee: str,
items: Iterable[StrPropertyType],
amount_title: str | None = None,
fee_title: str | None = None,
- ) -> Awaitable[None]:
+ ) -> None:
from ..properties import with_colon
amount_title = TR.send__total_amount
fee_title = TR.send__including_fee
- return raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=amount,
- amount_label=with_colon(amount_title),
- fee=fee,
- fee_label=with_colon(fee_title),
- extra_items=with_colon(items),
- ),
- br_name="confirm_cardano_tx",
- br_code=ButtonRequestType.SignTx,
- )
+ with trezorui_api.confirm_summary(
+ amount=amount,
+ amount_label=with_colon(amount_title),
+ fee=fee,
+ fee_label=with_colon(fee_title),
+ extra_items=with_colon(items),
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name="confirm_cardano_tx",
+ br_code=ButtonRequestType.SignTx,
+ )
async def confirm_ethereum_tx(
recipient: str | None,
@@ -1613,7 +1632,7 @@ if not utils.BITCOIN_ONLY:
) -> None:
from ..properties import with_colon
- summary_layout = trezorui_api.confirm_summary(
+ with trezorui_api.confirm_summary(
amount=total_amount,
amount_label=with_colon(TR.words__amount),
fee=maximum_fee,
@@ -1621,66 +1640,67 @@ if not utils.BITCOIN_ONLY:
extra_items=with_colon(fee_info_items),
extra_title=TR.confirm_total__title_fee,
verb_cancel="^",
- )
-
- if is_send:
- title = TR.words__recipient
- else:
- title = TR.ethereum__interaction_contract if recipient else ""
+ ) as summary_layout:
- while True:
- # Allowing going back and forth between recipient and summary/details
- await confirm_blob(
- br_name,
- title,
- recipient or TR.ethereum__new_contract,
- verb=TR.buttons__continue,
- br_code=br_code,
- chunkify=(chunkify if recipient else False),
- )
+ if is_send:
+ title = TR.words__recipient
+ else:
+ title = TR.ethereum__interaction_contract if recipient else ""
- try:
- await raise_if_not_confirmed(
- summary_layout,
+ while True:
+ # Allowing going back and forth between recipient and summary/details
+ await confirm_blob(
br_name,
- br_code,
+ title,
+ recipient or TR.ethereum__new_contract,
+ verb=TR.buttons__continue,
+ br_code=br_code,
+ chunkify=(chunkify if recipient else False),
)
- break
- except ActionCancelled:
- continue
- def confirm_stellar_tx(
+ try:
+ await raise_if_not_confirmed(
+ summary_layout,
+ br_name,
+ br_code,
+ )
+ break
+ except ActionCancelled:
+ continue
+
+ async def confirm_stellar_tx(
fee: str,
account_name: str,
account_path: str,
is_sending_from_trezor_account: bool,
extra_items: Iterable[StrPropertyType],
- ) -> Awaitable[None]:
+ ) -> None:
from ..properties import with_colon
- return raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=fee,
- fee_label=TR.send__maximum_fee,
- account_items=with_colon(
- (
- (TR.words__account, account_name, None),
- (TR.address_details__derivation_path, account_path, None),
- )
- ),
- account_title=(
- TR.send__send_from
- if is_sending_from_trezor_account
- else TR.stellar__sign_with
- ),
- extra_items=with_colon(extra_items),
- extra_title=TR.stellar__timebounds,
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=fee,
+ fee_label=TR.send__maximum_fee,
+ account_items=with_colon(
+ (
+ (TR.words__account, account_name, None),
+ (TR.address_details__derivation_path, account_path, None),
+ )
),
- br_name="confirm_stellar_tx",
- br_code=ButtonRequestType.SignTx,
- )
+ account_title=(
+ TR.send__send_from
+ if is_sending_from_trezor_account
+ else TR.stellar__sign_with
+ ),
+ extra_items=with_colon(extra_items),
+ extra_title=TR.stellar__timebounds,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name="confirm_stellar_tx",
+ br_code=ButtonRequestType.SignTx,
+ )
async def confirm_stellar_output_amount(
title: str,
@@ -1769,19 +1789,20 @@ if not utils.BITCOIN_ONLY:
display_fee, display_fee_label = fee or "", (
TR.words__fee_limit if fee else ""
)
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- title=title or TR.words__title_summary,
- amount=display_amount,
- amount_label=display_amount_label,
- fee=display_fee,
- fee_label=display_fee_label,
- account_items=account_items,
- account_title=TR.address_details__account_info,
- ),
- br_name="tron/summary",
- br_code=ButtonRequestType.SignTx,
- )
+ with trezorui_api.confirm_summary(
+ title=title or TR.words__title_summary,
+ amount=display_amount,
+ amount_label=display_amount_label,
+ fee=display_fee,
+ fee_label=display_fee_label,
+ account_items=account_items,
+ account_title=TR.address_details__account_info,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name="tron/summary",
+ br_code=ButtonRequestType.SignTx,
+ )
async def confirm_tron_send(
amount: str | None,
@@ -1865,18 +1886,19 @@ if not utils.BITCOIN_ONLY:
verb=TR.buttons__continue,
)
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=with_colon(TR.words__fee_limit),
- title=title,
- account_title=TR.address_details__account_info,
- extra_title=TR.confirm_total__title_fee,
- ),
- br_name=br_name,
- )
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=with_colon(TR.words__fee_limit),
+ title=title,
+ account_title=TR.address_details__account_info,
+ extra_title=TR.confirm_total__title_fee,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name=br_name,
+ )
# TODO: #6364 Consider simplifying with confirm_tron_send like ETH flows.
async def confirm_tron_transfer(
@@ -1918,33 +1940,34 @@ if not utils.BITCOIN_ONLY:
verb=TR.buttons__continue,
)
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=with_colon(TR.words__fee_limit),
- title=title,
- account_title=TR.address_details__account_info,
- extra_title=TR.confirm_total__title_fee,
- ),
- br_name=br_name,
- )
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=with_colon(TR.words__fee_limit),
+ title=title,
+ account_title=TR.address_details__account_info,
+ extra_title=TR.confirm_total__title_fee,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name=br_name,
+ )
async def confirm_tron_voting(voting_list: list[tuple[int, str]]) -> None:
- await raise_if_not_confirmed(
- trezorui_api.confirm_properties(
- title=TR.words__review,
- subtitle=TR.words__voting,
- items=[
- (f"{TR.words__votes}: {vote[0]}", vote[1], True)
- for vote in voting_list
- ],
- hold=True,
- ),
- br_name="tron/vote",
- br_code=ButtonRequestType.SignTx,
- )
+ with trezorui_api.confirm_properties(
+ title=TR.words__review,
+ subtitle=TR.words__voting,
+ items=[
+ (f"{TR.words__votes}: {vote[0]}", vote[1], True) for vote in voting_list
+ ],
+ hold=True,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name="tron/vote",
+ br_code=ButtonRequestType.SignTx,
+ )
def confirm_joint_total(spending_amount: str, total_amount: str) -> Awaitable[None]:
diff --git a/core/src/trezor/ui/layouts/caesar/fido.py b/core/src/trezor/ui/layouts/caesar/fido.py
index 0251ec7f..b7163068 100644
--- a/core/src/trezor/ui/layouts/caesar/fido.py
+++ b/core/src/trezor/ui/layouts/caesar/fido.py
@@ -35,14 +35,14 @@ async def confirm_fido(
async def confirm_fido_reset() -> bool:
from trezor import TR
- confirm = trezorui_api.confirm_action(
+ with trezorui_api.confirm_action(
title=TR.fido__title_reset,
description=TR.fido__wanna_erase_credentials,
action=None,
verb_cancel="",
verb=TR.buttons__confirm,
- )
- return (await ui.Layout(confirm).get_result()) is trezorui_api.CONFIRMED
+ ) as confirm:
+ return (await ui.Layout(confirm).get_result()) is trezorui_api.CONFIRMED
async def credential_warning(br_name: str, content: str) -> None:
diff --git a/core/src/trezor/ui/layouts/delizia/__init__.py b/core/src/trezor/ui/layouts/delizia/__init__.py
index 9c6d7824..6cf649ca 100644
--- a/core/src/trezor/ui/layouts/delizia/__init__.py
+++ b/core/src/trezor/ui/layouts/delizia/__init__.py
@@ -35,7 +35,7 @@ INFO = trezorui_api.INFO
BACK = trezorui_api.BACK
-def confirm_action(
+async def confirm_action(
br_name: str,
title: str,
action: str | None = None,
@@ -51,13 +51,13 @@ def confirm_action(
br_code: ButtonRequestType = BR_CODE_OTHER,
prompt_screen: bool = False,
prompt_title: str | None = None,
-) -> Awaitable[ui.UiResult]:
+) -> ui.UiResult:
from trezor.ui.layouts.menu import Menu, interact_with_menu
if description is not None and description_param is not None:
description = description.format(description_param)
- flow = trezorui_api.confirm_action(
+ with trezorui_api.confirm_action(
title=title,
action=action,
description=description,
@@ -70,29 +70,29 @@ def confirm_action(
prompt_screen=prompt_screen,
prompt_title=prompt_title or title,
external_menu=not (prompt_screen or hold),
- )
+ ) as flow:
- if prompt_screen or hold:
- # Note: multi-step confirm (prompt_screen/hold)
- # can't work with external menus yet
- return interact(
- flow,
- br_name,
- br_code,
- exc,
- )
- else:
- menu = Menu.root(
- cancel=verb_cancel or TR.buttons__cancel,
- )
+ if prompt_screen or hold:
+ # Note: multi-step confirm (prompt_screen/hold)
+ # can't work with external menus yet
+ return await interact(
+ flow,
+ br_name,
+ br_code,
+ exc,
+ )
+ else:
+ menu = Menu.root(
+ cancel=verb_cancel or TR.buttons__cancel,
+ )
- return interact_with_menu(
- flow,
- menu,
- br_name,
- br_code,
- exc,
- )
+ return await interact_with_menu(
+ flow,
+ menu,
+ br_name,
+ br_code,
+ exc,
+ )
async def confirm_single(
@@ -888,7 +888,7 @@ async def confirm_value(
return await interact_with_menu(main_layout, menu, br_name, br_code)
-def confirm_properties(
+async def confirm_properties(
br_name: str,
title: str,
props: Iterable[PropertyType],
@@ -896,21 +896,22 @@ def confirm_properties(
hold: bool = False,
br_code: ButtonRequestType = ButtonRequestType.ConfirmOutput,
verb: str | None = None,
-) -> Awaitable[None]:
+) -> None:
- return raise_if_not_confirmed(
- trezorui_api.confirm_properties(
- title=title,
- subtitle=subtitle,
- items=list(props),
- hold=hold,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.confirm_properties(
+ title=title,
+ subtitle=subtitle,
+ items=list(props),
+ hold=hold,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ )
-def confirm_total(
+async def confirm_total(
total_amount: str | None,
fee_amount: str,
title: str | None = None,
@@ -924,30 +925,31 @@ def confirm_total(
back_button: bool = False,
br_name: str = "confirm_total",
br_code: ButtonRequestType = ButtonRequestType.SignTx,
-) -> Awaitable[ui.UiResult]:
+) -> ui.UiResult:
title = title or TR.words__title_summary # def_arg
total_label = total_label or TR.send__total_amount # def_arg
fee_label = fee_label or TR.send__incl_transaction_fee # def_arg
- return interact(
- trezorui_api.confirm_summary(
- amount=total_amount,
- amount_label=total_label,
- fee=fee_amount,
- fee_label=fee_label,
- title=title,
- account_title=account_title,
- account_items=account_items,
- extra_items=fee_items,
- extra_title=TR.confirm_total__title_fee,
- back_button=back_button,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.confirm_summary(
+ amount=total_amount,
+ amount_label=total_label,
+ fee=fee_amount,
+ fee_label=fee_label,
+ title=title,
+ account_title=account_title,
+ account_items=account_items,
+ extra_items=fee_items,
+ extra_title=TR.confirm_total__title_fee,
+ back_button=back_button,
+ ) as layout:
+ return await interact(
+ layout,
+ br_name,
+ br_code,
+ )
-def _confirm_summary(
+async def _confirm_summary(
amount: str | None,
amount_label: str | None,
fee: str,
@@ -959,23 +961,24 @@ def _confirm_summary(
extra_title: str | None = None,
br_name: str = "confirm_total",
br_code: ButtonRequestType = ButtonRequestType.SignTx,
-) -> Awaitable[None]:
+) -> None:
title = title or TR.words__title_summary # def_arg
- return raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=amount,
- amount_label=amount_label,
- fee=fee,
- fee_label=fee_label,
- title=title,
- account_items=account_items,
- account_title=account_title,
- extra_items=extra_items,
- extra_title=extra_title or None,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.confirm_summary(
+ amount=amount,
+ amount_label=amount_label,
+ fee=fee,
+ fee_label=fee_label,
+ title=title,
+ account_items=account_items,
+ account_title=account_title,
+ extra_items=extra_items,
+ extra_title=extra_title or None,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ )
async def confirm_trade(
@@ -986,7 +989,7 @@ async def confirm_trade(
) -> None:
from trezor.ui.layouts.menu import Menu, confirm_with_menu
- trade_layout = trezorui_api.confirm_trade(
+ trade_ctx = trezorui_api.confirm_trade(
title=title,
subtitle=subtitle,
sell_amount=trade.sell_amount,
@@ -1005,7 +1008,8 @@ async def confirm_trade(
menu_items.append(create_details(k, v))
menu = Menu.root(menu_items, TR.send__cancel_sign)
- await confirm_with_menu(trade_layout, menu, "confirm_trade")
+ with trade_ctx as trade_layout:
+ await confirm_with_menu(trade_layout, menu, "confirm_trade")
if not utils.BITCOIN_ONLY:
@@ -1263,17 +1267,18 @@ if not utils.BITCOIN_ONLY:
TR.ethereum__confirm_contract,
properties,
)
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=TR.send__maximum_fee,
- extra_items=None,
- extra_title=None,
- ),
- br_name="confirm_ethereum_tx",
- )
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=TR.send__maximum_fee,
+ extra_items=None,
+ extra_title=None,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name="confirm_ethereum_tx",
+ )
async def confirm_ethereum_staking_tx(
title: str,
@@ -1885,16 +1890,17 @@ if not utils.BITCOIN_ONLY:
item_list.append((TR.words__address, address, True))
item_list.append((f"\n{TR.words__votes}", f"{vote_count}", False))
- await raise_if_not_confirmed(
- trezorui_api.confirm_properties(
- title=TR.words__review,
- subtitle=TR.words__voting,
- items=item_list,
- hold=True,
- ),
- br_name="tron/vote",
- br_code=ButtonRequestType.SignTx,
- )
+ with trezorui_api.confirm_properties(
+ title=TR.words__review,
+ subtitle=TR.words__voting,
+ items=item_list,
+ hold=True,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name="tron/vote",
+ br_code=ButtonRequestType.SignTx,
+ )
def confirm_joint_total(spending_amount: str, total_amount: str) -> Awaitable[None]:
diff --git a/core/src/trezor/ui/layouts/delizia/fido.py b/core/src/trezor/ui/layouts/delizia/fido.py
index a767fb2e..ef0ec3da 100644
--- a/core/src/trezor/ui/layouts/delizia/fido.py
+++ b/core/src/trezor/ui/layouts/delizia/fido.py
@@ -43,16 +43,15 @@ async def confirm_fido(
async def confirm_fido_reset() -> bool:
from trezor import TR
- confirm = ui.Layout(
- trezorui_api.confirm_action(
- title=TR.fido__title_reset,
- action=TR.fido__erase_credentials,
- description=TR.words__really_wanna,
- reverse=True,
- prompt_screen=True,
- )
- )
- return (await confirm.get_result()) is trezorui_api.CONFIRMED
+ with trezorui_api.confirm_action(
+ title=TR.fido__title_reset,
+ action=TR.fido__erase_credentials,
+ description=TR.words__really_wanna,
+ reverse=True,
+ prompt_screen=True,
+ ) as layout:
+ confirm = ui.Layout(layout)
+ return (await confirm.get_result()) is trezorui_api.CONFIRMED
async def credential_warning(br_name: str, content: str) -> None:
diff --git a/core/src/trezor/ui/layouts/eckhart/__init__.py b/core/src/trezor/ui/layouts/eckhart/__init__.py
index 83fcc89b..9de0a5a9 100644
--- a/core/src/trezor/ui/layouts/eckhart/__init__.py
+++ b/core/src/trezor/ui/layouts/eckhart/__init__.py
@@ -35,7 +35,7 @@ BACK = trezorui_api.BACK
INFO = trezorui_api.INFO
-def confirm_action(
+async def confirm_action(
br_name: str,
title: str,
action: str | None = None,
@@ -51,28 +51,29 @@ def confirm_action(
br_code: ButtonRequestType = BR_CODE_OTHER,
prompt_screen: bool = False,
prompt_title: str | None = None,
-) -> Awaitable[None]:
+) -> None:
if description is not None and description_param is not None:
description = description.format(description_param)
- return raise_if_not_confirmed(
- trezorui_api.confirm_action(
- title=title,
- action=action,
- description=description,
- subtitle=subtitle,
- verb=verb,
- verb_cancel=verb_cancel,
- hold=hold,
- hold_danger=hold_danger,
- reverse=reverse,
- prompt_screen=prompt_screen,
- prompt_title=prompt_title or title,
- ),
- br_name,
- br_code,
- exc,
- )
+ with trezorui_api.confirm_action(
+ title=title,
+ action=action,
+ description=description,
+ subtitle=subtitle,
+ verb=verb,
+ verb_cancel=verb_cancel,
+ hold=hold,
+ hold_danger=hold_danger,
+ reverse=reverse,
+ prompt_screen=prompt_screen,
+ prompt_title=prompt_title or title,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ exc,
+ )
async def confirm_reset_device(recovery: bool = False) -> None:
@@ -885,7 +886,7 @@ async def confirm_value(
)
-def confirm_properties(
+async def confirm_properties(
br_name: str,
title: str,
props: Iterable[PropertyType],
@@ -893,24 +894,25 @@ def confirm_properties(
hold: bool = False,
br_code: ButtonRequestType = ButtonRequestType.ConfirmOutput,
verb: str | None = None,
-) -> Awaitable[None]:
+) -> None:
if subtitle:
title += ": " + subtitle
- return raise_if_not_confirmed(
- trezorui_api.confirm_properties(
- title=title,
- items=list(props),
- hold=hold,
- verb=verb,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.confirm_properties(
+ title=title,
+ items=list(props),
+ hold=hold,
+ verb=verb,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ )
-def confirm_total(
+async def confirm_total(
total_amount: str | None,
fee_amount: str,
title: str | None = None,
@@ -922,30 +924,31 @@ def confirm_total(
back_button: bool = False,
br_name: str = "confirm_total",
br_code: ButtonRequestType = ButtonRequestType.SignTx,
-) -> Awaitable[ui.UiResult]:
+) -> ui.UiResult:
title = title or TR.words__send # def_arg
total_label = total_label or TR.send__total_amount # def_arg
fee_label = fee_label or TR.send__incl_transaction_fee # def_arg
- return interact(
- trezorui_api.confirm_summary(
- amount=total_amount,
- amount_label=total_label,
- fee=fee_amount,
- fee_label=fee_label,
- title=title,
- account_title=account_title,
- account_items=account_items,
- extra_items=fee_items,
- extra_title=TR.confirm_total__title_fee,
- back_button=back_button,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.confirm_summary(
+ amount=total_amount,
+ amount_label=total_label,
+ fee=fee_amount,
+ fee_label=fee_label,
+ title=title,
+ account_title=account_title,
+ account_items=account_items,
+ extra_items=fee_items,
+ extra_title=TR.confirm_total__title_fee,
+ back_button=back_button,
+ ) as layout:
+ return await interact(
+ layout,
+ br_name,
+ br_code,
+ )
-def _confirm_summary(
+async def _confirm_summary(
amount: str | None,
amount_label: str | None,
fee: str,
@@ -958,36 +961,37 @@ def _confirm_summary(
back_button: bool = False,
br_name: str = "confirm_total",
br_code: ButtonRequestType = ButtonRequestType.SignTx,
-) -> Awaitable[None]:
+) -> None:
title = title or TR.words__send # def_arg
- return raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=amount,
- amount_label=amount_label,
- fee=fee,
- fee_label=fee_label,
- title=title,
- account_items=list(account_items) if account_items else None,
- account_title=account_title,
- extra_items=list(extra_items) if extra_items else None,
- extra_title=extra_title or None,
- back_button=back_button,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.confirm_summary(
+ amount=amount,
+ amount_label=amount_label,
+ fee=fee,
+ fee_label=fee_label,
+ title=title,
+ account_items=list(account_items) if account_items else None,
+ account_title=account_title,
+ extra_items=list(extra_items) if extra_items else None,
+ extra_title=extra_title or None,
+ back_button=back_button,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ )
-def confirm_trade(
+async def confirm_trade(
title: str,
subtitle: str,
trade: Trade,
extra_menu_items: list[tuple[str, str]],
back_button: bool,
-) -> Awaitable[ui.UiResult]:
+) -> ui.UiResult:
from trezor.ui.layouts.menu import Menu, interact_with_menu
- trade_layout = trezorui_api.confirm_trade(
+ trade_ctx = trezorui_api.confirm_trade(
title=title,
subtitle=subtitle,
sell_amount=trade.sell_amount,
@@ -1007,7 +1011,8 @@ def confirm_trade(
menu_items.append(create_details(k, v))
menu = Menu.root(menu_items, TR.send__cancel_sign)
- return interact_with_menu(trade_layout, menu, "confirm_trade")
+ with trade_ctx as trade_layout:
+ return await interact_with_menu(trade_layout, menu, "confirm_trade")
if not utils.BITCOIN_ONLY:
@@ -1304,17 +1309,18 @@ if not utils.BITCOIN_ONLY:
TR.ethereum__confirm_contract,
properties,
)
- await raise_if_not_confirmed(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=TR.send__maximum_fee,
- extra_items=None,
- extra_title=None,
- ),
- br_name="confirm_ethereum_tx",
- )
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=TR.send__maximum_fee,
+ extra_items=None,
+ extra_title=None,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name="confirm_ethereum_tx",
+ )
async def confirm_ethereum_vault_tx(
title: str,
@@ -1346,76 +1352,92 @@ if not utils.BITCOIN_ONLY:
)
)
- steps = [
- lambda: interact_with_menu(
- trezorui_api.confirm_action(
- title=title,
- action=intro_question,
- description=None,
- external_menu=True,
- cancel=False,
- ),
- Menu.root(menu_items, TR.send__cancel_sign),
- f"{br_name}/intro",
- br_code,
- ),
- lambda: interact_with_menu(
- trezorui_api.confirm_with_info(
- title=title,
- subtitle=verb,
- items=[(vault_str, True)],
- verb=TR.buttons__continue,
- ),
- Menu.root(menu_items, TR.send__cancel_sign),
- f"{br_name}/vault_name",
- br_code,
- ),
- lambda: interact_with_menu(
- trezorui_api.confirm_properties(
+ async def _step1() -> trezorui_api.UiResult:
+ with trezorui_api.confirm_action(
+ title=title,
+ action=intro_question,
+ description=None,
+ external_menu=True,
+ cancel=False,
+ ) as layout:
+ return await interact_with_menu(
+ layout,
+ Menu.root(menu_items, TR.send__cancel_sign),
+ f"{br_name}/intro",
+ br_code,
+ )
+
+ async def _step2() -> trezorui_api.UiResult:
+ with trezorui_api.confirm_with_info(
+ title=title,
+ subtitle=verb,
+ items=[(vault_str, True)],
+ verb=TR.buttons__continue,
+ ) as layout:
+ return await interact_with_menu(
+ layout,
+ Menu.root(menu_items, TR.send__cancel_sign),
+ f"{br_name}/vault_name",
+ br_code,
+ )
+
+ async def _step3() -> trezorui_api.UiResult:
+ with trezorui_api.confirm_properties(
+ title=title,
+ items=[
+ (amount_label, amount, False),
+ (TR.words__chain, chain, False),
+ ],
+ hold=False,
+ verb=TR.buttons__continue,
+ ) as layout:
+ return await interact_with_menu(
+ layout,
+ Menu.root(menu_items, TR.send__cancel_sign),
+ f"{br_name}/amount",
+ br_code,
+ )
+
+ steps = [_step1, _step2, _step3]
+
+ if extra_data is not None:
+
+ async def _step4() -> trezorui_api.UiResult:
+ with trezorui_api.confirm_properties(
title=title,
- items=[
- (amount_label, amount, False),
- (TR.words__chain, chain, False),
- ],
+ items=[(TR.ethereum__calldata_suffix, extra_data, True)],
hold=False,
verb=TR.buttons__continue,
- ),
- Menu.root(menu_items, TR.send__cancel_sign),
- f"{br_name}/amount",
- br_code,
- ),
- ]
- if extra_data is not None:
- steps.append(
- lambda: interact_with_menu(
- trezorui_api.confirm_properties(
- title=title,
- items=[(TR.ethereum__calldata_suffix, extra_data, True)],
- hold=False,
- verb=TR.buttons__continue,
- ),
+ ) as layout:
+ return await interact_with_menu(
+ layout,
+ Menu.root(menu_items, TR.send__cancel_sign),
+ f"{br_name}/extra_data",
+ br_code,
+ )
+
+ steps.append(_step4)
+
+ async def _step5() -> trezorui_api.UiResult:
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=TR.send__maximum_fee,
+ extra_title=TR.confirm_total__title_fee,
+ extra_items=list(info_items),
+ title=title,
+ back_button=False,
+ ) as layout:
+ return await interact_with_menu(
+ layout,
Menu.root(menu_items, TR.send__cancel_sign),
- f"{br_name}/extra_data",
+ f"{br_name}/summary",
br_code,
)
- )
- steps.append(
- lambda: interact_with_menu(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=TR.send__maximum_fee,
- extra_title=TR.confirm_total__title_fee,
- extra_items=list(info_items),
- title=title,
- back_button=False,
- ),
- Menu.root(menu_items, TR.send__cancel_sign),
- f"{br_name}/summary",
- br_code,
- )
- )
+
+ steps.append(_step5)
+
await confirm_linear_flow(*steps)
async def confirm_ethereum_vault_claim(
@@ -1443,48 +1465,57 @@ if not utils.BITCOIN_ONLY:
subtitle=TR.send__send_from,
)
)
- await confirm_linear_flow(
- lambda: interact_with_menu(
- trezorui_api.confirm_action(
- title=title,
- action=intro_question,
- description=None,
- external_menu=True,
- cancel=False,
- ),
- Menu.root(menu_items, TR.send__cancel_sign),
- f"{br_name}/intro",
- br_code,
- ),
- lambda: interact_with_menu(
- trezorui_api.confirm_properties(
- title=title,
- items=[
- (TR.ethereum__reward_tokens, token_list, False),
- ],
- hold=False,
- verb=TR.buttons__continue,
- ),
- Menu.root(menu_items, TR.send__cancel_sign),
- f"{br_name}/tokens",
- br_code,
- ),
- lambda: interact_with_menu(
- trezorui_api.confirm_summary(
- amount=None,
- amount_label=None,
- fee=maximum_fee,
- fee_label=TR.send__maximum_fee,
- extra_title=TR.confirm_total__title_fee,
- extra_items=list(info_items),
- title=title,
- back_button=False,
- ),
- Menu.root(menu_items, TR.send__cancel_sign),
- f"{br_name}/summary",
- br_code,
- ),
- )
+
+ async def _step1() -> trezorui_api.UiResult:
+ with trezorui_api.confirm_action(
+ title=title,
+ action=intro_question,
+ description=None,
+ external_menu=True,
+ cancel=False,
+ ) as layout:
+ return await interact_with_menu(
+ layout,
+ Menu.root(menu_items, TR.send__cancel_sign),
+ f"{br_name}/intro",
+ br_code,
+ )
+
+ async def _step2() -> trezorui_api.UiResult:
+ with trezorui_api.confirm_properties(
+ title=title,
+ items=[
+ (TR.ethereum__reward_tokens, token_list, False),
+ ],
+ hold=False,
+ verb=TR.buttons__continue,
+ ) as layout:
+ return await interact_with_menu(
+ layout,
+ Menu.root(menu_items, TR.send__cancel_sign),
+ f"{br_name}/tokens",
+ br_code,
+ )
+
+ async def _step3() -> trezorui_api.UiResult:
+ with trezorui_api.confirm_summary(
+ amount=None,
+ amount_label=None,
+ fee=maximum_fee,
+ fee_label=TR.send__maximum_fee,
+ extra_title=TR.confirm_total__title_fee,
+ extra_items=list(info_items),
+ title=title,
+ back_button=False,
+ ) as layout:
+ return await interact_with_menu(
+ layout,
+ Menu.root(menu_items, TR.send__cancel_sign),
+ f"{br_name}/summary",
+ br_code,
+ )
+
+ await confirm_linear_flow(_step1, _step2, _step3)
async def confirm_ethereum_staking_tx(
title: str,
@@ -1966,16 +1997,17 @@ if not utils.BITCOIN_ONLY:
item_list.append((TR.words__address, address, True))
item_list.append((f"\n{TR.words__votes}", f"{vote_count}", False))
- await raise_if_not_confirmed(
- trezorui_api.confirm_properties(
- title=TR.words__review,
- subtitle=TR.words__voting,
- items=item_list,
- hold=True,
- ),
- br_name="tron/vote",
- br_code=ButtonRequestType.SignTx,
- )
+ with trezorui_api.confirm_properties(
+ title=TR.words__review,
+ subtitle=TR.words__voting,
+ items=item_list,
+ hold=True,
+ ) as layout:
+ await raise_if_not_confirmed(
+ layout,
+ br_name="tron/vote",
+ br_code=ButtonRequestType.SignTx,
+ )
def confirm_joint_total(spending_amount: str, total_amount: str) -> Awaitable[None]:
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.