diff --git a/core/.changelog.d/noissue.fixed b/core/.changelog.d/noissue.fixed new file mode 100644 index 00000000000..26a97edf5ba --- /dev/null +++ b/core/.changelog.d/noissue.fixed @@ -0,0 +1 @@ +[T3T1] Improved ETH staking flow. diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index 831b1f6ce7a..9b1224e2b6f 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -326,6 +326,7 @@ static void _librust_qstrs(void) { MP_QSTR_max_feerate; MP_QSTR_max_len; MP_QSTR_max_rounds; + MP_QSTR_message; MP_QSTR_min_count; MP_QSTR_misc__decrypt_value; MP_QSTR_misc__encrypt_value; diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_output.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_output.rs index 6724f639033..645562428d9 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_output.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_output.rs @@ -31,7 +31,8 @@ use super::{ const MENU_ITEM_CANCEL: usize = 0; const MENU_ITEM_FEE_INFO: usize = 1; -const MENU_ITEM_ACCOUNT_INFO: usize = 2; +const MENU_ITEM_ADDRESS_INFO: usize = 2; +const MENU_ITEM_ACCOUNT_INFO: usize = 3; #[derive(Copy, Clone, PartialEq, Eq)] pub enum ConfirmOutput { @@ -117,9 +118,10 @@ impl FlowState for ConfirmOutputWithAmount { #[derive(Copy, Clone, PartialEq, Eq)] pub enum ConfirmOutputWithSummary { - Address, - AddressMenu, - AddressMenuCancel, + Main, + MainMenu, + MainMenuCancel, + AddressInfo, Summary, SummaryMenu, SummaryMenuCancel, @@ -138,12 +140,13 @@ impl FlowState for ConfirmOutputWithSummary { fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange { match (self, direction) { - (Self::Address, SwipeDirection::Left) => Self::AddressMenu.swipe(direction), - (Self::Address, SwipeDirection::Up) => Self::Summary.swipe(direction), - (Self::AccountInfo, SwipeDirection::Right) => Self::AddressMenu.swipe(direction), + (Self::Main, SwipeDirection::Left) => Self::MainMenu.swipe(direction), + (Self::Main, SwipeDirection::Up) => Self::Summary.swipe(direction), + (Self::AddressInfo, SwipeDirection::Right) => Self::MainMenu.swipe(direction), + (Self::AccountInfo, SwipeDirection::Right) => Self::MainMenu.swipe(direction), (Self::Summary, SwipeDirection::Left) => Self::SummaryMenu.swipe(direction), (Self::Summary, SwipeDirection::Up) => Self::Hold.swipe(direction), - (Self::Summary, SwipeDirection::Down) => Self::Address.swipe(direction), + (Self::Summary, SwipeDirection::Down) => Self::Main.swipe(direction), (Self::FeeInfo, SwipeDirection::Right) => Self::SummaryMenu.swipe(direction), (Self::Hold, SwipeDirection::Left) => Self::HoldMenu.swipe(direction), (Self::Hold, SwipeDirection::Down) => Self::Summary.swipe(direction), @@ -153,11 +156,12 @@ impl FlowState for ConfirmOutputWithSummary { fn handle_event(&'static self, msg: FlowMsg) -> StateChange { match (self, msg) { - (Self::Address, FlowMsg::Info) => Self::AddressMenu.transit(), - (Self::AddressMenu, FlowMsg::Choice(MENU_ITEM_CANCEL)) => { - Self::AddressMenuCancel.swipe_left() + (Self::Main, FlowMsg::Info) => Self::MainMenu.transit(), + (Self::MainMenu, FlowMsg::Choice(MENU_ITEM_CANCEL)) => { + Self::MainMenuCancel.swipe_left() } - (Self::AddressMenuCancel, FlowMsg::Cancelled) => Self::AddressMenu.swipe_right(), + (Self::MainMenuCancel, FlowMsg::Cancelled) => Self::MainMenu.swipe_right(), + (Self::AddressInfo, FlowMsg::Info) => Self::MainMenu.transit(), (Self::Summary, FlowMsg::Info) => Self::SummaryMenu.transit(), (Self::SummaryMenu, FlowMsg::Choice(MENU_ITEM_CANCEL)) => { Self::SummaryMenuCancel.swipe_left() @@ -169,18 +173,21 @@ impl FlowState for ConfirmOutputWithSummary { } (Self::HoldMenuCancel, FlowMsg::Cancelled) => Self::HoldMenu.swipe_right(), (Self::SummaryMenu, FlowMsg::Choice(MENU_ITEM_FEE_INFO)) => Self::FeeInfo.swipe_left(), - (Self::AddressMenu, FlowMsg::Choice(MENU_ITEM_ACCOUNT_INFO)) => { + (Self::MainMenu, FlowMsg::Choice(MENU_ITEM_ADDRESS_INFO)) => { + Self::AddressInfo.swipe_left() + } + (Self::MainMenu, FlowMsg::Choice(MENU_ITEM_ACCOUNT_INFO)) => { Self::AccountInfo.swipe_left() } - (Self::AddressMenu, FlowMsg::Cancelled) => Self::Address.swipe_right(), + (Self::MainMenu, FlowMsg::Cancelled) => Self::Main.swipe_right(), (Self::SummaryMenu, FlowMsg::Cancelled) => Self::Summary.swipe_right(), (Self::FeeInfo, FlowMsg::Cancelled) => Self::SummaryMenu.swipe_right(), (Self::HoldMenu, FlowMsg::Cancelled) => Self::Hold.swipe_right(), ( - Self::AddressMenuCancel | Self::SummaryMenuCancel | Self::HoldMenuCancel, + Self::MainMenuCancel | Self::SummaryMenuCancel | Self::HoldMenuCancel, FlowMsg::Confirmed, ) => self.return_msg(FlowMsg::Cancelled), - (Self::Address, FlowMsg::Cancelled) => Self::AddressMenu.transit(), + (Self::Main, FlowMsg::Cancelled) => Self::MainMenu.transit(), (Self::Summary, FlowMsg::Cancelled) => Self::SummaryMenu.transit(), (Self::Hold, FlowMsg::Cancelled) => Self::HoldMenu.transit(), (Self::Hold, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed), @@ -213,6 +220,7 @@ pub extern "C" fn new_confirm_output(n_args: usize, args: *const Obj, kwargs: *m fn new_confirm_output_obj(_args: &[Obj], kwargs: &Map) -> Result { let title: Option = kwargs.get(Qstr::MP_QSTR_title)?.try_into_option()?; + let subtitle: Option = kwargs.get(Qstr::MP_QSTR_subtitle)?.try_into_option()?; let account: Option = kwargs.get(Qstr::MP_QSTR_account)?.try_into_option()?; let account_path: Option = @@ -221,12 +229,16 @@ fn new_confirm_output_obj(_args: &[Obj], kwargs: &Map) -> Result = kwargs.get(Qstr::MP_QSTR_amount)?.try_into_option()?; let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; let text_mono: bool = kwargs.get_or(Qstr::MP_QSTR_text_mono, true)?; + let address: Option = kwargs.get(Qstr::MP_QSTR_address)?.try_into_option()?; + let address_title: Option = + kwargs.get(Qstr::MP_QSTR_address_title)?.try_into_option()?; + let summary_items: Obj = kwargs.get(Qstr::MP_QSTR_summary_items)?; let fee_items: Obj = kwargs.get(Qstr::MP_QSTR_fee_items)?; @@ -241,9 +253,9 @@ fn new_confirm_output_obj(_args: &[Obj], kwargs: &Map) -> Result = kwargs.get(Qstr::MP_QSTR_cancel_text)?.try_into_option()?; - // Address - let content_address = ConfirmBlobParams::new(TR::words__address.into(), address, None) - .with_subtitle(title) + // Main + let main_content = ConfirmBlobParams::new(title.unwrap_or(TString::empty()), message, None) + .with_subtitle(subtitle) .with_menu_button() .with_footer(TR::instructions__swipe_up.into(), None) .with_chunkify(chunkify) @@ -251,55 +263,59 @@ fn new_confirm_output_obj(_args: &[Obj], kwargs: &Map) -> Result::new(); + // MainMenu + let mut main_menu = VerticalMenu::empty(); + let mut main_menu_items = Vec::::new(); + if address.is_some() { + main_menu = main_menu.item( + theme::ICON_CHEVRON_RIGHT, + address_title.unwrap_or(TR::words__address.into()), + ); + unwrap!(main_menu_items.push(MENU_ITEM_ADDRESS_INFO)); + } if account.is_some() && account_path.is_some() { - address_menu = address_menu.item( + main_menu = main_menu.item( theme::ICON_CHEVRON_RIGHT, TR::address_details__account_info.into(), ); - unwrap!(address_menu_items.push(MENU_ITEM_ACCOUNT_INFO)); + unwrap!(main_menu_items.push(MENU_ITEM_ACCOUNT_INFO)); } - address_menu = address_menu.danger( + main_menu = main_menu.danger( theme::ICON_CANCEL, cancel_text.unwrap_or(TR::send__cancel_sign.into()), ); - unwrap!(address_menu_items.push(MENU_ITEM_CANCEL)); - let content_address_menu = Frame::left_aligned(TString::empty(), address_menu) + unwrap!(main_menu_items.push(MENU_ITEM_CANCEL)); + let content_main_menu = Frame::left_aligned(TString::empty(), main_menu) .with_cancel_button() .with_swipe(SwipeDirection::Right, SwipeSettings::immediate()) .map(move |msg| match msg { FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => { - let selected_item = address_menu_items[i]; + let selected_item = main_menu_items[i]; Some(FlowMsg::Choice(selected_item)) } FrameMsg::Button(_) => Some(FlowMsg::Cancelled), }); // AccountInfo - let ad = AddressDetails::new(TR::send__send_from.into(), account, account_path)?; - let content_account = ad.map(|_| Some(FlowMsg::Cancelled)); + let ac = AddressDetails::new(TR::send__send_from.into(), account, account_path)?; + let account_content = ac.map(|_| Some(FlowMsg::Cancelled)); let res = if amount.is_some() { - let content_amount = ConfirmBlobParams::new( - TR::words__amount.into(), - amount.unwrap_or(Obj::const_none()), - None, - ) - .with_subtitle(title) - .with_menu_button() - .with_footer(TR::instructions__swipe_up.into(), None) - .with_text_mono(text_mono) - .with_swipe_down() - .into_layout()? - .one_button_request(ButtonRequest::from_num(br_code, br_name)); + let content_amount = + ConfirmBlobParams::new(TR::words__amount.into(), amount.unwrap(), None) + .with_subtitle(subtitle) + .with_menu_button() + .with_footer(TR::instructions__swipe_up.into(), None) + .with_text_mono(text_mono) + .with_swipe_down() + .into_layout()? + .one_button_request(ButtonRequest::from_num(br_code, br_name)); SwipeFlow::new(&ConfirmOutputWithAmount::Address)? - .with_page(&ConfirmOutputWithAmount::Address, content_address)? + .with_page(&ConfirmOutputWithAmount::Address, main_content)? .with_page(&ConfirmOutputWithAmount::Amount, content_amount)? - .with_page(&ConfirmOutputWithAmount::Menu, content_address_menu)? - .with_page(&ConfirmOutputWithAmount::AccountInfo, content_account)? + .with_page(&ConfirmOutputWithAmount::Menu, content_main_menu)? + .with_page(&ConfirmOutputWithAmount::AccountInfo, account_content)? .with_page(&ConfirmOutputWithAmount::CancelTap, get_cancel_page())? } else if summary_items != Obj::const_none() { // Summary @@ -389,14 +405,31 @@ fn new_confirm_output_obj(_args: &[Obj], kwargs: &Map) -> Result Some(FlowMsg::Cancelled), }); - SwipeFlow::new(&ConfirmOutputWithSummary::Address)? - .with_page(&ConfirmOutputWithSummary::Address, content_address)? - .with_page(&ConfirmOutputWithSummary::AddressMenu, content_address_menu)? - .with_page( - &ConfirmOutputWithSummary::AddressMenuCancel, - get_cancel_page(), - )? - .with_page(&ConfirmOutputWithSummary::Summary, content_summary)? + let mut flow = SwipeFlow::new(&ConfirmOutputWithSummary::Main)? + .with_page(&ConfirmOutputWithSummary::Main, main_content)? + .with_page(&ConfirmOutputWithSummary::MainMenu, content_main_menu)? + .with_page(&ConfirmOutputWithSummary::MainMenuCancel, get_cancel_page())?; + if address.is_some() { + let address_content = ConfirmBlobParams::new( + address_title.unwrap_or(TR::words__address.into()), + address.unwrap(), + None, + ) + .with_cancel_button() + .with_chunkify(true) + .with_text_mono(true) + .into_layout()?; + flow = flow.with_page(&ConfirmOutputWithSummary::AddressInfo, address_content)?; + } else { + // dummy page - this will never be shown since there is no menu item pointing to + // it, but the page has to exist in the flow + flow = flow.with_page( + &ConfirmOutputWithSummary::AddressInfo, + Frame::left_aligned(TString::empty(), VerticalMenu::empty()) + .map(|_| Some(FlowMsg::Cancelled)), + )?; + } + flow.with_page(&ConfirmOutputWithSummary::Summary, content_summary)? .with_page(&ConfirmOutputWithSummary::SummaryMenu, content_summary_menu)? .with_page( &ConfirmOutputWithSummary::SummaryMenuCancel, @@ -406,12 +439,12 @@ fn new_confirm_output_obj(_args: &[Obj], kwargs: &Map) -> Result>, extra: Option>, menu_button: bool, + cancel_button: bool, chunkify: bool, text_mono: bool, swipe_down: bool, @@ -50,6 +51,7 @@ impl ConfirmBlobParams { description, extra: None, menu_button: false, + cancel_button: false, chunkify: false, text_mono: true, swipe_down: false, @@ -71,6 +73,11 @@ impl ConfirmBlobParams { self } + pub const fn with_cancel_button(mut self) -> Self { + self.cancel_button = true; + self + } + pub const fn with_swipe_down(mut self) -> Self { self.swipe_down = true; self @@ -128,6 +135,9 @@ impl ConfirmBlobParams { if self.menu_button { frame = frame.with_menu_button(); } + if self.cancel_button { + frame = frame.with_cancel_button(); + } if let Some(instruction) = self.footer_instruction { frame = frame.with_footer(instruction, self.footer_description); frame = frame.with_swipe(SwipeDirection::Left, SwipeSettings::default()); diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index 3292bec53a3..1fd6bda46c4 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -1772,13 +1772,17 @@ pub static mp_module_trezorui2: Module = obj_module! { /// def flow_confirm_output( /// *, /// title: str | None, - /// address: str, + /// subtitle: str | None, + /// message: str, /// amount: str | None, /// chunkify: bool, + /// text_mono: bool, /// account: str | None, /// account_path: str | None, /// br_code: ButtonRequestType, /// br_name: str, + /// address: str | None, + /// address_title: str | None, /// summary_items: Iterable[tuple[str, str]] | None = None, /// fee_items: Iterable[tuple[str, str]] | None = None, /// summary_title: str | None = None, diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index 8f5b25ba450..511c2e2cd48 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -580,13 +580,17 @@ def flow_warning_hi_prio( def flow_confirm_output( *, title: str | None, - address: str, + subtitle: str | None, + message: str, amount: str | None, chunkify: bool, + text_mono: bool, account: str | None, account_path: str | None, br_code: ButtonRequestType, br_name: str, + address: str | None, + address_title: str | None, summary_items: Iterable[tuple[str, str]] | None = None, fee_items: Iterable[tuple[str, str]] | None = None, summary_title: str | None = None, diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index 182b70b4a17..3a8385e2f07 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -649,12 +649,16 @@ async def confirm_output( await raise_if_not_confirmed( RustLayout( trezorui2.flow_confirm_output( - title=title, - address=address, + title=TR.words__address, + subtitle=title, + message=address, amount=amount, chunkify=chunkify, + text_mono=True, account=source_account, account_path=source_account_path, + address=None, + address_title=None, br_code=br_code, br_name="confirm_output", summary_items=None, @@ -1032,12 +1036,16 @@ async def confirm_ethereum_tx( await raise_if_not_confirmed( RustLayout( trezorui2.flow_confirm_output( - title=TR.words__recipient, - address=recipient, + title=TR.words__address, + subtitle=TR.words__recipient, + message=recipient, amount=None, chunkify=chunkify, + text_mono=True, account=None, account_path=None, + address=None, + address_title=None, br_code=ButtonRequestType.Other, br_name="confirm_output", summary_items=( @@ -1066,36 +1074,36 @@ async def confirm_ethereum_staking_tx( br_name: str = "confirm_ethereum_staking_tx", br_code: ButtonRequestType = ButtonRequestType.SignTx, ) -> None: - - # intro - await confirm_value( - title, - intro_question, - "", - br_name, - br_code, - verb=verb, - value_text_mono=False, - info_items=(("", address),), - info_title=address_title, - chunkify_info=chunkify, - ) - - # confirmation if verb == TR.ethereum__staking_claim: - items = ((TR.send__maximum_fee, maximum_fee),) + summary_items = ((TR.send__maximum_fee, maximum_fee),) else: - items = ( + summary_items = ( (TR.words__amount, total_amount), (TR.send__maximum_fee, maximum_fee), ) - await _confirm_summary( - items=items, - title=title, - info_title=TR.confirm_total__title_fee, - info_items=info_items, - br_name=br_name, - br_code=br_code, + await raise_if_not_confirmed( + RustLayout( + trezorui2.flow_confirm_output( + title=verb, + subtitle=None, + message=intro_question, + amount=None, + chunkify=False, + text_mono=False, + account=None, + account_path=None, + br_code=br_code, + br_name=br_name, + address=address, + address_title=address_title, + summary_items=summary_items, + fee_items=info_items, + summary_title=verb, + summary_br_name="confirm_total", + summary_br_code=ButtonRequestType.SignTx, + cancel_text=TR.buttons__cancel, # cancel staking + ) + ) ) def confirm_solana_tx( diff --git a/tests/device_tests/ethereum/test_signtx.py b/tests/device_tests/ethereum/test_signtx.py index 196d6b5bfa0..6ae85d5dd1d 100644 --- a/tests/device_tests/ethereum/test_signtx.py +++ b/tests/device_tests/ethereum/test_signtx.py @@ -459,7 +459,6 @@ def _sign_tx_call(): _sign_tx_call() -@pytest.mark.skip_t3t1(reason="Not yet implemented in new UI") @pytest.mark.skip_t1b1("T1 does not support Everstake") @parametrize_using_common_fixtures("ethereum/sign_tx_staking.json") @pytest.mark.parametrize("chunkify", (True, False)) diff --git a/tests/input_flows_helpers.py b/tests/input_flows_helpers.py index 7abe27fcfa0..1cf2266760a 100644 --- a/tests/input_flows_helpers.py +++ b/tests/input_flows_helpers.py @@ -490,7 +490,9 @@ def confirm_tx_staking( self, info: bool = False, ) -> BRGeneratorType: - yield + br = yield + assert br.code == B.SignTx + assert br.name == "confirm_ethereum_staking_tx" TR.assert_equals_multiple( self.debug.wait_layout().title(), [ @@ -507,7 +509,7 @@ def confirm_tx_staking( "ethereum__staking_claim_intro", ], ) - if self.client.model in (models.T2T1, models.T3T1): + if self.client.model in (models.T2T1,): # confirm intro if info: self.debug.click(buttons.CORNER_BUTTON, wait=True) @@ -523,7 +525,7 @@ def confirm_tx_staking( yield # confirm summary - if info and self.client.model != models.T3T1: + if info: self.debug.press_info(wait=True) TR.assert_in( self.debug.wait_layout().text_content(), "ethereum__gas_limit" @@ -536,7 +538,49 @@ def confirm_tx_staking( yield self.debug.press_yes() - else: + elif self.client.model in (models.T3T1,): + # confirm intro + if info: + self.debug.click(buttons.CORNER_BUTTON, wait=True) + self.debug.synchronize_at("VerticalMenu") + self.debug.click(buttons.VERTICAL_MENU[0], wait=True) + TR.assert_equals_multiple( + self.debug.wait_layout().title(), + [ + "ethereum__staking_stake_address", + "ethereum__staking_claim_address", + ], + ) + self.debug.click(buttons.CORNER_BUTTON, wait=True) + self.debug.click(buttons.CORNER_BUTTON, wait=True) + + self.debug.swipe_up() + br = yield + assert br.code == B.SignTx + assert br.name == "confirm_total" + + # confirm summary + if info: + self.debug.click(buttons.CORNER_BUTTON, wait=True) + self.debug.synchronize_at("VerticalMenu") + self.debug.click(buttons.VERTICAL_MENU[0], wait=True) + TR.assert_in( + self.debug.wait_layout().text_content(), "ethereum__gas_limit" + ) + TR.assert_in( + self.debug.wait_layout().text_content(), "ethereum__gas_price" + ) + self.debug.click(buttons.CORNER_BUTTON, wait=True) + self.debug.click(buttons.CORNER_BUTTON, wait=True) + self.debug.swipe_up() + # br = yield # FIXME: no BR on sign transaction + + self.debug.press_yes() + + elif self.client.model in ( + models.T2B1, + models.T3B1, + ): # confirm intro if info: self.debug.press_right(wait=True) @@ -567,3 +611,5 @@ def confirm_tx_staking( yield self.debug.press_yes() + else: + raise ValueError("Unknown model!") diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index b4d5f401d06..d0b2cfa777b 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -16449,6 +16449,18 @@ "T3T1_cs_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "6ce1d66af3f9e857b66dd057a60f5f5bcba6e7a0a241a08855d109a2fc440ac7", "T3T1_cs_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "6ce1d66af3f9e857b66dd057a60f5f5bcba6e7a0a241a08855d109a2fc440ac7", "T3T1_cs_ethereum-test_signtx.py::test_signtx_fee_info": "6a43a117d79ced98980f2c3d63b8cf7c580326f8df601be465627f1131a8606d", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[False-claim_holesky]": "de5a3f76a0c9bc879f9046285a050a36738d369ce2fc01e13733838795fe574b", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[False-claim_mainnet]": "534d5a30dda303900259c190868d8143af063282e35e685e71788e92d0937e38", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[False-stake_holesky]": "d00a990e3511885aeea98d5ff004da4b59614faea1bdfb3efab445f431c282b4", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[False-stake_main]": "4a36106048823d8f95f2ed06d988ae2c5d61ca2132f5f3b198eda08671d399ca", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[False-unstake_holesky]": "c0c90a36e3be72160ef50ed2355fa022fdcb2735c381f22512ebb5b4d9290a2f", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[False-unstake_main]": "35f51f28bc80f3517e6ce4fea2a4763833a828aa0f970a4766ee619f48e332e8", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[True-claim_holesky]": "de5a3f76a0c9bc879f9046285a050a36738d369ce2fc01e13733838795fe574b", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[True-claim_mainnet]": "534d5a30dda303900259c190868d8143af063282e35e685e71788e92d0937e38", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[True-stake_holesky]": "d00a990e3511885aeea98d5ff004da4b59614faea1bdfb3efab445f431c282b4", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[True-stake_main]": "4a36106048823d8f95f2ed06d988ae2c5d61ca2132f5f3b198eda08671d399ca", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[True-unstake_holesky]": "c0c90a36e3be72160ef50ed2355fa022fdcb2735c381f22512ebb5b4d9290a2f", +"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking[True-unstake_main]": "35f51f28bc80f3517e6ce4fea2a4763833a828aa0f970a4766ee619f48e332e8", "T3T1_cs_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[claim_bad_inputs_1]": "db145237dd6797d9dd5204b63976d890465fa96aa121b5a84032f6d62955b6d1", "T3T1_cs_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_1]": "db145237dd6797d9dd5204b63976d890465fa96aa121b5a84032f6d62955b6d1", "T3T1_cs_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_2]": "db145237dd6797d9dd5204b63976d890465fa96aa121b5a84032f6d62955b6d1", @@ -17791,6 +17803,18 @@ "T3T1_de_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "fe02b97c28cec0b8f6c03cd93fe6219b3b732390bb98badf5a6f35a82cb997ef", "T3T1_de_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "fe02b97c28cec0b8f6c03cd93fe6219b3b732390bb98badf5a6f35a82cb997ef", "T3T1_de_ethereum-test_signtx.py::test_signtx_fee_info": "17a4d8511d786f95410c1cfe55ab6df1c54edd581637839380d504a9a943192e", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[False-claim_holesky]": "f27b041783cc79a22c11ed668a003c906f1065aa76d8f16b30472d04409a154a", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[False-claim_mainnet]": "c33ae42431c166ca0cece0f9e22caacd96dde3afa5fef705aebafc649e92ce5b", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[False-stake_holesky]": "f69d79f138e87dcde788d6fe50362e14c4954431f940dc9ac958c4caeceead93", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[False-stake_main]": "d8a29f667f4e48fffe17f13cd698b19b855ce97c60d1e22628136fe08d55c44f", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[False-unstake_holesky]": "9e70a5e0158171f5f74fdcf801684dff0aea6d0f97076046b0f18af209d3325d", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[False-unstake_main]": "c6a47a4a4899ae0cb796692e3d0570440daceab947a0442ea2f62fa5e5a6fa74", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[True-claim_holesky]": "f27b041783cc79a22c11ed668a003c906f1065aa76d8f16b30472d04409a154a", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[True-claim_mainnet]": "c33ae42431c166ca0cece0f9e22caacd96dde3afa5fef705aebafc649e92ce5b", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[True-stake_holesky]": "f69d79f138e87dcde788d6fe50362e14c4954431f940dc9ac958c4caeceead93", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[True-stake_main]": "d8a29f667f4e48fffe17f13cd698b19b855ce97c60d1e22628136fe08d55c44f", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[True-unstake_holesky]": "9e70a5e0158171f5f74fdcf801684dff0aea6d0f97076046b0f18af209d3325d", +"T3T1_de_ethereum-test_signtx.py::test_signtx_staking[True-unstake_main]": "c6a47a4a4899ae0cb796692e3d0570440daceab947a0442ea2f62fa5e5a6fa74", "T3T1_de_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[claim_bad_inputs_1]": "adfe275fcc2caed0137079330cbc85aaccecf9e5fdc0404238db121212124edf", "T3T1_de_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_1]": "adfe275fcc2caed0137079330cbc85aaccecf9e5fdc0404238db121212124edf", "T3T1_de_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_2]": "adfe275fcc2caed0137079330cbc85aaccecf9e5fdc0404238db121212124edf", @@ -19133,6 +19157,18 @@ "T3T1_en_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "dd2790ac7fa5c240b051e85342d6368d0deac5a5cf8c7c8c4af1c09e3cf7182f", "T3T1_en_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "dd2790ac7fa5c240b051e85342d6368d0deac5a5cf8c7c8c4af1c09e3cf7182f", "T3T1_en_ethereum-test_signtx.py::test_signtx_fee_info": "b85b87c6946ad2074272ae7156fd6a5bfec4db17f12290c8b88d1bde1b551565", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[False-claim_holesky]": "c9ea54681f77d78b130719dec5be110ae0268f499466cc4656e96aa090c7f057", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[False-claim_mainnet]": "ef7330fe5b7ef7d9bef858d63bd78401ffacb39ee2b07134f74c25ca0ac057e2", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[False-stake_holesky]": "ee0a79a53b01e068bfee5ecc98597d4c6504b241ddff2eed22fadd0c4690913f", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[False-stake_main]": "28a8ede2baa9b729d626e128451452e335e3161dbc651867c9ed70a2192d4944", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[False-unstake_holesky]": "e5b6b99c47e6f5bf2d0dda1c317db61858ca42f5ab67ef268379770bc01ccc86", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[False-unstake_main]": "47ab2304a91cfbf820996c7514b5cc25d2f5fa317c294f6f7d60914836a1e25f", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[True-claim_holesky]": "c9ea54681f77d78b130719dec5be110ae0268f499466cc4656e96aa090c7f057", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[True-claim_mainnet]": "ef7330fe5b7ef7d9bef858d63bd78401ffacb39ee2b07134f74c25ca0ac057e2", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[True-stake_holesky]": "ee0a79a53b01e068bfee5ecc98597d4c6504b241ddff2eed22fadd0c4690913f", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[True-stake_main]": "28a8ede2baa9b729d626e128451452e335e3161dbc651867c9ed70a2192d4944", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[True-unstake_holesky]": "e5b6b99c47e6f5bf2d0dda1c317db61858ca42f5ab67ef268379770bc01ccc86", +"T3T1_en_ethereum-test_signtx.py::test_signtx_staking[True-unstake_main]": "47ab2304a91cfbf820996c7514b5cc25d2f5fa317c294f6f7d60914836a1e25f", "T3T1_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[claim_bad_inputs_1]": "886a329a63547ee0f07547685dfc1c8677587c3471fe1bcba81c6a9363659185", "T3T1_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_1]": "886a329a63547ee0f07547685dfc1c8677587c3471fe1bcba81c6a9363659185", "T3T1_en_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_2]": "886a329a63547ee0f07547685dfc1c8677587c3471fe1bcba81c6a9363659185", @@ -20475,6 +20511,18 @@ "T3T1_es_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "8f70757da8d2e04371c54ce284f59c7d1212eb3f4a9e035b1afa09dea6dda976", "T3T1_es_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "8f70757da8d2e04371c54ce284f59c7d1212eb3f4a9e035b1afa09dea6dda976", "T3T1_es_ethereum-test_signtx.py::test_signtx_fee_info": "2fb56492bae54739eb8af2259ea05fff90397dc4ca16ed0ab859566a97c5ec48", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[False-claim_holesky]": "82e98ccae78a78f96e67e7ba2d137036375d97c2e3644c4ecbc63941cbef8adc", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[False-claim_mainnet]": "69aa565c1f41969831a03a37075ff02a16333357a956aabdf0771af9be070fdd", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[False-stake_holesky]": "45430e948c1725caf0769bb44bc338d1ecb4258d8a88a85e9849131674be08d9", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[False-stake_main]": "601545c5963df3c325a2d72510d0ceb1e9c05cd753b802c9e44fb7735ca1bbe1", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[False-unstake_holesky]": "aaaacd4652ba80623098ea6606d5d284c3c8eb13938919339c25db8a120568de", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[False-unstake_main]": "7dfc04f0d6289822e0ae017dd517df67f2cedc26d7a7dfca0f952b1a7489896f", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[True-claim_holesky]": "82e98ccae78a78f96e67e7ba2d137036375d97c2e3644c4ecbc63941cbef8adc", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[True-claim_mainnet]": "69aa565c1f41969831a03a37075ff02a16333357a956aabdf0771af9be070fdd", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[True-stake_holesky]": "45430e948c1725caf0769bb44bc338d1ecb4258d8a88a85e9849131674be08d9", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[True-stake_main]": "601545c5963df3c325a2d72510d0ceb1e9c05cd753b802c9e44fb7735ca1bbe1", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[True-unstake_holesky]": "aaaacd4652ba80623098ea6606d5d284c3c8eb13938919339c25db8a120568de", +"T3T1_es_ethereum-test_signtx.py::test_signtx_staking[True-unstake_main]": "7dfc04f0d6289822e0ae017dd517df67f2cedc26d7a7dfca0f952b1a7489896f", "T3T1_es_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[claim_bad_inputs_1]": "9e2b64f79ece46f82e116b01abc0a03d1edf7bb2deb53a5216e6665f97ac2840", "T3T1_es_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_1]": "9e2b64f79ece46f82e116b01abc0a03d1edf7bb2deb53a5216e6665f97ac2840", "T3T1_es_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_2]": "9e2b64f79ece46f82e116b01abc0a03d1edf7bb2deb53a5216e6665f97ac2840", @@ -21817,6 +21865,18 @@ "T3T1_fr_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "19b948f557ebf500d80540e5b86a03f2be9dfa8e6a30686e4c3efa89689b78e1", "T3T1_fr_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "19b948f557ebf500d80540e5b86a03f2be9dfa8e6a30686e4c3efa89689b78e1", "T3T1_fr_ethereum-test_signtx.py::test_signtx_fee_info": "7f9aece317e149abd566d9028ad68752eb8226e2775d1655c3e60ef5a6980a63", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[False-claim_holesky]": "faabf370b82af0a2f632716077c32a46e1c307b2daf3ae812c1f6fc1e2077845", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[False-claim_mainnet]": "e84b2a35327660d4a054aea04edf89c0a949714a11dc9c2ce80765366ff7ff88", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[False-stake_holesky]": "1bac8774a8961b42e03dcc6a44140751b4788c94e4edd196269ca60c8d495f49", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[False-stake_main]": "a2fe6f20640f425dd26276d79135c9964efe426b9f2d054f4c0124b2468801e0", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[False-unstake_holesky]": "d551310247673206f3b372b9c669716ea8435fe6f23d900527d0086842a1a5d3", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[False-unstake_main]": "9f2d47695f80731856f5c7e7395dc48affc7f2a0a98c41af93a06c4d9d8af5da", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[True-claim_holesky]": "faabf370b82af0a2f632716077c32a46e1c307b2daf3ae812c1f6fc1e2077845", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[True-claim_mainnet]": "e84b2a35327660d4a054aea04edf89c0a949714a11dc9c2ce80765366ff7ff88", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[True-stake_holesky]": "1bac8774a8961b42e03dcc6a44140751b4788c94e4edd196269ca60c8d495f49", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[True-stake_main]": "a2fe6f20640f425dd26276d79135c9964efe426b9f2d054f4c0124b2468801e0", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[True-unstake_holesky]": "d551310247673206f3b372b9c669716ea8435fe6f23d900527d0086842a1a5d3", +"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking[True-unstake_main]": "9f2d47695f80731856f5c7e7395dc48affc7f2a0a98c41af93a06c4d9d8af5da", "T3T1_fr_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[claim_bad_inputs_1]": "84bc5711f80dff8ebb527d9204da271acc3ce29e17caacec880253ff12a418c2", "T3T1_fr_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_1]": "84bc5711f80dff8ebb527d9204da271acc3ce29e17caacec880253ff12a418c2", "T3T1_fr_ethereum-test_signtx.py::test_signtx_staking_bad_inputs[stake_bad_inputs_2]": "84bc5711f80dff8ebb527d9204da271acc3ce29e17caacec880253ff12a418c2",