diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index 4b3dbd1e7..50116a2f5 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -24,10 +24,12 @@ static void _librust_qstrs(void) { MP_QSTR_address_label; MP_QSTR_address_title; MP_QSTR_allow_cancel; + MP_QSTR_altcoin_tx_summary; MP_QSTR_amount; MP_QSTR_amount_change; MP_QSTR_amount_new; MP_QSTR_amount_title; + MP_QSTR_amount_value; MP_QSTR_app_name; MP_QSTR_attach_timer_fn; MP_QSTR_bootscreen; @@ -35,6 +37,7 @@ static void _librust_qstrs(void) { MP_QSTR_button; MP_QSTR_button_event; MP_QSTR_cancel_arrow; + MP_QSTR_cancel_cross; MP_QSTR_case_sensitive; MP_QSTR_check_homescreen_format; MP_QSTR_chunkify; @@ -69,11 +72,12 @@ static void _librust_qstrs(void) { MP_QSTR_dry_run; MP_QSTR_encode; MP_QSTR_encoded_length; - MP_QSTR_ethereum_tx_summary; MP_QSTR_extra; MP_QSTR_fee_amount; MP_QSTR_fee_label; MP_QSTR_fee_rate_amount; + MP_QSTR_fee_title; + MP_QSTR_fee_value; MP_QSTR_fingerprint; MP_QSTR_hold; MP_QSTR_hold_danger; @@ -90,7 +94,6 @@ static void _librust_qstrs(void) { MP_QSTR_max_feerate; MP_QSTR_max_len; MP_QSTR_max_rounds; - MP_QSTR_maximum_fee; MP_QSTR_min_count; MP_QSTR_multiple_pages_texts; MP_QSTR_notification; diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index 54c0055b8..db1708346 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -751,32 +751,39 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_ethereum_tx_summary(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { +extern "C" fn new_altcoin_tx_summary(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = |_args: &[Obj], kwargs: &Map| { - let total_amount: StrBuffer = kwargs.get(Qstr::MP_QSTR_total_amount)?.try_into()?; - let maximum_fee: StrBuffer = kwargs.get(Qstr::MP_QSTR_maximum_fee)?.try_into()?; + let amount_title: StrBuffer = kwargs.get(Qstr::MP_QSTR_amount_title)?.try_into()?; + let amount_value: StrBuffer = kwargs.get(Qstr::MP_QSTR_amount_value)?.try_into()?; + let fee_title: StrBuffer = kwargs.get(Qstr::MP_QSTR_fee_title)?.try_into()?; + let fee_value: StrBuffer = kwargs.get(Qstr::MP_QSTR_fee_value)?.try_into()?; + let cancel_cross: bool = kwargs.get_or(Qstr::MP_QSTR_cancel_cross, false)?; let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; let get_page = move |page_index| { match page_index { 0 => { - // Total amount + fee - let btn_layout = ButtonLayout::up_arrow_armed_info("CONFIRM".into()); + // Amount + fee + let btn_layout = if cancel_cross { + ButtonLayout::cancel_armed_info("CONFIRM".into()) + } else { + ButtonLayout::up_arrow_armed_info("CONFIRM".into()) + }; let btn_actions = ButtonActions::cancel_confirm_next(); let ops = OpTextLayout::new(theme::TEXT_MONO) - .text_mono(total_amount.clone()) + .text_mono(amount_value.clone()) .newline() .newline_half() - .text_bold("Maximum fee:".into()) + .text_bold(fee_title.clone()) .newline() - .text_mono(maximum_fee.clone()); + .text_mono(fee_value.clone()); let formatted = FormattedText::new(ops); - Page::new(btn_layout, btn_actions, formatted).with_title("Amount:".into()) + Page::new(btn_layout, btn_actions, formatted).with_title(amount_title.clone()) } 1 => { - // Fee information + // Other information let btn_layout = ButtonLayout::arrow_none_none(); let btn_actions = ButtonActions::prev_none_none(); @@ -1793,14 +1800,17 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Confirm summary of a transaction.""" Qstr::MP_QSTR_confirm_total => obj_fn_kw!(0, new_confirm_total).as_obj(), - /// def ethereum_tx_summary( + /// def altcoin_tx_summary( /// *, - /// total_amount: str, - /// maximum_fee: str, + /// amount_title: str, + /// amount_value: str, + /// fee_title: str, + /// fee_value: str, /// items: Iterable[Tuple[str, str]], + /// cancel_cross: bool = False, /// ) -> object: - /// """Confirm details about Ethereum transaction.""" - Qstr::MP_QSTR_ethereum_tx_summary => obj_fn_kw!(0, new_ethereum_tx_summary).as_obj(), + /// """Confirm details about altcoin transaction.""" + Qstr::MP_QSTR_altcoin_tx_summary => obj_fn_kw!(0, new_altcoin_tx_summary).as_obj(), /// def tutorial() -> object: /// """Show user how to interact with the device.""" diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index 96d244d59..7b3edd7a0 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -749,7 +749,7 @@ extern "C" fn new_show_info_with_cancel(n_args: usize, args: *const Obj, kwargs: let [key, value]: [Obj; 2] = iter_into_array(para)?; let key: StrBuffer = key.try_into()?; let value: StrBuffer = value.try_into()?; - paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, key)); + paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, key).no_break()); paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value)); } @@ -812,7 +812,7 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma for pair in IterBuf::new().try_iterate(items)? { let [label, value]: [StrBuffer; 2] = iter_into_array(pair)?; - paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, label)); + paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, label).no_break()); paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value)); } let mut page: ButtonPage<_, StrBuffer> = @@ -1757,7 +1757,7 @@ pub static mp_module_trezorui2: Module = obj_module! { /// def confirm_total( /// *, /// title: str, - /// items: list[tuple[str, str]], + /// items: Iterable[tuple[str, str]], /// info_button: bool = False, /// cancel_arrow: bool = False, /// ) -> object: diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index 474b48744..afcd5ea7b 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -169,13 +169,16 @@ def confirm_total( # rust/src/ui/model_tr/layout.rs -def ethereum_tx_summary( +def altcoin_tx_summary( *, - total_amount: str, - maximum_fee: str, + amount_title: str, + amount_value: str, + fee_title: str, + fee_value: str, items: Iterable[Tuple[str, str]], + cancel_cross: bool = False, ) -> object: - """Confirm details about Ethereum transaction.""" + """Confirm details about altcoin transaction.""" # rust/src/ui/model_tr/layout.rs @@ -586,7 +589,7 @@ def confirm_value( def confirm_total( *, title: str, - items: list[tuple[str, str]], + items: Iterable[tuple[str, str]], info_button: bool = False, cancel_arrow: bool = False, ) -> object: diff --git a/core/src/trezor/ui/layouts/tr/__init__.py b/core/src/trezor/ui/layouts/tr/__init__.py index d8e6a49b6..79a76e459 100644 --- a/core/src/trezor/ui/layouts/tr/__init__.py +++ b/core/src/trezor/ui/layouts/tr/__init__.py @@ -991,6 +991,33 @@ async def confirm_total( ) +async def confirm_solana_tx( + amount: str, + fee: str, + items: Iterable[tuple[str, str]], + amount_title="Amount:", + fee_title="Fee", + br_type: str = "confirm_solana_tx", + br_code: ButtonRequestType = ButtonRequestType.SignTx, +): + await raise_if_not_confirmed( + interact( + RustLayout( + trezorui2.altcoin_tx_summary( + amount_title=amount_title, + amount_value=amount, + fee_title=fee_title, + fee_value=fee, + items=items, + cancel_cross=True, + ) + ), + br_type=br_type, + br_code=br_code, + ) + ) + + async def confirm_ethereum_tx( recipient: str, total_amount: str, @@ -1001,9 +1028,11 @@ async def confirm_ethereum_tx( chunkify: bool = False, ) -> None: summary_layout = RustLayout( - trezorui2.ethereum_tx_summary( - total_amount=total_amount, - maximum_fee=maximum_fee, + trezorui2.altcoin_tx_summary( + amount_title="Amount:", + amount_value=total_amount, + fee_title="Maximum fee:", + fee_value=maximum_fee, items=items, ) ) diff --git a/core/src/trezor/ui/layouts/tt/__init__.py b/core/src/trezor/ui/layouts/tt/__init__.py index 09b6639ce..ea22c4964 100644 --- a/core/src/trezor/ui/layouts/tt/__init__.py +++ b/core/src/trezor/ui/layouts/tt/__init__.py @@ -901,33 +901,48 @@ async def confirm_properties( async def confirm_total( total_amount: str, fee_amount: str, - fee_rate_amount: str | None = None, title: str = "SUMMARY", total_label: str = "Total amount:", fee_label: str = "Including fee:", account_label: str | None = None, + fee_rate_amount: str | None = None, + br_type: str = "confirm_total", + br_code: ButtonRequestType = ButtonRequestType.SignTx, +) -> None: + items = [ + (total_label, total_amount), + (fee_label, fee_amount), + ] + info_items = [] + if account_label: + info_items.append(("Sending from account:", account_label)) + if fee_rate_amount: + info_items.append(("Fee rate:", fee_rate_amount)) + + await confirm_summary( + items, "SUMMARY", info_items, br_type=br_type, br_code=br_code + ) + + +async def confirm_summary( + items: Iterable[tuple[str, str]], + title: str = "SUMMARY", + info_items: Iterable[tuple[str, str]] | None = None, br_type: str = "confirm_total", br_code: ButtonRequestType = ButtonRequestType.SignTx, ) -> None: total_layout = RustLayout( trezorui2.confirm_total( - title=title, - items=[ - (total_label, total_amount), - (fee_label, fee_amount), - ], - info_button=bool(account_label or fee_rate_amount), + title=title.upper(), + items=items, + info_button=bool(info_items), ) ) - items: list[tuple[str, str]] = [] - if account_label: - items.append(("Sending from account:", account_label)) - if fee_rate_amount: - items.append(("Fee rate:", fee_rate_amount)) + info_items = info_items or [] info_layout = RustLayout( trezorui2.show_info_with_cancel( title="INFORMATION", - items=items, + items=info_items, ) ) await raise_if_not_confirmed(with_info(total_layout, info_layout, br_type, br_code)) @@ -980,6 +995,23 @@ async def confirm_ethereum_tx( continue +async def confirm_solana_tx( + amount: str, + fee: str, + items: Iterable[tuple[str, str]], + amount_title="Amount:", + fee_title="Fee", + br_type: str = "confirm_solana_tx", + br_code: ButtonRequestType = ButtonRequestType.SignTx, +): + await confirm_summary( + ((amount_title, amount), (fee_title, fee)), + info_items=items, + br_type=br_type, + br_code=br_code, + ) + + async def confirm_joint_total(spending_amount: str, total_amount: str) -> None: await raise_if_not_confirmed( interact( diff --git a/tools/check-bitcoin-only b/tools/check-bitcoin-only index 8158b56d1..4651bec8a 100755 --- a/tools/check-bitcoin-only +++ b/tools/check-bitcoin-only @@ -6,7 +6,7 @@ EXCEPTIONS+=( "decred" ) # "decred" figures in field names used by the bitcoin EXCEPTIONS+=( "omni" ) # OMNI is part of the bitcoin app # BIP39 or SLIP39 words that have "dash" in them EXCEPTIONS+=( "dash" ) -EXCEPTIONS+=( "confirm_ethereum_tx" "ethereum_tx_summary" ) # is model-specific, so is in layout/__init__.py instead of ethereum/layout.py +EXCEPTIONS+=( "confirm_ethereum_tx" ) # is model-specific, so is in layout/__init__.py instead of ethereum/layout.py GREP_ARGS=() for exception in "${EXCEPTIONS[@]}"; do