1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-24 13:22:05 +00:00

feat(core): support extra info item in summary menu on Delizia

It will allow confirming the blockhash for Solana transactions.

Also, simplify arguments passing into `new_confirm_output()`.

[no changelog]
This commit is contained in:
Roman Zeyde 2025-02-20 23:55:01 +02:00
parent 97b8409cf4
commit 4efc51d3b4
12 changed files with 85 additions and 50 deletions

View File

@ -63,9 +63,9 @@ static void _librust_qstrs(void) {
MP_QSTR_address_details__derivation_path_colon;
MP_QSTR_address_details__title_receive_address;
MP_QSTR_address_details__title_receiving_to;
MP_QSTR_address_item;
MP_QSTR_address_label;
MP_QSTR_address_qr;
MP_QSTR_address_title;
MP_QSTR_allow_cancel;
MP_QSTR_amount;
MP_QSTR_amount_change;
@ -232,6 +232,7 @@ static void _librust_qstrs(void) {
MP_QSTR_experimental_mode__only_for_dev;
MP_QSTR_experimental_mode__title;
MP_QSTR_extra;
MP_QSTR_extra_item;
MP_QSTR_extra_items;
MP_QSTR_extra_title;
MP_QSTR_fee;

View File

@ -435,9 +435,22 @@ extern "C" fn new_flow_confirm_output(n_args: usize, args: *const Obj, kwargs: *
let br_code: u16 = kwargs.get(Qstr::MP_QSTR_br_code)?.try_into()?;
let br_name: TString = kwargs.get(Qstr::MP_QSTR_br_name)?.try_into()?;
let address: Option<Obj> = kwargs.get(Qstr::MP_QSTR_address)?.try_into_option()?;
let address_title: Option<TString> =
kwargs.get(Qstr::MP_QSTR_address_title)?.try_into_option()?;
let address_item = kwargs
.get(Qstr::MP_QSTR_address_item)?
.try_into_option()?
.map(|item| -> Result<(TString, Obj), crate::error::Error> {
let pair: [Obj; 2] = util::iter_into_array(item)?;
Ok((pair[0].try_into()?, pair[1]))
})
.transpose()?;
let extra_item = kwargs
.get(Qstr::MP_QSTR_extra_item)?
.try_into_option()?
.map(|item| -> Result<(TString, Obj), crate::error::Error> {
let pair: [Obj; 2] = util::iter_into_array(item)?;
Ok((pair[0].try_into()?, pair[1]))
})
.transpose()?;
let summary_items: Option<Obj> =
kwargs.get(Qstr::MP_QSTR_summary_items)?.try_into_option()?;
let fee_items: Option<Obj> = kwargs.get(Qstr::MP_QSTR_fee_items)?.try_into_option()?;
@ -464,8 +477,8 @@ extern "C" fn new_flow_confirm_output(n_args: usize, args: *const Obj, kwargs: *
account_path,
br_code,
br_name,
address,
address_title,
address_item,
extra_item,
summary_items,
fee_items,
summary_title,
@ -1333,8 +1346,8 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// account_path: str | None,
/// br_code: ButtonRequestType,
/// br_name: str,
/// address: str | None,
/// address_title: str | None,
/// address_item: (str, str) | None,
/// extra_item: (str, str) | None,
/// summary_items: Iterable[tuple[str, str]] | None = None,
/// fee_items: Iterable[tuple[str, str]] | None = None,
/// summary_title: str | None = None,

View File

@ -98,7 +98,7 @@ pub struct SwipeFlow {
/// Current state of the flow.
state: FlowState,
/// Store of all screens which are part of the flow.
store: Vec<GcBox<dyn FlowComponentDynTrait>, 12>,
store: Vec<GcBox<dyn FlowComponentDynTrait>, 16>,
/// Swipe detector.
swipe: SwipeDetect,
/// Swipe allowed

View File

@ -548,8 +548,8 @@ impl FirmwareUI for UIBolt {
_account_path: Option<TString<'static>>,
_br_code: u16,
_br_name: TString<'static>,
_address: Option<Obj>,
_address_title: Option<TString<'static>>,
_address_item: Option<(TString<'static>, Obj)>,
_extra_item: Option<(TString<'static>, Obj)>,
_summary_items: Option<Obj>,
_fee_items: Option<Obj>,
_summary_title: Option<TString<'static>>,

View File

@ -687,8 +687,8 @@ impl FirmwareUI for UICaesar {
_account_path: Option<TString<'static>>,
_br_code: u16,
_br_name: TString<'static>,
_address: Option<Obj>,
_address_title: Option<TString<'static>>,
_address_item: Option<(TString<'static>, Obj)>,
_extra_item: Option<(TString<'static>, Obj)>,
_summary_items: Option<Obj>,
_fee_items: Option<Obj>,
_summary_title: Option<TString<'static>>,

View File

@ -30,6 +30,7 @@ const MENU_ITEM_CANCEL: usize = 0;
const MENU_ITEM_FEE_INFO: usize = 1;
const MENU_ITEM_ADDRESS_INFO: usize = 2;
const MENU_ITEM_ACCOUNT_INFO: usize = 3;
const MENU_ITEM_EXTRA_INFO: usize = 4;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum ConfirmOutput {
@ -123,6 +124,7 @@ pub enum ConfirmOutputWithSummary {
HoldMenu,
HoldMenuCancel,
AccountInfo,
ExtraInfo,
}
impl FlowController for ConfirmOutputWithSummary {
@ -144,6 +146,7 @@ impl FlowController for ConfirmOutputWithSummary {
(Self::Summary, Direction::Down) => Self::Main.swipe(direction),
(Self::SummaryMenu, Direction::Right) => Self::Summary.swipe(direction),
(Self::SummaryMenuCancel, Direction::Right) => Self::SummaryMenu.swipe(direction),
(Self::ExtraInfo, Direction::Right) => Self::SummaryMenu.swipe(direction),
(Self::FeeInfo, Direction::Right) => Self::SummaryMenu.swipe(direction),
(Self::Hold, Direction::Left) => Self::HoldMenu.swipe(direction),
(Self::Hold, Direction::Down) => Self::Summary.swipe(direction),
@ -162,6 +165,7 @@ impl FlowController for ConfirmOutputWithSummary {
(Self::AccountInfo, FlowMsg::Cancelled) => Self::MainMenu.goto(),
(Self::MainMenuCancel, FlowMsg::Cancelled) => Self::MainMenu.goto(),
(Self::AddressInfo, FlowMsg::Info) => Self::MainMenu.goto(),
(Self::ExtraInfo, FlowMsg::Info) => Self::SummaryMenu.goto(),
(Self::Summary, FlowMsg::Info) => Self::SummaryMenu.goto(),
(Self::SummaryMenu, FlowMsg::Choice(MENU_ITEM_CANCEL)) => {
Self::SummaryMenuCancel.swipe_left()
@ -173,6 +177,9 @@ impl FlowController for ConfirmOutputWithSummary {
}
(Self::HoldMenuCancel, FlowMsg::Cancelled) => Self::HoldMenu.goto(),
(Self::SummaryMenu, FlowMsg::Choice(MENU_ITEM_FEE_INFO)) => Self::FeeInfo.swipe_left(),
(Self::SummaryMenu, FlowMsg::Choice(MENU_ITEM_EXTRA_INFO)) => {
Self::ExtraInfo.swipe_left()
}
(Self::MainMenu, FlowMsg::Choice(MENU_ITEM_ADDRESS_INFO)) => {
Self::AddressInfo.swipe_left()
}
@ -221,7 +228,7 @@ pub fn new_confirm_output(
br_code: u16,
confirm_amount: Option<ConfirmValue>,
confirm_address: Option<ConfirmValue>,
address_title: TString<'static>,
confirm_extra: Option<ConfirmValue>,
summary_items_params: Option<ShowInfoParams>,
fee_items_params: ShowInfoParams,
summary_br_name: Option<TString<'static>>,
@ -236,8 +243,8 @@ pub fn new_confirm_output(
// MainMenu
let mut main_menu = VerticalMenu::empty();
let mut main_menu_items = Vec::<usize, 3>::new();
if confirm_address.is_some() {
main_menu = main_menu.item(theme::ICON_CHEVRON_RIGHT, address_title);
if let Some(ref confirm_address) = confirm_address {
main_menu = main_menu.item(theme::ICON_CHEVRON_RIGHT, confirm_address.title());
unwrap!(main_menu_items.push(MENU_ITEM_ADDRESS_INFO));
}
if account.is_some() && account_path.is_some() {
@ -309,7 +316,11 @@ pub fn new_confirm_output(
// SummaryMenu
let mut summary_menu = VerticalMenu::empty();
let mut summary_menu_items = Vec::<usize, 2>::new();
let mut summary_menu_items = Vec::<usize, 3>::new();
if let Some(ref confirm_extra) = confirm_extra {
summary_menu = summary_menu.item(theme::ICON_CHEVRON_RIGHT, confirm_extra.title());
unwrap!(summary_menu_items.push(MENU_ITEM_EXTRA_INFO));
}
if has_fee_info {
summary_menu = summary_menu.item(
theme::ICON_CHEVRON_RIGHT,
@ -364,7 +375,8 @@ pub fn new_confirm_output(
.map(|_| Some(FlowMsg::Cancelled)),
)?;
}
flow.with_page(&ConfirmOutputWithSummary::Summary, content_summary)?
flow = flow
.with_page(&ConfirmOutputWithSummary::Summary, content_summary)?
.with_page(&ConfirmOutputWithSummary::SummaryMenu, content_summary_menu)?
.with_page(
&ConfirmOutputWithSummary::SummaryMenuCancel,
@ -374,7 +386,12 @@ pub fn new_confirm_output(
.with_page(&ConfirmOutputWithSummary::Hold, content_hold)?
.with_page(&ConfirmOutputWithSummary::HoldMenu, content_hold_menu)?
.with_page(&ConfirmOutputWithSummary::HoldMenuCancel, get_cancel_page())?
.with_page(&ConfirmOutputWithSummary::AccountInfo, account_content)?
.with_page(&ConfirmOutputWithSummary::AccountInfo, account_content)?;
if let Some(confirm_extra) = confirm_extra {
let extra_content = confirm_extra.into_layout()?;
flow = flow.with_page(&ConfirmOutputWithSummary::ExtraInfo, extra_content)?
}
flow
} else {
SwipeFlow::new(&ConfirmOutput::Address)?
.with_page(&ConfirmOutput::Address, main_content)?

View File

@ -300,6 +300,10 @@ impl ConfirmValue {
self.page_counter,
)
}
pub fn title(&self) -> TString<'static> {
self.title
}
}
pub struct ShowInfoParams {

View File

@ -519,8 +519,8 @@ impl FirmwareUI for UIDelizia {
account_path: Option<TString<'static>>,
br_code: u16,
br_name: TString<'static>,
address: Option<Obj>,
address_title: Option<TString<'static>>,
address_item: Option<(TString<'static>, Obj)>,
extra_item: Option<(TString<'static>, Obj)>,
summary_items: Option<Obj>,
fee_items: Option<Obj>,
summary_title: Option<TString<'static>>,
@ -528,8 +528,6 @@ impl FirmwareUI for UIDelizia {
summary_br_name: Option<TString<'static>>,
cancel_text: Option<TString<'static>>,
) -> Result<impl LayoutMaybeTrace, Error> {
let address_title = address_title.unwrap_or(TR::words__address.into());
let confirm_main =
ConfirmValue::new(title.unwrap_or(TString::empty()), message, description)
.with_subtitle(subtitle)
@ -549,7 +547,7 @@ impl FirmwareUI for UIDelizia {
.with_swipe_down()
});
let confirm_value = address.map(|address| {
let confirm_address = address_item.map(|(address_title, address)| {
ConfirmValue::new(address_title, address, None)
.with_cancel_button()
.with_chunkify(true)
@ -557,6 +555,14 @@ impl FirmwareUI for UIDelizia {
.with_swipe_right()
});
let confirm_extra = extra_item.map(|(extra_title, extra)| {
ConfirmValue::new(extra_title, extra, None)
.with_cancel_button()
.with_chunkify(true)
.with_text_mono(true)
.with_swipe_right()
});
let mut fee_items_params =
ShowInfoParams::new(TR::confirm_total__title_fee.into()).with_cancel_button();
if fee_items.is_some() {
@ -589,8 +595,8 @@ impl FirmwareUI for UIDelizia {
br_name,
br_code,
confirm_amount,
confirm_value,
address_title,
confirm_address,
confirm_extra,
summary_items_params,
fee_items_params,
summary_br_name,

View File

@ -169,8 +169,8 @@ pub trait FirmwareUI {
account_path: Option<TString<'static>>,
br_code: u16,
br_name: TString<'static>,
address: Option<Obj>, // TODO: replace Obj
address_title: Option<TString<'static>>,
address_item: Option<(TString<'static>, Obj)>,
extra_item: Option<(TString<'static>, Obj)>,
summary_items: Option<Obj>, // TODO: replace Obj
fee_items: Option<Obj>, // TODO: replace Obj
summary_title: Option<TString<'static>>,

View File

@ -319,8 +319,8 @@ def flow_confirm_output(
account_path: str | None,
br_code: ButtonRequestType,
br_name: str,
address: str | None,
address_title: str | None,
address_item: (str, str) | None,
extra_item: (str, str) | None,
summary_items: Iterable[tuple[str, str]] | None = None,
fee_items: Iterable[tuple[str, str]] | None = None,
summary_title: str | None = None,

View File

@ -49,10 +49,6 @@ def _get_address_reference_props(
)
def _blockhash_item(blockhash: bytes) -> tuple[str, str]:
return (f"{TR.words__blockhash}:", base58.encode(blockhash))
async def confirm_instruction(
instruction: Instruction,
instructions_count: int,
@ -352,7 +348,7 @@ async def confirm_custom_transaction(
fee_title=f"{TR.solana__expected_fee}:",
items=(
(f"{TR.words__account}:", _format_path(signer_path)),
_blockhash_item(blockhash),
(f"{TR.words__blockhash}:", base58.encode(blockhash)),
),
)
@ -426,7 +422,7 @@ async def confirm_stake_transaction(
),
fee_item=_fee_summary(fee),
fee_details=_fee_details(fee),
blockhash_item=_blockhash_item(blockhash),
blockhash_item=(TR.words__blockhash, base58.encode(blockhash)),
br_name="confirm_stake_transaction",
)
@ -452,7 +448,7 @@ async def confirm_unstake_transaction(
amount_item=("", ""),
fee_item=_fee_summary(fee),
fee_details=_fee_details(fee),
blockhash_item=_blockhash_item(blockhash),
blockhash_item=(TR.words__blockhash, base58.encode(blockhash)),
br_name="confirm_unstake_transaction",
)
@ -481,7 +477,7 @@ async def confirm_claim_transaction(
),
fee_item=_fee_summary(fee),
fee_details=_fee_details(fee),
blockhash_item=_blockhash_item(blockhash),
blockhash_item=(TR.words__blockhash, base58.encode(blockhash)),
br_name="confirm_claim_transaction",
)
@ -497,6 +493,6 @@ async def confirm_transaction(
fee_title=fee_title,
items=(
(f"{TR.words__account}:", _format_path(signer_path)),
_blockhash_item(blockhash),
(f"{TR.words__blockhash}:", base58.encode(blockhash)),
),
)

View File

@ -398,8 +398,8 @@ async def confirm_output(
text_mono=True,
account=source_account,
account_path=source_account_path,
address=None,
address_title=None,
address_item=None,
extra_item=None,
br_code=br_code,
br_name="confirm_output",
summary_items=None,
@ -778,8 +778,8 @@ if not utils.BITCOIN_ONLY:
text_mono=True,
account=account,
account_path=account_path,
address=None,
address_title=None,
address_item=None,
extra_item=None,
br_code=ButtonRequestType.SignTx,
br_name="confirm_output",
summary_items=(
@ -830,8 +830,8 @@ if not utils.BITCOIN_ONLY:
account_path=account_path,
br_code=br_code,
br_name=br_name,
address=address,
address_title=address_title,
address_item=(address_title, address),
extra_item=None,
summary_items=summary_items,
fee_items=info_items,
summary_title=verb,
@ -879,8 +879,6 @@ if not utils.BITCOIN_ONLY:
blockhash_item: tuple[str, str],
br_name: str,
) -> None:
(address_title, address) = stake_item
summary_items = (amount_item, fee_item)
description = message
if vote_account:
description = f"{message}\n{TR.solana__stake_provider}:"
@ -898,11 +896,11 @@ if not utils.BITCOIN_ONLY:
account_path=account_path,
br_code=ButtonRequestType.SignTx,
br_name=br_name,
address=address,
address_title=address_title,
address_item=stake_item,
extra_item=blockhash_item,
fee_items=fee_details,
summary_title=title,
summary_items=summary_items,
summary_items=(amount_item, fee_item),
summary_br_name="confirm_solana_staking_tx_total",
summary_br_code=ButtonRequestType.SignTx,
cancel_text=TR.buttons__cancel,