From f32d747f88b712fe1c8c1b1439cfb9718f8d43e6 Mon Sep 17 00:00:00 2001 From: Lukas Bielesch Date: Wed, 18 Jun 2025 17:21:13 +0200 Subject: [PATCH] chore(core): promote multiple_accounts_warning to danger - for eckhart and delizia layouts --- core/.changelog.d/5218.changed | 1 + core/embed/rust/librust_qstr.h | 1 + .../src/translations/generated/translated_string.rs | 3 +++ core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs | 7 ++++--- core/mocks/trezortranslate_keys.pyi | 1 + core/src/apps/bitcoin/sign_tx/layout.py | 8 +------- core/src/trezor/ui/layouts/bolt/__init__.py | 10 ++++++++++ core/src/trezor/ui/layouts/caesar/__init__.py | 10 ++++++++++ core/src/trezor/ui/layouts/delizia/__init__.py | 9 +++++++++ core/src/trezor/ui/layouts/eckhart/__init__.py | 10 ++++++++++ core/translations/en.json | 1 + core/translations/order.json | 3 ++- core/translations/signatures.json | 6 +++--- tests/device_tests/bitcoin/test_signtx_invalid_path.py | 2 ++ tests/device_tests/bitcoin/test_signtx_mixed_inputs.py | 9 +++++++++ tests/device_tests/bitcoin/test_signtx_segwit.py | 5 +++++ .../device_tests/bitcoin/test_signtx_segwit_native.py | 2 ++ tests/device_tests/bitcoin/test_signtx_taproot.py | 5 +++++ tests/input_flows.py | 10 ++++++++-- 19 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 core/.changelog.d/5218.changed diff --git a/core/.changelog.d/5218.changed b/core/.changelog.d/5218.changed new file mode 100644 index 0000000000..a230ab3123 --- /dev/null +++ b/core/.changelog.d/5218.changed @@ -0,0 +1 @@ +[T3T1] Change multiple accounts warning to danger. diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index cba4833a8e..92de809d9e 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -677,6 +677,7 @@ static void _librust_qstrs(void) { MP_QSTR_select_word; MP_QSTR_select_word_count; MP_QSTR_send__cancel_sign; + MP_QSTR_send__cancel_transaction; MP_QSTR_send__confirm_sending; MP_QSTR_send__from_multiple_accounts; MP_QSTR_send__incl_transaction_fee; diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs index 94118f1fcc..ce135813ff 100644 --- a/core/embed/rust/src/translations/generated/translated_string.rs +++ b/core/embed/rust/src/translations/generated/translated_string.rs @@ -1446,6 +1446,7 @@ pub enum TranslatedString { reset__check_share_backup_template = 1042, // "Let's do a quick check of Share #{0}." reset__select_word_from_share_template = 1043, // "Select word #{0} from\nShare #{1}" recovery__share_from_group_entered_template = 1044, // "Share #{0} from Group #{1} entered." + send__cancel_transaction = 1045, // "Cancel transaction" } impl TranslatedString { @@ -3197,6 +3198,7 @@ impl TranslatedString { (Self::reset__check_share_backup_template, "Let's do a quick check of Share #{0}."), (Self::reset__select_word_from_share_template, "Select word #{0} from\nShare #{1}"), (Self::recovery__share_from_group_entered_template, "Share #{0} from Group #{1} entered."), + (Self::send__cancel_transaction, "Cancel transaction"), ]; #[cfg(feature = "micropython")] @@ -4261,6 +4263,7 @@ impl TranslatedString { (Qstr::MP_QSTR_sd_card__wanna_format, Self::sd_card__wanna_format), (Qstr::MP_QSTR_sd_card__wrong_sd_card, Self::sd_card__wrong_sd_card), (Qstr::MP_QSTR_send__cancel_sign, Self::send__cancel_sign), + (Qstr::MP_QSTR_send__cancel_transaction, Self::send__cancel_transaction), (Qstr::MP_QSTR_send__confirm_sending, Self::send__confirm_sending), (Qstr::MP_QSTR_send__from_multiple_accounts, Self::send__from_multiple_accounts), (Qstr::MP_QSTR_send__incl_transaction_fee, Self::send__incl_transaction_fee), diff --git a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs index 53a393697c..bbb47de160 100644 --- a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs +++ b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs @@ -1350,11 +1350,12 @@ impl FirmwareUI for UIEckhart { danger: bool, ) -> Result, Error> { let paragraphs = ParagraphVecShort::from_iter([ - Paragraph::new(&theme::TEXT_SMALL, description), + Paragraph::new(&theme::TEXT_REGULAR, description), Paragraph::new(&theme::TEXT_REGULAR, value), ]) .into_paragraphs() - .with_placement(LinearPlacement::vertical()); + .with_placement(LinearPlacement::vertical()) + .with_spacing(theme::TEXT_VERTICAL_SPACING); let (color, style) = if danger { (theme::ORANGE, theme::label_title_danger()) @@ -1367,7 +1368,7 @@ impl FirmwareUI for UIEckhart { .with_text_style(style); let action_bar = if allow_cancel { ActionBar::new_double( - Button::with_icon(theme::ICON_CROSS).styled(theme::button_cancel()), + Button::with_icon(theme::ICON_CROSS), Button::with_single_line_text(button), ) } else { diff --git a/core/mocks/trezortranslate_keys.pyi b/core/mocks/trezortranslate_keys.pyi index 6dee328828..f3613104e9 100644 --- a/core/mocks/trezortranslate_keys.pyi +++ b/core/mocks/trezortranslate_keys.pyi @@ -761,6 +761,7 @@ class TR: sd_card__wanna_format: str = "Do you really want to format the SD card?" sd_card__wrong_sd_card: str = "Wrong SD card." send__cancel_sign: str = "Cancel sign" + send__cancel_transaction: str = "Cancel transaction" send__confirm_sending: str = "Sending amount" send__from_multiple_accounts: str = "Sending from multiple accounts." send__incl_transaction_fee: str = "incl. Transaction fee" diff --git a/core/src/apps/bitcoin/sign_tx/layout.py b/core/src/apps/bitcoin/sign_tx/layout.py index 932b596ed6..bb4cec1a51 100644 --- a/core/src/apps/bitcoin/sign_tx/layout.py +++ b/core/src/apps/bitcoin/sign_tx/layout.py @@ -283,13 +283,7 @@ async def confirm_unverified_external_input() -> None: async def confirm_multiple_accounts() -> None: - await layouts.show_warning( - "sending_from_multiple_accounts", - TR.send__from_multiple_accounts, - TR.words__continue_anyway_question, - button=TR.buttons__continue, - br_code=ButtonRequestType.SignTx, - ) + await layouts.confirm_multiple_accounts_warning() async def confirm_nondefault_locktime(lock_time: int, lock_time_disabled: bool) -> None: diff --git a/core/src/trezor/ui/layouts/bolt/__init__.py b/core/src/trezor/ui/layouts/bolt/__init__.py index 006619be98..ed0194936f 100644 --- a/core/src/trezor/ui/layouts/bolt/__init__.py +++ b/core/src/trezor/ui/layouts/bolt/__init__.py @@ -180,6 +180,16 @@ def confirm_multisig_different_paths_warning() -> Awaitable[None]: ) +def confirm_multiple_accounts_warning() -> Awaitable[None]: + return show_warning( + "sending_from_multiple_accounts", + TR.send__from_multiple_accounts, + TR.words__continue_anyway_question, + button=TR.buttons__continue, + br_code=ButtonRequestType.SignTx, + ) + + def confirm_homescreen(image: bytes) -> Awaitable[None]: return raise_if_not_confirmed( trezorui_api.confirm_homescreen( diff --git a/core/src/trezor/ui/layouts/caesar/__init__.py b/core/src/trezor/ui/layouts/caesar/__init__.py index 2f5a823098..b9a5946be4 100644 --- a/core/src/trezor/ui/layouts/caesar/__init__.py +++ b/core/src/trezor/ui/layouts/caesar/__init__.py @@ -197,6 +197,16 @@ def confirm_multisig_different_paths_warning() -> Awaitable[ui.UiResult]: ) +def confirm_multiple_accounts_warning() -> Awaitable[ui.UiResult]: + return show_warning( + "sending_from_multiple_accounts", + TR.send__from_multiple_accounts, + TR.words__continue_anyway_question, + button=TR.buttons__continue, + br_code=ButtonRequestType.SignTx, + ) + + def confirm_homescreen(image: bytes) -> Awaitable[None]: return raise_if_not_confirmed( trezorui_api.confirm_homescreen( diff --git a/core/src/trezor/ui/layouts/delizia/__init__.py b/core/src/trezor/ui/layouts/delizia/__init__.py index e8b806da73..f9df28a6bf 100644 --- a/core/src/trezor/ui/layouts/delizia/__init__.py +++ b/core/src/trezor/ui/layouts/delizia/__init__.py @@ -165,6 +165,15 @@ def confirm_multisig_different_paths_warning() -> Awaitable[None]: ) +def confirm_multiple_accounts_warning() -> Awaitable[None]: + return show_danger( + "sending_from_multiple_accounts", + TR.send__from_multiple_accounts, + verb_cancel=TR.send__cancel_transaction, + br_code=ButtonRequestType.SignTx, + ) + + def confirm_homescreen( image: bytes, ) -> Awaitable[None]: diff --git a/core/src/trezor/ui/layouts/eckhart/__init__.py b/core/src/trezor/ui/layouts/eckhart/__init__.py index 482e9cd76c..83a96fe6dc 100644 --- a/core/src/trezor/ui/layouts/eckhart/__init__.py +++ b/core/src/trezor/ui/layouts/eckhart/__init__.py @@ -174,6 +174,16 @@ def confirm_multisig_different_paths_warning() -> Awaitable[None]: ) +def confirm_multiple_accounts_warning() -> Awaitable[None]: + return show_danger( + "sending_from_multiple_accounts", + TR.send__from_multiple_accounts, + title=TR.words__important, + verb_cancel=TR.send__cancel_transaction, + br_code=ButtonRequestType.SignTx, + ) + + def confirm_homescreen( image: bytes, ) -> Awaitable[None]: diff --git a/core/translations/en.json b/core/translations/en.json index 89f0aa2478..08857a24c9 100644 --- a/core/translations/en.json +++ b/core/translations/en.json @@ -976,6 +976,7 @@ "send__maximum_fee": "Maximum fee", "send__receiving_to_multisig": "Receiving to a multisig address.", "send__send_from": "Send from", + "send__cancel_transaction": "Cancel transaction", "send__sign_transaction": "Sign transaction", "send__send_in_the_app": "After signing, send the transaction in the app.", "send__title_confirm_sending": "Confirm sending", diff --git a/core/translations/order.json b/core/translations/order.json index 74e8f4ee22..f0532c2993 100644 --- a/core/translations/order.json +++ b/core/translations/order.json @@ -1043,5 +1043,6 @@ "1041": "instructions__shares_start_with_x_template", "1042": "reset__check_share_backup_template", "1043": "reset__select_word_from_share_template", - "1044": "recovery__share_from_group_entered_template" + "1044": "recovery__share_from_group_entered_template", + "1045": "send__cancel_transaction" } diff --git a/core/translations/signatures.json b/core/translations/signatures.json index 46bd70385e..c70292dc39 100644 --- a/core/translations/signatures.json +++ b/core/translations/signatures.json @@ -1,8 +1,8 @@ { "current": { - "merkle_root": "c17219dfef87f023e53dd6470f633d38a8f8572466f987e0efe4536652b0d805", - "datetime": "2025-06-23T08:18:59.627189+00:00", - "commit": "1312054ba96c9037aa99cf48709d9cdafdeb708c" + "merkle_root": "4a06e39dde3af691ccef119898d3124fb596e384b777a55044f29d27a7ebbd8e", + "datetime": "2025-06-23T10:46:39.805001+00:00", + "commit": "f8327ed2c85209eafbe0c73eeea8861bf1cb57d7" }, "history": [ { diff --git a/tests/device_tests/bitcoin/test_signtx_invalid_path.py b/tests/device_tests/bitcoin/test_signtx_invalid_path.py index 5ef4ba0389..6e3da7dae8 100644 --- a/tests/device_tests/bitcoin/test_signtx_invalid_path.py +++ b/tests/device_tests/bitcoin/test_signtx_invalid_path.py @@ -179,6 +179,8 @@ def test_attack_path_segwit(client: Client): return msg with client: + IF = InputFlowConfirmAllWarnings(client) + client.set_input_flow(IF.get()) client.set_filter(messages.TxAck, attack_processor) with pytest.raises(TrezorFailure): btc.sign_tx( diff --git a/tests/device_tests/bitcoin/test_signtx_mixed_inputs.py b/tests/device_tests/bitcoin/test_signtx_mixed_inputs.py index de0f380768..5f56a382c0 100644 --- a/tests/device_tests/bitcoin/test_signtx_mixed_inputs.py +++ b/tests/device_tests/bitcoin/test_signtx_mixed_inputs.py @@ -18,6 +18,7 @@ from trezorlib import btc, messages from trezorlib.debuglink import TrezorClientDebugLink as Client from trezorlib.tools import parse_path +from ...input_flows import InputFlowConfirmAllWarnings from ...tx_cache import TxCache from .signtx import assert_tx_matches @@ -59,6 +60,8 @@ def test_non_segwit_segwit_inputs(client: Client): ) with client: + IF = InputFlowConfirmAllWarnings(client) + client.set_input_flow(IF.get()) signatures, serialized_tx = btc.sign_tx( client, "Testnet", [inp1, inp2], [out1], prev_txes=TX_API ) @@ -95,6 +98,8 @@ def test_segwit_non_segwit_inputs(client: Client): ) with client: + IF = InputFlowConfirmAllWarnings(client) + client.set_input_flow(IF.get()) signatures, serialized_tx = btc.sign_tx( client, "Testnet", [inp1, inp2], [out1], prev_txes=TX_API ) @@ -139,6 +144,8 @@ def test_segwit_non_segwit_segwit_inputs(client: Client): ) with client: + IF = InputFlowConfirmAllWarnings(client) + client.set_input_flow(IF.get()) signatures, serialized_tx = btc.sign_tx( client, "Testnet", [inp1, inp2, inp3], [out1], prev_txes=TX_API ) @@ -181,6 +188,8 @@ def test_non_segwit_segwit_non_segwit_inputs(client: Client): ) with client: + IF = InputFlowConfirmAllWarnings(client) + client.set_input_flow(IF.get()) signatures, serialized_tx = btc.sign_tx( client, "Testnet", [inp1, inp2, inp3], [out1], prev_txes=TX_API ) diff --git a/tests/device_tests/bitcoin/test_signtx_segwit.py b/tests/device_tests/bitcoin/test_signtx_segwit.py index 763626caef..5b2416bbbb 100644 --- a/tests/device_tests/bitcoin/test_signtx_segwit.py +++ b/tests/device_tests/bitcoin/test_signtx_segwit.py @@ -22,6 +22,7 @@ from trezorlib.exceptions import TrezorFailure from trezorlib.tools import H_, parse_path from ...common import is_core +from ...input_flows import InputFlowConfirmAllWarnings from ...tx_cache import TxCache from .signtx import ( assert_tx_matches, @@ -422,6 +423,8 @@ def test_attack_mixed_inputs(client: Client): expected_responses.insert(-2, request_input(0)) with client: + IF = InputFlowConfirmAllWarnings(client) + client.set_input_flow(IF.get()) # Sign unmodified transaction. # "Fee over threshold" warning is displayed - fee is the whole TRUE_AMOUNT client.set_expected_responses(expected_responses) @@ -447,6 +450,8 @@ def test_attack_mixed_inputs(client: Client): ) with pytest.raises(TrezorFailure) as e, client: + IF = InputFlowConfirmAllWarnings(client) + client.set_input_flow(IF.get()) client.set_expected_responses(expected_responses) btc.sign_tx( client, diff --git a/tests/device_tests/bitcoin/test_signtx_segwit_native.py b/tests/device_tests/bitcoin/test_signtx_segwit_native.py index 0c779c777e..b514ff0388 100644 --- a/tests/device_tests/bitcoin/test_signtx_segwit_native.py +++ b/tests/device_tests/bitcoin/test_signtx_segwit_native.py @@ -345,6 +345,8 @@ def test_send_both(client: Client): ) with client: + IF = InputFlowConfirmAllWarnings(client) + client.set_input_flow(IF.get()) client.set_expected_responses( [ request_input(0), diff --git a/tests/device_tests/bitcoin/test_signtx_taproot.py b/tests/device_tests/bitcoin/test_signtx_taproot.py index f548154ae7..695fc7c353 100644 --- a/tests/device_tests/bitcoin/test_signtx_taproot.py +++ b/tests/device_tests/bitcoin/test_signtx_taproot.py @@ -22,6 +22,7 @@ from trezorlib.exceptions import TrezorFailure from trezorlib.tools import H_, parse_path from ...common import is_core +from ...input_flows import InputFlowConfirmAllWarnings from ...tx_cache import TxCache from .signtx import ( assert_tx_matches, @@ -223,6 +224,8 @@ def test_send_mixed(client: Client): ) with client: + IF = InputFlowConfirmAllWarnings(client) + client.set_input_flow(IF.get()) client.set_expected_responses( [ # process inputs @@ -355,6 +358,8 @@ def test_attack_script_type(client: Client): return msg with client: + IF = InputFlowConfirmAllWarnings(client) + client.set_input_flow(IF.get()) client.set_filter(messages.TxAck, attack_processor) client.set_expected_responses( [ diff --git a/tests/input_flows.py b/tests/input_flows.py index 484720b3b8..f961c5bc9a 100644 --- a/tests/input_flows.py +++ b/tests/input_flows.py @@ -1130,7 +1130,9 @@ def sign_tx_go_to_info_delizia( if multi_account: yield client.debug.read_layout() - client.debug.swipe_up() + client.debug.click(client.debug.screen_buttons.menu()) + client.debug.synchronize_at("VerticalMenu") + client.debug.click(client.debug.screen_buttons.vertical_menu_items()[1]) yield # confirm transaction client.debug.read_layout() @@ -1168,7 +1170,9 @@ def sign_tx_go_to_info_eckhart( if multi_account: yield client.debug.read_layout() - client.debug.press_yes() + client.debug.click(client.debug.screen_buttons.menu()) + client.debug.synchronize_at("VerticalMenuScreen") + client.debug.click(client.debug.screen_buttons.vertical_menu_items()[1]) yield # confirm transaction client.debug.read_layout() @@ -2939,6 +2943,7 @@ class InputFlowConfirmAllWarnings(InputFlowBase): hi_prio = ( TR.words__cancel_and_exit, TR.send__cancel_sign, + TR.send__cancel_transaction, ) if any(needle.lower() in text for needle in hi_prio): self.debug.click(self.debug.screen_buttons.menu()) @@ -2967,6 +2972,7 @@ class InputFlowConfirmAllWarnings(InputFlowBase): hi_prio = ( TR.words__cancel_and_exit, TR.send__cancel_sign, + TR.send__cancel_transaction, ) if any(needle.lower() in text for needle in hi_prio): self.debug.click(self.debug.screen_buttons.menu())