refactor(core): enforce layout scoping for more Rust layouts
What changed, and why it matters
This commit is a code cleanup that wraps more on-screen UI layouts in a new 'layout context' scoping mechanism. It changes how layout objects are created and awaited, but does not add or remove security checks. The main risk is that any mistake in the refactor could cause a layout to be used outside its intended scope, but the diff itself shows consistent mechanical changes rather than a security fix or vulnerability.
Treat as a routine refactor. Reviewers should verify that every `with ... as layout:` block correctly awaits the layout before exiting the context, and that no layout object is returned or used outside its scope. Regression testing of affected flows (backup, recovery, FIDO2, address display, PIN mismatch popups) is appropriate, but no immediate security response is indicated.
Security signals we found
Large refactor touching UI layout lifecycle across multiple product variants (bolt, caesar, delizia, eckhart)
Context-manager scoping may be a defensive pattern to prevent use-after-free or concurrent layout misuse
No explicit security relevance stated by vendor; marked [no changelog]
No changes to input validation, crypto, or authorization logic visible in diff
Evidence from the diff
The commit refactors Trezor firmware UI code to use LayoutContext (a context-manager-scoped layout handle) instead of bare LayoutObj for a broader set of Rust-backed layouts. Python callers now use with trezorui_api.some_layout(...) as layout: and then await interact(layout, ...). Type annotations, mock stubs, and several helper functions are updated from returning Awaitable to being async def. The error_popup() return type is corrected from LayoutObj[None] to LayoutContext[UiResult]. No security boundaries, permission checks, or cryptographic operations are changed.
Changed components
core/embed/rust/src/ui/api/firmware_micropython.rscore/mocks/generated/trezorui_api.pyicore/src/trezor/ui/layouts/bolt/*core/src/trezor/ui/layouts/caesar/*core/src/trezor/ui/layouts/delizia/*core/src/trezor/ui/layouts/eckhart/*core/src/apps/webauthn/fido2.pycore/src/apps/homescreen/device_menu.pycore/src/apps/management/recovery_device/layout.pycore/src/apps/management/reset_device/layout.pycore/src/apps/debug/n4w1_mock.pycore/src/trezor/wire/thp/ui.pyInspect captured patch +607 / −718
diff --git a/core/embed/rust/src/ui/api/firmware_micropython.rs b/core/embed/rust/src/ui/api/firmware_micropython.rs
index 397b8c63..870ed40e 100644
--- a/core/embed/rust/src/ui/api/firmware_micropython.rs
+++ b/core/embed/rust/src/ui/api/firmware_micropython.rs
@@ -1888,7 +1888,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// title: str,
/// description: str,
/// words: Iterable[str],
- /// ) -> LayoutObj[int]:
+ /// ) -> LayoutContext[int]:
/// """Select mnemonic word from three possibilities - seed check after backup. The
/// iterable must be of exact size. Returns index in range `0..3`."""
Qstr::MP_QSTR_select_word => obj_fn_kw!(0, new_select_word).as_obj(),
@@ -1896,7 +1896,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// def select_word_count(
/// *,
/// recovery_type: RecoveryType,
- /// ) -> LayoutObj[int | str | UiResult]: # TR returns str
+ /// ) -> LayoutContext[int | str | UiResult]: # TR returns str
/// """Select a mnemonic word count from the options: 12, 18, 20, 24, or 33.
/// For unlocking a repeated backup, select between 20 and 33."""
Qstr::MP_QSTR_select_word_count => obj_fn_kw!(0, new_select_word_count).as_obj(),
@@ -1914,7 +1914,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// account: str | None,
/// path: str | None,
/// xpubs: Sequence[tuple[str, str]],
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Show address details - QR code, account, path, cosigner xpubs."""
Qstr::MP_QSTR_show_address_details => obj_fn_kw!(0, new_show_address_details).as_obj(),
@@ -1924,7 +1924,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// items: Iterable[str],
/// active: int,
/// button: str,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Checklist of backup steps. Active index is highlighted, previous items have check
/// mark next to them. Limited to 3 items."""
Qstr::MP_QSTR_show_checklist => obj_fn_kw!(0, new_show_checklist).as_obj(),
@@ -1936,7 +1936,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// value: str = "",
/// menu_title: str | None = None,
/// verb_cancel: str | None = None,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Warning modal that makes it easier to cancel than to continue."""
Qstr::MP_QSTR_show_danger => obj_fn_kw!(0, new_show_danger).as_obj(),
@@ -1947,14 +1947,14 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// description: str = "",
/// allow_cancel: bool = True,
/// time_ms: int = 0,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Error modal. No buttons shown when `button` is empty string."""
Qstr::MP_QSTR_show_error => obj_fn_kw!(0, new_show_error).as_obj(),
/// def show_group_share_success(
/// *,
/// lines: Iterable[str],
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Shown after successfully finishing a group."""
Qstr::MP_QSTR_show_group_share_success => obj_fn_kw!(0, new_show_group_share_success).as_obj(),
@@ -2040,7 +2040,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// button: tuple[str, bool] | None = None,
/// time_ms: int = 0,
/// external_menu: bool = False,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Info screen."""
Qstr::MP_QSTR_show_info => obj_fn_kw!(0, new_show_info).as_obj(),
@@ -2050,7 +2050,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// items: list[StrPropertyType],
/// horizontal: bool = False,
/// chunkify: bool = False,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Show metadata for outgoing transaction with a 'close' button."""
Qstr::MP_QSTR_show_info_with_cancel => obj_fn_kw!(0, new_show_info_with_cancel).as_obj(),
@@ -2103,7 +2103,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// def show_remaining_shares(
/// *,
/// pages: Iterable[tuple[str, str]],
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Shows SLIP39 state after info button is pressed on `confirm_recovery`."""
Qstr::MP_QSTR_show_remaining_shares => obj_fn_kw!(0, new_show_remaining_shares).as_obj(),
@@ -2111,7 +2111,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// *,
/// words: Iterable[str],
/// title: str | None = None,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Show mnemonic for backup."""
Qstr::MP_QSTR_show_share_words => obj_fn_kw!(0, new_show_share_words).as_obj(),
@@ -2124,7 +2124,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// text_footer: str | None,
/// text_confirm: str,
/// text_check: str,
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Show mnemonic for wallet backup preceded by an instruction screen and followed by a
/// confirmation screen."""
Qstr::MP_QSTR_show_share_words_extended => obj_fn_kw!(0, new_show_share_words_extended).as_obj(),
@@ -2161,7 +2161,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// description: str = "",
/// allow_cancel: bool = True,
/// danger: bool = False, # unused on bolt
- /// ) -> LayoutObj[UiResult]:
+ /// ) -> LayoutContext[UiResult]:
/// """Warning modal. Bolt: No buttons shown when `button` is empty string. Caesar: middle button and centered text."""
Qstr::MP_QSTR_show_warning => obj_fn_kw!(0, new_show_warning).as_obj(),
diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi
index dec29f7d..7f0bc3db 100644
--- a/core/mocks/generated/trezorui_api.pyi
+++ b/core/mocks/generated/trezorui_api.pyi
@@ -539,7 +539,7 @@ def select_word(
title: str,
description: str,
words: Iterable[str],
-) -> LayoutObj[int]:
+) -> LayoutContext[int]:
"""Select mnemonic word from three possibilities - seed check after backup. The
iterable must be of exact size. Returns index in range `0..3`."""
@@ -548,7 +548,7 @@ def select_word(
def select_word_count(
*,
recovery_type: RecoveryType,
-) -> LayoutObj[int | str | UiResult]: # TR returns str
+) -> LayoutContext[int | str | UiResult]: # TR returns str
"""Select a mnemonic word count from the options: 12, 18, 20, 24, or 33.
For unlocking a repeated backup, select between 20 and 33."""
@@ -568,7 +568,7 @@ def show_address_details(
account: str | None,
path: str | None,
xpubs: Sequence[tuple[str, str]],
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Show address details - QR code, account, path, cosigner xpubs."""
@@ -579,7 +579,7 @@ def show_checklist(
items: Iterable[str],
active: int,
button: str,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Checklist of backup steps. Active index is highlighted, previous items have check
mark next to them. Limited to 3 items."""
@@ -592,7 +592,7 @@ def show_danger(
value: str = "",
menu_title: str | None = None,
verb_cancel: str | None = None,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Warning modal that makes it easier to cancel than to continue."""
@@ -604,7 +604,7 @@ def show_error(
description: str = "",
allow_cancel: bool = True,
time_ms: int = 0,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Error modal. No buttons shown when `button` is empty string."""
@@ -612,7 +612,7 @@ def show_error(
def show_group_share_success(
*,
lines: Iterable[str],
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Shown after successfully finishing a group."""
@@ -706,7 +706,7 @@ def show_info(
button: tuple[str, bool] | None = None,
time_ms: int = 0,
external_menu: bool = False,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Info screen."""
@@ -717,7 +717,7 @@ def show_info_with_cancel(
items: list[StrPropertyType],
horizontal: bool = False,
chunkify: bool = False,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Show metadata for outgoing transaction with a 'close' button."""
@@ -776,7 +776,7 @@ def show_properties(
def show_remaining_shares(
*,
pages: Iterable[tuple[str, str]],
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Shows SLIP39 state after info button is pressed on `confirm_recovery`."""
@@ -785,7 +785,7 @@ def show_share_words(
*,
words: Iterable[str],
title: str | None = None,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Show mnemonic for backup."""
@@ -799,7 +799,7 @@ def show_share_words_extended(
text_footer: str | None,
text_confirm: str,
text_check: str,
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Show mnemonic for wallet backup preceded by an instruction screen and followed by a
confirmation screen."""
@@ -840,7 +840,7 @@ def show_warning(
description: str = "",
allow_cancel: bool = True,
danger: bool = False, # unused on bolt
-) -> LayoutObj[UiResult]:
+) -> LayoutContext[UiResult]:
"""Warning modal. Bolt: No buttons shown when `button` is empty string. Caesar: middle button and centered text."""
diff --git a/core/src/apps/debug/n4w1_mock.py b/core/src/apps/debug/n4w1_mock.py
index 8e4a56f4..908bea25 100644
--- a/core/src/apps/debug/n4w1_mock.py
+++ b/core/src/apps/debug/n4w1_mock.py
@@ -6,7 +6,7 @@ from trezor.ui import Layout
if TYPE_CHECKING:
from buffer_types import AnyBytes
- from typing import Any, Awaitable, Iterator
+ from typing import Any, Iterator
from trezor.wire.context import Context
from typing_extensions import Self
@@ -61,9 +61,9 @@ class N4W1Context:
res = await ctx.call(req, DebugLinkN4W1Response)
self.rx.put(res)
- def confirm_connect(
+ async def confirm_connect(
self, *, title: str, description: str, button: str, br_name: str | None
- ) -> Awaitable[None]:
+ ) -> None:
"""Show a layout waiting for N4W1 connection, allowing cancellation."""
from trezor import TR
@@ -89,18 +89,18 @@ class N4W1Context:
yield from super().create_tasks()
yield _task()
- main = show_info(
+ with show_info(
title=title,
description=description,
button=(button, False),
external_menu=True,
- )
- return confirm_with_menu(
- main,
- Menu.root(cancel=TR.buttons__cancel),
- br_name=br_name,
- layout_type=_Connect,
- )
+ ) as main:
+ return await confirm_with_menu(
+ main,
+ Menu.root(cancel=TR.buttons__cancel),
+ br_name=br_name,
+ layout_type=_Connect,
+ )
ctx = N4W1Context()
diff --git a/core/src/apps/homescreen/device_menu.py b/core/src/apps/homescreen/device_menu.py
index e710ee54..dcb81785 100644
--- a/core/src/apps/homescreen/device_menu.py
+++ b/core/src/apps/homescreen/device_menu.py
@@ -208,15 +208,13 @@ async def handle_ReviewFailedBackup() -> None:
backup_failed = is_initialized and storage_device.unfinished_backup()
utils.ensure(backup_failed)
- await raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=TR.homescreen__title_backup_failed,
- button=TR.words__wipe,
- description=TR.wipe__start_again,
- danger=True,
- ),
- "prompt_device_wipe",
- )
+ with trezorui_api.show_warning(
+ title=TR.homescreen__title_backup_failed,
+ button=TR.words__wipe,
+ description=TR.wipe__start_again,
+ danger=True,
+ ) as layout:
+ await raise_if_not_confirmed(layout, "prompt_device_wipe")
await wipe_device(WipeDevice())
raise ExitDeviceMenu # return to homescreen
@@ -237,16 +235,14 @@ async def handle_PairDevice() -> None:
# Show warning if Bluetooth is not enabled
if not ble.get_enabled():
- await interact(
- trezorui_api.show_warning(
- title=TR.words__important,
- description=TR.ble__must_be_enabled,
- button=TR.buttons__turn_on,
- allow_cancel=True,
- danger=False,
- ),
- "enable_bluetooth",
- )
+ with trezorui_api.show_warning(
+ title=TR.words__important,
+ description=TR.ble__must_be_enabled,
+ button=TR.buttons__turn_on,
+ allow_cancel=True,
+ danger=False,
+ ) as layout:
+ await interact(layout, "enable_bluetooth")
ble_enable(True)
hostname_map = {e.mac_addr: e for e in paired_cache.load()}
diff --git a/core/src/apps/management/recovery_device/layout.py b/core/src/apps/management/recovery_device/layout.py
index 16352c03..edfb99d3 100644
--- a/core/src/apps/management/recovery_device/layout.py
+++ b/core/src/apps/management/recovery_device/layout.py
@@ -378,15 +378,13 @@ else:
share = await _read_share()
break
except RetryRead as exc:
- await raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=TR.words__important,
- button=TR.buttons__continue,
- description=exc.msg,
- danger=True,
- ),
- br_name="recovery_retry",
- )
+ with trezorui_api.show_warning(
+ title=TR.words__important,
+ button=TR.buttons__continue,
+ description=exc.msg,
+ danger=True,
+ ) as layout:
+ await raise_if_not_confirmed(layout, br_name="recovery_retry")
# wait for a new N4W1 tag
continue
diff --git a/core/src/apps/management/reset_device/layout.py b/core/src/apps/management/reset_device/layout.py
index 4ab820f1..802b3552 100644
--- a/core/src/apps/management/reset_device/layout.py
+++ b/core/src/apps/management/reset_device/layout.py
@@ -266,15 +266,13 @@ if utils.USE_N4W1:
import trezorui_api
from trezor.ui.layouts.common import raise_if_not_confirmed
- await raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=TR.words__important,
- button=TR.buttons__continue,
- description=exc.msg,
- danger=True,
- ),
- br_name="backup_retry",
- )
+ with trezorui_api.show_warning(
+ title=TR.words__important,
+ button=TR.buttons__continue,
+ description=exc.msg,
+ danger=True,
+ ) as layout:
+ await raise_if_not_confirmed(layout, br_name="backup_retry")
# wait for a new N4W1 tag
continue
diff --git a/core/src/apps/webauthn/fido2.py b/core/src/apps/webauthn/fido2.py
index 74be5db5..62e3d7bd 100644
--- a/core/src/apps/webauthn/fido2.py
+++ b/core/src/apps/webauthn/fido2.py
@@ -630,15 +630,15 @@ async def _show_error_popup(
button: str = "",
timeout_ms: int = 0,
) -> None:
- popup = error_popup(
+ with error_popup(
title,
description,
subtitle,
description_param,
button=button,
timeout_ms=timeout_ms,
- )
- await Layout(popup).get_result()
+ ) as popup:
+ await Layout(popup).get_result()
async def _confirm_bogus_app(title: str) -> None:
diff --git a/core/src/trezor/ui/__init__.py b/core/src/trezor/ui/__init__.py
index 29becd75..8d301289 100644
--- a/core/src/trezor/ui/__init__.py
+++ b/core/src/trezor/ui/__init__.py
@@ -23,7 +23,7 @@ if TYPE_CHECKING:
from typing import Any, Callable, Generator, Generic, Iterator, TypeVar
from trezor.enums import ButtonRequestType
- from trezorui_api import LayoutObj, UiResult # noqa: F401
+ from trezorui_api import LayoutContext, LayoutObj, UiResult # noqa: F401
T = TypeVar("T", covariant=True)
ButtonRequestMsg = tuple[ButtonRequestType, str] | None
diff --git a/core/src/trezor/ui/layouts/bolt/__init__.py b/core/src/trezor/ui/layouts/bolt/__init__.py
index f4b8ee63..e29265f4 100644
--- a/core/src/trezor/ui/layouts/bolt/__init__.py
+++ b/core/src/trezor/ui/layouts/bolt/__init__.py
@@ -156,22 +156,23 @@ async def prompt_backup() -> bool:
return result is CONFIRMED
-def confirm_path_warning(path: str, path_type: str | None = None) -> Awaitable[None]:
+async def confirm_path_warning(path: str, path_type: str | None = None) -> None:
title = (
TR.addr_mismatch__wrong_derivation_path
if not path_type
else f"{TR.words__unknown} {path_type.lower()}."
)
- return raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=title,
- value=path,
- description=TR.words__continue_anyway_question,
- button=TR.buttons__continue,
- ),
- "path_warning",
- br_code=ButtonRequestType.UnknownDerivationPath,
- )
+ with trezorui_api.show_warning(
+ title=title,
+ value=path,
+ description=TR.words__continue_anyway_question,
+ button=TR.buttons__continue,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ "path_warning",
+ br_code=ButtonRequestType.UnknownDerivationPath,
+ )
def confirm_multisig_warning() -> Awaitable[None]:
@@ -361,19 +362,16 @@ async def show_address(
)
return result
- result = await interact(
- trezorui_api.show_address_details(
- qr_title=title,
- address=address if address_qr is None else address_qr,
- case_sensitive=case_sensitive,
- details_title=details_title,
- account=account,
- path=path,
- xpubs=[(xpub_title(i), xpub) for i, xpub in enumerate(xpubs)],
- ),
- None,
- raise_on_cancel=None,
- )
+ with trezorui_api.show_address_details(
+ qr_title=title,
+ address=address if address_qr is None else address_qr,
+ case_sensitive=case_sensitive,
+ details_title=details_title,
+ account=account,
+ path=path,
+ xpubs=[(xpub_title(i), xpub) for i, xpub in enumerate(xpubs)],
+ ) as layout:
+ result = await interact(layout, None, raise_on_cancel=None)
assert result is CANCELLED
else:
@@ -421,39 +419,32 @@ async def show_error_and_raise(
exc: ExceptionType = ActionCancelled,
) -> NoReturn:
button = button or TR.buttons__try_again # def_arg
- await interact(
- trezorui_api.show_error(
- title=subheader or "",
- description=content,
- button=button,
- allow_cancel=False,
- ),
- br_name,
- BR_CODE_OTHER,
- raise_on_cancel=None,
- )
+ with trezorui_api.show_error(
+ title=subheader or "",
+ description=content,
+ button=button,
+ allow_cancel=False,
+ ) as layout:
+ await interact(layout, br_name, BR_CODE_OTHER, raise_on_cancel=None)
# always raise regardless of result
raise exc
-def show_warning(
+async def show_warning(
br_name: str,
content: str,
subheader: str | None = None,
button: str | None = None,
verb_cancel: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
-) -> Awaitable[None]:
+) -> None:
button = button or TR.buttons__continue # def_arg
- return raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=content,
- description=subheader or "",
- button=button,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.show_warning(
+ title=content,
+ description=subheader or "",
+ button=button,
+ ) as layout:
+ return await raise_if_not_confirmed(layout, br_name, br_code)
def show_danger(
@@ -965,7 +956,7 @@ def confirm_total(
)
-def _confirm_summary(
+async def _confirm_summary(
amount: str | None,
amount_label: str | None,
fee: str,
@@ -977,7 +968,7 @@ def _confirm_summary(
extra_title: str | None = None,
br_name: str = "confirm_total",
br_code: ButtonRequestType = ButtonRequestType.SignTx,
-) -> Awaitable[None]:
+) -> None:
from ..properties import with_colon
title = title or TR.words__title_summary # def_arg
@@ -1001,11 +992,11 @@ def _confirm_summary(
info_props_colon.extend(account_items_colon)
if extra_items_colon:
info_props_colon.extend(extra_items_colon)
- info_layout = trezorui_api.show_info_with_cancel(
+ with trezorui_api.show_info_with_cancel(
title=extra_title if extra_title else TR.words__title_information,
items=info_props_colon,
- )
- return with_info(total_layout, info_layout, br_name, br_code)
+ ) as info_layout:
+ return await with_info(total_layout, info_layout, br_name, br_code)
async def confirm_trade(
@@ -2043,7 +2034,7 @@ async def confirm_signverify(
address_title = TR.sign_message__confirm_address
br_name = "sign_message"
- address_layout = trezorui_api.confirm_address(
+ address_ctx = trezorui_api.confirm_address(
title=address_title,
address=address,
address_label=None,
@@ -2065,29 +2056,34 @@ async def confirm_signverify(
)
)
- info_layout = trezorui_api.show_info_with_cancel(
+ info_ctx = trezorui_api.show_info_with_cancel(
title=TR.words__title_information,
items=with_colon(items),
horizontal=True,
)
- while True:
- try:
- await with_info(address_layout, info_layout, br_name, br_code=BR_CODE_OTHER)
- break
- except ActionCancelled:
- with trezorui_api.show_mismatch(title=TR.addr_mismatch__mismatch) as layout:
- result = await interact(
- layout,
- None,
- raise_on_cancel=None,
+ with address_ctx as address_layout, info_ctx as info_layout:
+ while True:
+ try:
+ await with_info(
+ address_layout, info_layout, br_name, br_code=BR_CODE_OTHER
)
- assert result in (CONFIRMED, CANCELLED)
- # Right button aborts action, left goes back to showing address.
- if result is CONFIRMED:
- raise ActionCancelled
- else:
- continue
+ break
+ except ActionCancelled:
+ with trezorui_api.show_mismatch(
+ title=TR.addr_mismatch__mismatch
+ ) as layout:
+ result = await interact(
+ layout,
+ None,
+ raise_on_cancel=None,
+ )
+ assert result in (CONFIRMED, CANCELLED)
+ # Right button aborts action, left goes back to showing address.
+ if result is CONFIRMED:
+ raise ActionCancelled
+ else:
+ continue
with trezorui_api.confirm_value(
title=TR.sign_message__confirm_message,
@@ -2125,7 +2121,7 @@ def error_popup(
*,
button: str = "",
timeout_ms: int = 0,
-) -> ui.LayoutObj[None]:
+) -> ui.LayoutContext[ui.UiResult]:
if not button and not timeout_ms:
raise ValueError("Either button or timeout_ms must be set")
@@ -2138,7 +2134,7 @@ def error_popup(
time_ms=timeout_ms,
allow_cancel=False,
)
- return layout # type: ignore ["LayoutObj[UiResult]" is not assignable to "LayoutObj[None]"]
+ return layout
def request_passphrase_on_host() -> None:
@@ -2204,33 +2200,29 @@ async def confirm_reenter_pin(is_wipe_code: bool = False) -> None:
pass
-def pin_mismatch_popup(is_wipe_code: bool = False) -> Awaitable[None]:
+async def pin_mismatch_popup(is_wipe_code: bool = False) -> None:
title = TR.wipe_code__wipe_code_mismatch if is_wipe_code else TR.pin__pin_mismatch
br_name = "wipe_code_mismatch" if is_wipe_code else "pin_mismatch"
description = TR.wipe_code__mismatch if is_wipe_code else TR.pin__mismatch
- return interact(
- error_popup(
- title,
- description,
- button=TR.buttons__try_again,
- ),
- br_name,
- BR_CODE_OTHER,
- raise_on_cancel=None,
- )
+ with error_popup(
+ title,
+ description,
+ button=TR.buttons__try_again,
+ ) as layout:
+ # result is ignored
+ await interact(layout, br_name, BR_CODE_OTHER, raise_on_cancel=None)
-def wipe_code_same_as_pin_popup() -> Awaitable[None]:
- return interact(
- error_popup(
- TR.wipe_code__invalid,
- TR.wipe_code__diff_from_pin,
- button=TR.buttons__try_again,
- ),
- "wipe_code_same_as_pin",
- BR_CODE_OTHER,
- raise_on_cancel=None,
- )
+async def wipe_code_same_as_pin_popup() -> None:
+ with error_popup(
+ TR.wipe_code__invalid,
+ TR.wipe_code__diff_from_pin,
+ button=TR.buttons__try_again,
+ ) as layout:
+ # result is ignored
+ await interact(
+ layout, "wipe_code_same_as_pin", BR_CODE_OTHER, raise_on_cancel=None
+ )
async def wipe_code_pin_not_set_popup(
diff --git a/core/src/trezor/ui/layouts/bolt/recovery.py b/core/src/trezor/ui/layouts/bolt/recovery.py
index 94802239..77a58f80 100644
--- a/core/src/trezor/ui/layouts/bolt/recovery.py
+++ b/core/src/trezor/ui/layouts/bolt/recovery.py
@@ -9,19 +9,16 @@ from apps.common import backup_types
from ..common import interact
if TYPE_CHECKING:
- from typing import Awaitable
-
from trezor.enums import RecoveryType
from apps.management.recovery_device.layout import RemainingSharesInfo
async def request_word_count(recovery_type: RecoveryType) -> int:
- count = await interact(
- trezorui_api.select_word_count(recovery_type=recovery_type),
- "recovery_word_count",
- ButtonRequestType.MnemonicWordCount,
- )
+ with trezorui_api.select_word_count(recovery_type=recovery_type) as layout:
+ count = await interact(
+ layout, "recovery_word_count", ButtonRequestType.MnemonicWordCount
+ )
assert isinstance(count, (int, str))
return int(count)
@@ -86,31 +83,27 @@ def format_remaining_shares_info(
return pages
-def show_remaining_shares(
+async def show_remaining_shares(
pages: list[tuple[str, str]],
-) -> Awaitable[trezorui_api.UiResult]:
- return interact(
- trezorui_api.show_remaining_shares(pages=pages),
- "show_shares",
- ButtonRequestType.Other,
- )
-
-
-def show_group_share_success(
- share_index: int, group_index: int
-) -> Awaitable[ui.UiResult]:
- return interact(
- trezorui_api.show_group_share_success(
- lines=[
- TR.recovery__you_have_entered,
- TR.recovery__share_num_template.format(share_index + 1),
- TR.words__from,
- TR.recovery__group_num_template.format(group_index + 1),
- ],
- ),
- "share_success",
- ButtonRequestType.Other,
- )
+) -> trezorui_api.UiResult:
+ with trezorui_api.show_remaining_shares(pages=pages) as layout:
+ return await interact(layout, "show_shares", ButtonRequestType.Other)
+
+
+async def show_group_share_success(share_index: int, group_index: int) -> ui.UiResult:
+ with trezorui_api.show_group_share_success(
+ lines=[
+ TR.recovery__you_have_entered,
+ TR.recovery__share_num_template.format(share_index + 1),
+ TR.words__from,
+ TR.recovery__group_num_template.format(group_index + 1),
+ ],
+ ) as layout:
+ return await interact(
+ layout,
+ "share_success",
+ ButtonRequestType.Other,
+ )
async def _confirm_abort(dry_run: bool = False) -> None:
@@ -227,25 +220,22 @@ async def show_group_threshold() -> None:
)
-def show_recovery_warning(
+async def show_recovery_warning(
br_name: str,
content: str,
subheader: str | None = None,
button: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
-) -> Awaitable[ui.UiResult]:
+) -> ui.UiResult:
button = button or TR.buttons__try_again # def_arg
- return interact(
- trezorui_api.show_warning(
- title=content,
- description=subheader or "",
- button=button,
- allow_cancel=False,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.show_warning(
+ title=content,
+ description=subheader or "",
+ button=button,
+ allow_cancel=False,
+ ) as layout:
+ return await interact(layout, br_name, br_code)
async def show_dry_run_result(result: bool, is_slip39: bool) -> None:
diff --git a/core/src/trezor/ui/layouts/bolt/reset.py b/core/src/trezor/ui/layouts/bolt/reset.py
index 763a27fc..3c067019 100644
--- a/core/src/trezor/ui/layouts/bolt/reset.py
+++ b/core/src/trezor/ui/layouts/bolt/reset.py
@@ -9,11 +9,11 @@ from ..common import interact, raise_if_not_confirmed
CONFIRMED = trezorui_api.CONFIRMED # global_import_cache
-def show_share_words(
+async def show_share_words(
share_words: Sequence[str],
share_index: int | None = None,
group_index: int | None = None,
-) -> Awaitable[None]:
+) -> None:
if share_index is None:
title = TR.reset__recovery_wallet_backup_title
elif group_index is None:
@@ -23,14 +23,13 @@ def show_share_words(
group_index + 1, share_index + 1
)
- return raise_if_not_confirmed(
- trezorui_api.show_share_words(
- words=share_words,
- title=title,
- ),
- "backup_words",
- ButtonRequestType.ResetDevice,
- )
+ with trezorui_api.show_share_words(
+ words=share_words,
+ title=title,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout, "backup_words", ButtonRequestType.ResetDevice
+ )
async def select_word(
@@ -56,28 +55,26 @@ async def select_word(
while len(words) < 3:
words.append(words[-1])
- result = await interact(
- trezorui_api.select_word(
- title=title,
- description=TR.reset__select_word_x_of_y_template.format(
- checked_index + 1, count
- ),
- words=(words[0], words[1], words[2]),
+ with trezorui_api.select_word(
+ title=title,
+ description=TR.reset__select_word_x_of_y_template.format(
+ checked_index + 1, count
),
- None,
- )
+ words=(words[0], words[1], words[2]),
+ ) as layout:
+ result = await interact(layout, None)
if __debug__ and isinstance(result, str):
return result
assert isinstance(result, int) and 0 <= result <= 2
return words[result]
-def slip39_show_checklist(
+async def slip39_show_checklist(
step: int,
advanced: bool,
count: int | None = None,
threshold: int | None = None,
-) -> Awaitable[None]:
+) -> None:
items = (
(
TR.reset__slip39_checklist_set_num_shares,
@@ -92,16 +89,15 @@ def slip39_show_checklist(
)
)
- return raise_if_not_confirmed(
- trezorui_api.show_checklist(
- title=TR.reset__slip39_checklist_title,
- button=TR.buttons__continue,
- active=step,
- items=items,
- ),
- "slip39_checklist",
- ButtonRequestType.ResetDevice,
- )
+ with trezorui_api.show_checklist(
+ title=TR.reset__slip39_checklist_title,
+ button=TR.buttons__continue,
+ active=step,
+ items=items,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout, "slip39_checklist", ButtonRequestType.ResetDevice
+ )
async def _prompt_number(
@@ -275,33 +271,29 @@ def slip39_advanced_prompt_group_threshold(num_of_groups: int) -> Awaitable[int]
)
-def show_intro_backup(num_of_words: int | None) -> Awaitable[None]:
+async def show_intro_backup(num_of_words: int | None) -> None:
if num_of_words is not None:
description = TR.backup__info_single_share_backup.format(num_of_words)
else:
description = TR.backup__info_multi_share_backup
- return raise_if_not_confirmed(
- trezorui_api.show_info(
- title="",
- description=description,
- button=(TR.buttons__continue, True),
- ),
- "backup_intro",
- ButtonRequestType.ResetDevice,
- )
+ with trezorui_api.show_info(
+ title="",
+ description=description,
+ button=(TR.buttons__continue, True),
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout, "backup_intro", ButtonRequestType.ResetDevice
+ )
-def show_warning_backup() -> Awaitable[trezorui_api.UiResult]:
- return interact(
- trezorui_api.show_info(
- title=TR.reset__never_make_digital_copy,
- description="",
- button=(TR.buttons__ok_i_understand, True),
- ),
- "backup_warning",
- ButtonRequestType.ResetDevice,
- )
+async def show_warning_backup() -> trezorui_api.UiResult:
+ with trezorui_api.show_info(
+ title=TR.reset__never_make_digital_copy,
+ description="",
+ button=(TR.buttons__ok_i_understand, True),
+ ) as layout:
+ return await interact(layout, "backup_warning", ButtonRequestType.ResetDevice)
async def show_success_backup() -> None:
@@ -314,24 +306,21 @@ async def show_success_backup() -> None:
)
-def show_reset_warning(
+async def show_reset_warning(
br_name: str,
content: str,
subheader: str | None = None,
button: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
-) -> Awaitable[trezorui_api.UiResult]:
+) -> trezorui_api.UiResult:
button = button or TR.buttons__try_again # def_arg
- return interact(
- trezorui_api.show_warning(
- title=subheader or "",
- description=content,
- button=button,
- allow_cancel=False,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.show_warning(
+ title=subheader or "",
+ description=content,
+ button=button,
+ allow_cancel=False,
+ ) as layout:
+ return await interact(layout, br_name, br_code)
async def show_share_confirmation_success(
diff --git a/core/src/trezor/ui/layouts/caesar/__init__.py b/core/src/trezor/ui/layouts/caesar/__init__.py
index fea53f15..d8800fbf 100644
--- a/core/src/trezor/ui/layouts/caesar/__init__.py
+++ b/core/src/trezor/ui/layouts/caesar/__init__.py
@@ -369,19 +369,16 @@ async def show_address(
)
return result
- result = await interact(
- trezorui_api.show_address_details(
- qr_title="", # unused on this model
- address=address if address_qr is None else address_qr,
- case_sensitive=case_sensitive,
- details_title="", # unused on this model
- account=account,
- path=path,
- xpubs=[(xpub_title(i), xpub) for i, xpub in enumerate(xpubs)],
- ),
- None,
- raise_on_cancel=None,
- )
+ with trezorui_api.show_address_details(
+ qr_title="", # unused on this model
+ address=address if address_qr is None else address_qr,
+ case_sensitive=case_sensitive,
+ details_title="", # unused on this model
+ account=account,
+ path=path,
+ xpubs=[(xpub_title(i), xpub) for i, xpub in enumerate(xpubs)],
+ ) as layout:
+ result = await interact(layout, None, raise_on_cancel=None)
# Can only go back from the address details.
assert result is CANCELLED
@@ -465,7 +462,7 @@ async def show_error_and_raise(
raise exc
-def show_warning(
+async def show_warning(
br_name: str,
content: str,
subheader: str | None = None,
@@ -473,7 +470,7 @@ def show_warning(
verb_cancel: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
exc: ExceptionType | None = ActionCancelled,
-) -> Awaitable[ui.UiResult]:
+) -> ui.UiResult:
from trezor import translations
button = button or TR.buttons__continue # def_arg
@@ -485,36 +482,33 @@ def show_warning(
if content and subheader and translations.get_language() == "en-US":
content = content + "\n"
- return interact(
- trezorui_api.show_warning(
- title="",
- button=button,
- value=content,
- description=subheader or "",
- ),
- br_name,
- br_code,
- raise_on_cancel=exc,
- )
+ with trezorui_api.show_warning(
+ title="",
+ button=button,
+ value=content,
+ description=subheader or "",
+ ) as layout:
+ return await interact(layout, br_name, br_code, raise_on_cancel=exc)
-def show_danger(
+async def show_danger(
br_name: str,
content: str,
title: str | None = None,
verb_cancel: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
-) -> Awaitable[None]:
+) -> None:
title = title or TR.words__warning
verb_cancel = verb_cancel or TR.buttons__cancel
- return raise_if_not_confirmed(
- trezorui_api.show_danger(
- title=title,
- description=content,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.show_danger(
+ title=title,
+ description=content,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ )
def show_success(
@@ -2142,7 +2136,7 @@ def error_popup(
*,
button: str = "",
timeout_ms: int = 0,
-) -> trezorui_api.LayoutObj[trezorui_api.UiResult]:
+) -> trezorui_api.LayoutContext[trezorui_api.UiResult]:
if button:
raise NotImplementedError("Button not implemented")
@@ -2246,17 +2240,17 @@ async def _confirm_multiple_pages_texts(
return await raise_if_not_confirmed(layout, br_name, br_code)
-def pin_mismatch_popup(is_wipe_code: bool = False) -> Awaitable[None]:
+async def pin_mismatch_popup(is_wipe_code: bool = False) -> None:
description = TR.wipe_code__mismatch if is_wipe_code else TR.pin__mismatch
br_name = "wipe_code_mismatch" if is_wipe_code else "pin_mismatch"
- layout = show_warning(
+ # result is ignored
+ await show_warning(
br_name,
description,
TR.pin__please_check_again,
TR.buttons__check_again,
br_code=BR_CODE_OTHER,
)
- return layout # type: ignore ["UiResult" is not assignable to "None"]
def wipe_code_same_as_pin_popup() -> Awaitable[None]:
diff --git a/core/src/trezor/ui/layouts/caesar/recovery.py b/core/src/trezor/ui/layouts/caesar/recovery.py
index 8b954bef..187df408 100644
--- a/core/src/trezor/ui/layouts/caesar/recovery.py
+++ b/core/src/trezor/ui/layouts/caesar/recovery.py
@@ -22,11 +22,10 @@ async def request_word_count(recovery_type: RecoveryType) -> int:
# May raise `RecoveryAborted`
await homescreen_dialog(TR.buttons__continue, TR.recovery__num_of_words)
- count = await interact(
- trezorui_api.select_word_count(recovery_type=recovery_type),
- "recovery_word_count",
- ButtonRequestType.MnemonicWordCount,
- )
+ with trezorui_api.select_word_count(recovery_type=recovery_type) as layout:
+ count = await interact(
+ layout, "recovery_word_count", ButtonRequestType.MnemonicWordCount
+ )
# It can be returning a string (for example for __debug__ in tests)
assert isinstance(count, (int, str))
return int(count)
@@ -67,21 +66,16 @@ async def show_remaining_shares(
raise NotImplementedError
-def show_group_share_success(
- share_index: int, group_index: int
-) -> Awaitable[ui.UiResult]:
- return interact(
- trezorui_api.show_group_share_success(
- lines=[
- TR.recovery__you_have_entered,
- TR.recovery__share_num_template.format(share_index + 1),
- TR.words__from,
- TR.recovery__group_num_template.format(group_index + 1),
- ],
- ),
- "share_success",
- ButtonRequestType.Other,
- )
+async def show_group_share_success(share_index: int, group_index: int) -> ui.UiResult:
+ with trezorui_api.show_group_share_success(
+ lines=[
+ TR.recovery__you_have_entered,
+ TR.recovery__share_num_template.format(share_index + 1),
+ TR.words__from,
+ TR.recovery__group_num_template.format(group_index + 1),
+ ],
+ ) as layout:
+ return await interact(layout, "share_success", ButtonRequestType.Other)
async def _confirm_abort(dry_run: bool = False) -> None:
diff --git a/core/src/trezor/ui/layouts/caesar/reset.py b/core/src/trezor/ui/layouts/caesar/reset.py
index 21d88a2b..2f9227df 100644
--- a/core/src/trezor/ui/layouts/caesar/reset.py
+++ b/core/src/trezor/ui/layouts/caesar/reset.py
@@ -48,15 +48,16 @@ async def show_share_words(
br_code=br_code,
)
- result = await interact(
- trezorui_api.show_share_words(
- words=share_words,
- title=None,
- ),
- br_name,
- br_code,
- raise_on_cancel=None,
- )
+ with trezorui_api.show_share_words(
+ words=share_words,
+ title=None,
+ ) as layout:
+ result = await interact(
+ layout,
+ br_name,
+ br_code,
+ raise_on_cancel=None,
+ )
if result is CONFIRMED:
break
@@ -84,28 +85,26 @@ async def select_word(
while len(words) < 3:
words.append(words[-1])
- result = await interact(
- trezorui_api.select_word(
- title="",
- description=TR.reset__select_word_x_of_y_template.format(
- checked_index + 1, count
- ),
- words=(words[0].lower(), words[1].lower(), words[2].lower()),
+ with trezorui_api.select_word(
+ title="",
+ description=TR.reset__select_word_x_of_y_template.format(
+ checked_index + 1, count
),
- None,
- )
+ words=(words[0].lower(), words[1].lower(), words[2].lower()),
+ ) as layout:
+ result = await interact(layout, None)
if __debug__ and isinstance(result, str):
return result
assert isinstance(result, int) and 0 <= result <= 2
return words[result]
-def slip39_show_checklist(
+async def slip39_show_checklist(
step: int,
advanced: bool,
count: int | None = None,
threshold: int | None = None,
-) -> Awaitable[None]:
+) -> None:
items = (
(
TR.reset__slip39_checklist_num_shares,
@@ -120,16 +119,15 @@ def slip39_show_checklist(
)
)
- return raise_if_not_confirmed(
- trezorui_api.show_checklist(
- title=TR.reset__slip39_checklist_title,
- button=TR.buttons__continue,
- active=step,
- items=items,
- ),
- "slip39_checklist",
- ButtonRequestType.ResetDevice,
- )
+ with trezorui_api.show_checklist(
+ title=TR.reset__slip39_checklist_title,
+ button=TR.buttons__continue,
+ active=step,
+ items=items,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout, "slip39_checklist", ButtonRequestType.ResetDevice
+ )
async def _prompt_number(
diff --git a/core/src/trezor/ui/layouts/delizia/__init__.py b/core/src/trezor/ui/layouts/delizia/__init__.py
index a8cab6a8..9c6d7824 100644
--- a/core/src/trezor/ui/layouts/delizia/__init__.py
+++ b/core/src/trezor/ui/layouts/delizia/__init__.py
@@ -188,15 +188,16 @@ def confirm_multisig_warning() -> Awaitable[None]:
)
-def confirm_multisig_different_paths_warning() -> Awaitable[None]:
- return raise_if_not_confirmed(
- trezorui_api.show_danger(
- title=f"{TR.words__important}!",
- description=TR.send__multisig_different_paths,
- ),
- "warning_multisig_different_paths",
- br_code=ButtonRequestType.Warning,
- )
+async def confirm_multisig_different_paths_warning() -> None:
+ with trezorui_api.show_danger(
+ title=f"{TR.words__important}!",
+ description=TR.send__multisig_different_paths,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ "warning_multisig_different_paths",
+ br_code=ButtonRequestType.Warning,
+ )
def confirm_multiple_accounts_warning() -> Awaitable[None]:
@@ -403,60 +404,50 @@ async def show_error_and_raise(
exc: ExceptionType = ActionCancelled,
) -> NoReturn:
button = button or TR.buttons__try_again # def_arg
- await interact(
- trezorui_api.show_error(
- title=subheader or "",
- description=content,
- button=button,
- allow_cancel=False,
- ),
- br_name,
- BR_CODE_OTHER,
- raise_on_cancel=None,
- )
+ with trezorui_api.show_error(
+ title=subheader or "",
+ description=content,
+ button=button,
+ allow_cancel=False,
+ ) as layout:
+ await interact(layout, br_name, BR_CODE_OTHER, raise_on_cancel=None)
raise exc
-def show_warning(
+async def show_warning(
br_name: str,
content: str,
subheader: str | None = None,
button: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
-) -> Awaitable[None]:
+) -> None:
button = button or TR.buttons__continue # def_arg
- return raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=TR.words__important,
- value=content,
- button=subheader or TR.words__continue_anyway_question,
- danger=True,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.show_warning(
+ title=TR.words__important,
+ value=content,
+ button=subheader or TR.words__continue_anyway_question,
+ danger=True,
+ ) as layout:
+ return await raise_if_not_confirmed(layout, br_name, br_code)
-def show_danger(
+async def show_danger(
br_name: str,
content: str,
value: str | None = None,
title: str | None = None,
verb_cancel: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
-) -> Awaitable[None]:
+) -> None:
title = title or TR.words__warning
verb_cancel = verb_cancel or TR.buttons__cancel
- return raise_if_not_confirmed(
- trezorui_api.show_danger(
- title=title,
- description=content,
- value=(value or ""),
- verb_cancel=verb_cancel,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.show_danger(
+ title=title,
+ description=content,
+ value=(value or ""),
+ verb_cancel=verb_cancel,
+ ) as layout:
+ return await raise_if_not_confirmed(layout, br_name, br_code)
async def show_success(
@@ -1177,18 +1168,19 @@ if not utils.BITCOIN_ONLY:
br_name=br_name,
)
else:
- main_layout = trezorui_api.confirm_with_info(
+ main_ctx = trezorui_api.confirm_with_info(
title=title,
items=[(recipient_str, True)],
verb="",
verb_info=TR.ethereum__contract_address,
)
- info_layout = trezorui_api.show_info_with_cancel(
+ info_ctx = trezorui_api.show_info_with_cancel(
title=TR.ethereum__contract_address,
items=[("", recipient_addr, True)],
chunkify=chunkify,
)
- await with_info(main_layout, info_layout, br_name, br_code)
+ with main_ctx as main_layout, info_ctx as info_layout:
+ await with_info(main_layout, info_layout, br_name, br_code)
if isinstance(total_amount, AboveThreshold):
await show_warning(
@@ -2126,7 +2118,7 @@ def error_popup(
*,
button: str = "",
timeout_ms: int = 0,
-) -> ui.LayoutObj[ui.UiResult]:
+) -> ui.LayoutContext[ui.UiResult]:
if not button and not timeout_ms:
raise ValueError("Either button or timeout_ms must be set")
@@ -2203,32 +2195,28 @@ async def confirm_reenter_pin(is_wipe_code: bool = False) -> None:
pass
-def pin_mismatch_popup(is_wipe_code: bool = False) -> Awaitable[ui.UiResult]:
+async def pin_mismatch_popup(is_wipe_code: bool = False) -> None:
title = TR.wipe_code__mismatch if is_wipe_code else TR.pin__mismatch
description = TR.wipe_code__enter_new if is_wipe_code else TR.pin__reenter_new
br_name = "wipe_code_mismatch" if is_wipe_code else "pin_mismatch"
- return interact(
- error_popup(
- title,
- description,
- button=TR.buttons__try_again,
- ),
- br_name,
- BR_CODE_OTHER,
- )
+ with error_popup(
+ title,
+ description,
+ button=TR.buttons__try_again,
+ ) as layout:
+ # result is ignored
+ await interact(layout, br_name, BR_CODE_OTHER)
-def wipe_code_same_as_pin_popup() -> Awaitable[ui.UiResult]:
- return interact(
- error_popup(
- TR.wipe_code__invalid,
- TR.wipe_code__diff_from_pin,
- button=TR.buttons__try_again,
- ),
- "wipe_code_same_as_pin",
- BR_CODE_OTHER,
- )
+async def wipe_code_same_as_pin_popup() -> None:
+ with error_popup(
+ TR.wipe_code__invalid,
+ TR.wipe_code__diff_from_pin,
+ button=TR.buttons__try_again,
+ ) as layout:
+ # result is ignored
+ await interact(layout, "wipe_code_same_as_pin", BR_CODE_OTHER)
async def wipe_code_pin_not_set_popup(
diff --git a/core/src/trezor/ui/layouts/delizia/recovery.py b/core/src/trezor/ui/layouts/delizia/recovery.py
index f5cd863f..8f75ad59 100644
--- a/core/src/trezor/ui/layouts/delizia/recovery.py
+++ b/core/src/trezor/ui/layouts/delizia/recovery.py
@@ -18,11 +18,10 @@ if TYPE_CHECKING:
async def request_word_count(recovery_type: RecoveryType) -> int:
- count = await interact(
- trezorui_api.select_word_count(recovery_type=recovery_type),
- "recovery_word_count",
- ButtonRequestType.MnemonicWordCount,
- )
+ with trezorui_api.select_word_count(recovery_type=recovery_type) as layout:
+ count = await interact(
+ layout, "recovery_word_count", ButtonRequestType.MnemonicWordCount
+ )
assert isinstance(count, (int, str))
return int(count)
@@ -88,18 +87,15 @@ def format_remaining_shares_info(
async def show_group_share_success(share_index: int, group_index: int) -> None:
- await raise_if_not_confirmed(
- trezorui_api.show_group_share_success(
- lines=[
- TR.recovery__you_have_entered,
- TR.recovery__share_num_template.format(share_index + 1),
- TR.words__from,
- TR.recovery__group_num_template.format(group_index + 1),
- ],
- ),
- "share_success",
- ButtonRequestType.Other,
- )
+ with trezorui_api.show_group_share_success(
+ lines=[
+ TR.recovery__you_have_entered,
+ TR.recovery__share_num_template.format(share_index + 1),
+ TR.words__from,
+ TR.recovery__group_num_template.format(group_index + 1),
+ ],
+ ) as layout:
+ await raise_if_not_confirmed(layout, "share_success", ButtonRequestType.Other)
async def continue_recovery(
@@ -178,17 +174,14 @@ async def show_recovery_warning(
br_code: ButtonRequestType = ButtonRequestType.Warning,
) -> None:
button = button or TR.buttons__try_again # def_arg
- await raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=content or TR.words__warning,
- value=subheader or "",
- button=button,
- description="",
- danger=True,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.show_warning(
+ title=content or TR.words__warning,
+ value=subheader or "",
+ button=button,
+ description="",
+ danger=True,
+ ) as layout:
+ await raise_if_not_confirmed(layout, br_name, br_code)
async def show_dry_run_result(result: bool, is_slip39: bool) -> None:
diff --git a/core/src/trezor/ui/layouts/delizia/reset.py b/core/src/trezor/ui/layouts/delizia/reset.py
index adff0a21..4d24e616 100644
--- a/core/src/trezor/ui/layouts/delizia/reset.py
+++ b/core/src/trezor/ui/layouts/delizia/reset.py
@@ -11,11 +11,11 @@ from . import raise_if_not_confirmed, show_success
CONFIRMED = trezorui_api.CONFIRMED # global_import_cache
-def show_share_words(
+async def show_share_words(
share_words: Sequence[str],
share_index: int | None = None,
group_index: int | None = None,
-) -> Awaitable[None]:
+) -> None:
if share_index is None:
subtitle = None
elif group_index is None:
@@ -37,18 +37,16 @@ def show_share_words(
assert len(instructions) < 3
text_confirm = TR.reset__words_written_down_template.format(words_count)
- return raise_if_not_confirmed(
- trezorui_api.show_share_words_extended(
- words=share_words,
- subtitle=subtitle,
- instructions=instructions,
- instructions_verb=None,
- text_footer=description,
- text_confirm=text_confirm,
- text_check=TR.reset__check_backup_instructions,
- ),
- None,
- )
+ with trezorui_api.show_share_words_extended(
+ words=share_words,
+ subtitle=subtitle,
+ instructions=instructions,
+ instructions_verb=None,
+ text_footer=description,
+ text_confirm=text_confirm,
+ text_check=TR.reset__check_backup_instructions,
+ ) as layout:
+ return await raise_if_not_confirmed(layout, None)
async def select_word(
@@ -74,16 +72,14 @@ async def select_word(
while len(words) < 3:
words.append(words[-1])
- result = await interact(
- trezorui_api.select_word(
- title=title,
- description=TR.reset__select_word_x_of_y_template.format(
- checked_index + 1, count
- ),
- words=(words[0], words[1], words[2]),
+ with trezorui_api.select_word(
+ title=title,
+ description=TR.reset__select_word_x_of_y_template.format(
+ checked_index + 1, count
),
- None,
- )
+ words=(words[0], words[1], words[2]),
+ ) as layout:
+ result = await interact(layout, None)
if __debug__ and isinstance(result, str):
return result
assert isinstance(result, int) and 0 <= result <= 2
@@ -97,16 +93,15 @@ async def slip39_show_checklist(
threshold: int | None = None,
) -> None:
items = _slip_39_checklist_items(step, advanced, count, threshold)
- result = await interact(
- trezorui_api.show_checklist(
- title=TR.reset__title_shamir_backup,
- button=TR.buttons__continue,
- active=step,
- items=items,
- ),
- "slip39_checklist",
- ButtonRequestType.ResetDevice,
- )
+ with trezorui_api.show_checklist(
+ title=TR.reset__title_shamir_backup,
+ button=TR.buttons__continue,
+ active=step,
+ items=items,
+ ) as layout:
+ result = await interact(
+ layout, "slip39_checklist", ButtonRequestType.ResetDevice
+ )
if result != CONFIRMED:
raise ActionCancelled
@@ -289,28 +284,22 @@ async def show_intro_backup(num_of_words: int | None) -> None:
else:
description = TR.backup__info_multi_share_backup
- await interact(
- trezorui_api.show_info(
- title=TR.backup__title_create_wallet_backup,
- description=description,
- ),
- "backup_intro",
- ButtonRequestType.ResetDevice,
- )
+ with trezorui_api.show_info(
+ title=TR.backup__title_create_wallet_backup,
+ description=description,
+ ) as layout:
+ await interact(layout, "backup_intro", ButtonRequestType.ResetDevice)
-def show_warning_backup() -> Awaitable[ui.UiResult]:
- return interact(
- trezorui_api.show_warning(
- title=TR.words__important,
- value=TR.reset__never_make_digital_copy,
- button="",
- allow_cancel=False,
- danger=False, # Use a less severe icon color
- ),
- "backup_warning",
- ButtonRequestType.ResetDevice,
- )
+async def show_warning_backup() -> ui.UiResult:
+ with trezorui_api.show_warning(
+ title=TR.words__important,
+ value=TR.reset__never_make_digital_copy,
+ button="",
+ allow_cancel=False,
+ danger=False, # Use a less severe icon color
+ ) as layout:
+ return await interact(layout, "backup_warning", ButtonRequestType.ResetDevice)
def show_success_backup() -> Awaitable[None]:
@@ -320,25 +309,22 @@ def show_success_backup() -> Awaitable[None]:
)
-def show_reset_warning(
+async def show_reset_warning(
br_name: str,
content: str,
subheader: str | None = None,
button: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
-) -> Awaitable[None]:
- return raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=subheader or "",
- description=content,
- value="",
- button="",
- allow_cancel=False,
- danger=True,
- ),
- br_name,
- br_code,
- )
+) -> None:
+ with trezorui_api.show_warning(
+ title=subheader or "",
+ description=content,
+ value="",
+ button="",
+ allow_cancel=False,
+ danger=True,
+ ) as layout:
+ return await raise_if_not_confirmed(layout, br_name, br_code)
async def show_share_confirmation_success(
diff --git a/core/src/trezor/ui/layouts/eckhart/__init__.py b/core/src/trezor/ui/layouts/eckhart/__init__.py
index ba34c30e..83fcc89b 100644
--- a/core/src/trezor/ui/layouts/eckhart/__init__.py
+++ b/core/src/trezor/ui/layouts/eckhart/__init__.py
@@ -357,42 +357,39 @@ async def show_error_and_raise(
exc: ExceptionType = ActionCancelled,
) -> NoReturn:
button = button or TR.buttons__try_again # def_arg
- await interact(
- trezorui_api.show_error(
- title=subheader or "",
- description=content,
- button=button,
- allow_cancel=False,
- ),
- br_name,
- BR_CODE_OTHER,
- raise_on_cancel=None,
- )
+ with trezorui_api.show_error(
+ title=subheader or "",
+ description=content,
+ button=button,
+ allow_cancel=False,
+ ) as layout:
+ await interact(layout, br_name, BR_CODE_OTHER, raise_on_cancel=None)
raise exc
-def show_warning(
+async def show_warning(
br_name: str,
content: str,
subheader: str | None = None,
button: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
-) -> Awaitable[None]:
+) -> None:
button = button or TR.words__continue_anyway # def_arg
- return raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=TR.words__important,
- button=button,
- description=content,
- value=subheader or "",
- danger=True,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.show_warning(
+ title=TR.words__important,
+ button=button,
+ description=content,
+ value=subheader or "",
+ danger=True,
+ ) as layout:
+ return await raise_if_not_confirmed(
+ layout,
+ br_name,
+ br_code,
+ )
-def show_danger(
+async def show_danger(
br_name: str,
content: str,
value: str | None = None,
@@ -400,20 +397,17 @@ def show_danger(
menu_title: str | None = None,
verb_cancel: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
-) -> Awaitable[None]:
+) -> None:
title = title or TR.words__warning
verb_cancel = verb_cancel or TR.buttons__cancel
- return raise_if_not_confirmed(
- trezorui_api.show_danger(
- title=title,
- description=content,
- value=(value or ""),
- menu_title=menu_title,
- verb_cancel=verb_cancel,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.show_danger(
+ title=title,
+ description=content,
+ value=(value or ""),
+ menu_title=menu_title,
+ verb_cancel=verb_cancel,
+ ) as layout:
+ return await raise_if_not_confirmed(layout, br_name, br_code)
async def show_success(
@@ -1209,7 +1203,7 @@ if not utils.BITCOIN_ONLY:
verb=TR.buttons__continue,
)
else:
- main_layout = trezorui_api.confirm_with_info(
+ main_ctx = trezorui_api.confirm_with_info(
title=title,
subtitle=(
TR.ethereum__approve_revoke_from
@@ -1220,12 +1214,13 @@ if not utils.BITCOIN_ONLY:
verb=TR.buttons__continue,
verb_info=TR.ethereum__contract_address,
)
- info_layout = trezorui_api.show_info_with_cancel(
+ info_ctx = trezorui_api.show_info_with_cancel(
title=title,
items=[("", recipient_addr, True)],
chunkify=chunkify,
)
- await with_info(main_layout, info_layout, br_name, br_code)
+ with main_ctx as main_layout, info_ctx as info_layout:
+ await with_info(main_layout, info_layout, br_name, br_code)
if isinstance(total_amount, AboveThreshold):
await show_warning(
@@ -2221,7 +2216,7 @@ def error_popup(
*,
button: str = "",
timeout_ms: int = 0,
-) -> ui.LayoutObj[ui.UiResult]:
+) -> ui.LayoutContext[ui.UiResult]:
if not button and not timeout_ms:
raise ValueError("Either button or timeout_ms must be set")
@@ -2302,32 +2297,28 @@ async def confirm_reenter_pin(is_wipe_code: bool = False) -> None:
pass
-def pin_mismatch_popup(is_wipe_code: bool = False) -> Awaitable[ui.UiResult]:
+async def pin_mismatch_popup(is_wipe_code: bool = False) -> None:
description = TR.wipe_code__mismatch if is_wipe_code else TR.pin__mismatch
button = TR.wipe_code__enter_new if is_wipe_code else TR.pin__reenter
br_name = "wipe_code_mismatch" if is_wipe_code else "pin_mismatch"
- return interact(
- error_popup(
- TR.words__important,
- description,
- button=button,
- ),
- br_name,
- BR_CODE_OTHER,
- )
+ with error_popup(
+ TR.words__important,
+ description,
+ button=button,
+ ) as layout:
+ # result is ignored
+ await interact(layout, br_name, BR_CODE_OTHER)
-def wipe_code_same_as_pin_popup() -> Awaitable[ui.UiResult]:
- return interact(
- error_popup(
- TR.words__important,
- TR.wipe_code__diff_from_pin,
- button=TR.buttons__try_again,
- ),
- "wipe_code_same_as_pin",
- BR_CODE_OTHER,
- )
+async def wipe_code_same_as_pin_popup() -> None:
+ with error_popup(
+ TR.words__important,
+ TR.wipe_code__diff_from_pin,
+ button=TR.buttons__try_again,
+ ) as layout:
+ # result is ignored
+ await interact(layout, "wipe_code_same_as_pin", BR_CODE_OTHER)
async def wipe_code_pin_not_set_popup(
diff --git a/core/src/trezor/ui/layouts/eckhart/fido.py b/core/src/trezor/ui/layouts/eckhart/fido.py
index 8a92a120..0d59d3e2 100644
--- a/core/src/trezor/ui/layouts/eckhart/fido.py
+++ b/core/src/trezor/ui/layouts/eckhart/fido.py
@@ -43,17 +43,16 @@ async def confirm_fido(
async def confirm_fido_reset() -> bool:
from trezor import TR
- confirm = ui.Layout(
- trezorui_api.show_warning(
- title=TR.words__important,
- button=TR.buttons__confirm,
- value=TR.fido__erase_credentials,
- description="",
- allow_cancel=True,
- danger=True,
- )
- )
- return (await confirm.get_result()) is trezorui_api.CONFIRMED
+ with trezorui_api.show_warning(
+ title=TR.words__important,
+ button=TR.buttons__confirm,
+ value=TR.fido__erase_credentials,
+ description="",
+ allow_cancel=True,
+ danger=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/recovery.py b/core/src/trezor/ui/layouts/eckhart/recovery.py
index 1e6b05f6..faf7353b 100644
--- a/core/src/trezor/ui/layouts/eckhart/recovery.py
+++ b/core/src/trezor/ui/layouts/eckhart/recovery.py
@@ -22,11 +22,10 @@ if TYPE_CHECKING:
async def request_word_count(recovery_type: RecoveryType) -> int:
- count = await interact(
- trezorui_api.select_word_count(recovery_type=recovery_type),
- "recovery_word_count",
- ButtonRequestType.MnemonicWordCount,
- )
+ with trezorui_api.select_word_count(recovery_type=recovery_type) as layout:
+ count = await interact(
+ layout, "recovery_word_count", ButtonRequestType.MnemonicWordCount
+ )
assert isinstance(count, (int, str))
return int(count)
@@ -92,18 +91,15 @@ def format_remaining_shares_info(
async def show_group_share_success(share_index: int, group_index: int) -> None:
- await raise_if_not_confirmed(
- trezorui_api.show_group_share_success(
- lines=[
- f"{TR.recovery__share_from_group_entered_template.format(share_index + 1, group_index + 1)}",
- "",
- "",
- "",
- ],
- ),
- "share_success",
- ButtonRequestType.Other,
- )
+ with trezorui_api.show_group_share_success(
+ lines=[
+ f"{TR.recovery__share_from_group_entered_template.format(share_index + 1, group_index + 1)}",
+ "",
+ "",
+ "",
+ ],
+ ) as layout:
+ await raise_if_not_confirmed(layout, "share_success", ButtonRequestType.Other)
async def continue_recovery(
@@ -179,18 +175,15 @@ async def show_recovery_warning(
button: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
) -> None:
- await raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=subheader or TR.words__important,
- value=content or "",
- button=button or TR.buttons__continue,
- description="",
- danger=True,
- allow_cancel=False,
- ),
- br_name,
- br_code,
- )
+ with trezorui_api.show_warning(
+ title=subheader or TR.words__important,
+ value=content or "",
+ button=button or TR.buttons__continue,
+ description="",
+ danger=True,
+ allow_cancel=False,
+ ) as layout:
+ await raise_if_not_confirmed(layout, br_name, br_code)
async def show_dry_run_result(result: bool, is_slip39: bool) -> None:
@@ -226,12 +219,10 @@ if utils.USE_N4W1:
import trezorui_api
from trezor.enums import BackupMethod
- index = await interact(
- trezorui_api.select_word(
- title=title,
- description=description,
- words=(TR.backup__type_n4w1, TR.backup__type_wordlist, ""),
- ),
- br_name="choose_method",
- )
+ with trezorui_api.select_word(
+ title=title,
+ description=description,
+ words=(TR.backup__type_n4w1, TR.backup__type_wordlist, ""),
+ ) as layout:
+ index = await interact(layout, br_name="choose_method")
return (BackupMethod.N4W1, BackupMethod.Display)[index]
diff --git a/core/src/trezor/ui/layouts/eckhart/reset.py b/core/src/trezor/ui/layouts/eckhart/reset.py
index 0ac823d4..536ccfd7 100644
--- a/core/src/trezor/ui/layouts/eckhart/reset.py
+++ b/core/src/trezor/ui/layouts/eckhart/reset.py
@@ -11,11 +11,11 @@ from . import raise_if_not_confirmed, show_success
CONFIRMED = trezorui_api.CONFIRMED # global_import_cache
-def show_share_words(
+async def show_share_words(
share_words: Sequence[str],
share_index: int | None = None,
group_index: int | None = None,
-) -> Awaitable[None]:
+) -> None:
if share_index is None:
subtitle = None
elif group_index is None:
@@ -58,18 +58,16 @@ def show_share_words(
text_confirm = TR.reset__words_written_down_template.format(words_count)
- return raise_if_not_confirmed(
- trezorui_api.show_share_words_extended(
- words=share_words,
- subtitle=subtitle,
- instructions=instructions,
- instructions_verb=instructions_verb,
- text_confirm=text_confirm,
- text_check=text_check,
- text_footer=None,
- ),
- None,
- )
+ with trezorui_api.show_share_words_extended(
+ words=share_words,
+ subtitle=subtitle,
+ instructions=instructions,
+ instructions_verb=instructions_verb,
+ text_confirm=text_confirm,
+ text_check=text_check,
+ text_footer=None,
+ ) as layout:
+ return await raise_if_not_confirmed(layout, None)
async def select_word(
@@ -100,14 +98,12 @@ async def select_word(
while len(words) < 3:
words.append(words[-1])
- result = await interact(
- trezorui_api.select_word(
- title=title,
- description=description,
- words=(words[0], words[1], words[2]),
- ),
- None,
- )
+ with trezorui_api.select_word(
+ title=title,
+ description=description,
+ words=(words[0], words[1], words[2]),
+ ) as layout:
+ result = await interact(layout, None)
if __debug__ and isinstance(result, str):
return result
assert isinstance(result, int) and 0 <= result <= 2
@@ -121,16 +117,15 @@ async def slip39_show_checklist(
threshold: int | None = None,
) -> None:
items = _slip_39_checklist_items(step, advanced, count, threshold)
- result = await interact(
- trezorui_api.show_checklist(
- title=TR.reset__title_shamir_backup,
- button=TR.buttons__continue,
- active=step,
- items=items,
- ),
- "slip39_checklist",
- ButtonRequestType.ResetDevice,
- )
+ with trezorui_api.show_checklist(
+ title=TR.reset__title_shamir_backup,
+ button=TR.buttons__continue,
+ active=step,
+ items=items,
+ ) as layout:
+ result = await interact(
+ layout, "slip39_checklist", ButtonRequestType.ResetDevice
+ )
if result != CONFIRMED:
raise ActionCancelled
@@ -313,29 +308,31 @@ async def show_intro_backup(num_of_words: int | None) -> None:
else:
description = TR.backup__info_multi_share_backup
- await interact(
- trezorui_api.show_info(
- title=TR.reset__recovery_wallet_backup_title,
- description=description,
- button=(TR.buttons__continue, True),
- ),
- "backup_intro",
- ButtonRequestType.ResetDevice,
- )
+ with trezorui_api.show_info(
+ title=TR.reset__recovery_wallet_backup_title,
+ description=description,
+ button=(TR.buttons__continue, True),
+ ) as layout:
+ await interact(
+ layout,
+ "backup_intro",
+ ButtonRequestType.ResetDevice,
+ )
-def show_warning_backup() -> Awaitable[ui.UiResult]:
- return interact(
- trezorui_api.show_warning(
- title=TR.words__important,
- value=TR.reset__never_make_digital_copy,
- button=TR.buttons__continue,
- allow_cancel=False,
- danger=False, # Use a less severe icon color
- ),
- "backup_warning",
- ButtonRequestType.ResetDevice,
- )
+async def show_warning_backup() -> ui.UiResult:
+ with trezorui_api.show_warning(
+ title=TR.words__important,
+ value=TR.reset__never_make_digital_copy,
+ button=TR.buttons__continue,
+ allow_cancel=False,
+ danger=False, # Use a less severe icon color
+ ) as layout:
+ return await interact(
+ layout,
+ "backup_warning",
+ ButtonRequestType.ResetDevice,
+ )
def show_success_backup() -> Awaitable[None]:
@@ -347,25 +344,22 @@ def show_success_backup() -> Awaitable[None]:
)
-def show_reset_warning(
+async def show_reset_warning(
br_name: str,
content: str,
subheader: str | None = None,
button: str | None = None,
br_code: ButtonRequestType = ButtonRequestType.Warning,
-) -> Awaitable[None]:
- return raise_if_not_confirmed(
- trezorui_api.show_warning(
- title=subheader or "",
- description="",
- value=content,
- button=button or "",
- allow_cancel=False,
- danger=True,
- ),
- br_name,
- br_code,
- )
+) -> None:
+ with trezorui_api.show_warning(
+ title=subheader or "",
+ description="",
+ value=content,
+ button=button or "",
+ allow_cancel=False,
+ danger=True,
+ ) as layout:
+ return await raise_if_not_confirmed(layout, br_name, br_code)
async def show_share_confirmation_success(
diff --git a/core/src/trezor/wire/thp/ui.py b/core/src/trezor/wire/thp/ui.py
index 6cd84e23..e18af382 100644
--- a/core/src/trezor/wire/thp/ui.py
+++ b/core/src/trezor/wire/thp/ui.py
@@ -105,15 +105,13 @@ async def show_qr_code_screen(qr_code_str: str) -> UiResult:
from trezor.ui.layouts.common import interact
from trezorui_api import show_address_details
- return await interact(
- show_address_details( # noqa
- qr_title=TR.thp__qr_title,
- address=qr_code_str,
- case_sensitive=True,
- details_title="",
- account="",
- path="",
- xpubs=[],
- ),
- br_name=None,
- )
+ with show_address_details(
+ qr_title=TR.thp__qr_title,
+ address=qr_code_str,
+ case_sensitive=True,
+ details_title="",
+ account="",
+ path="",
+ xpubs=[],
+ ) as layout:
+ return await interact(layout, br_name=None)
Why this scored 21/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.