2023-11-21 15:55:46 +00:00
|
|
|
import typing as t
|
|
|
|
|
2024-09-02 11:01:16 +00:00
|
|
|
from trezorlib import messages
|
|
|
|
from trezorlib.debuglink import LayoutType
|
2023-07-21 09:38:28 +00:00
|
|
|
from trezorlib.debuglink import TrezorClientDebugLink as Client
|
|
|
|
|
2024-05-27 22:19:01 +00:00
|
|
|
from . import buttons
|
2023-08-11 15:57:32 +00:00
|
|
|
from . import translations as TR
|
2023-11-21 12:51:59 +00:00
|
|
|
from .click_tests.common import go_next
|
2023-08-11 15:57:32 +00:00
|
|
|
from .common import BRGeneratorType, get_text_possible_pagination
|
2023-07-21 09:38:28 +00:00
|
|
|
|
|
|
|
B = messages.ButtonRequestType
|
|
|
|
|
|
|
|
|
|
|
|
class PinFlow:
|
|
|
|
def __init__(self, client: Client):
|
|
|
|
self.client = client
|
|
|
|
self.debug = self.client.debug
|
|
|
|
|
|
|
|
def setup_new_pin(
|
2023-11-21 15:55:46 +00:00
|
|
|
self,
|
|
|
|
pin: str,
|
|
|
|
second_different_pin: str | None = None,
|
|
|
|
what: str = "pin",
|
2023-07-21 09:38:28 +00:00
|
|
|
) -> BRGeneratorType:
|
2023-11-21 15:55:46 +00:00
|
|
|
assert (yield).name == "pin_device" # Enter PIN
|
2023-11-21 12:51:59 +00:00
|
|
|
assert "PinKeyboard" in self.debug.read_layout().all_components()
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.input(pin)
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR:
|
2023-11-21 15:55:46 +00:00
|
|
|
assert (yield).name == f"reenter_{what}" # Reenter PIN
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(
|
2023-11-21 15:55:46 +00:00
|
|
|
self.debug.read_layout().text_content(), f"{what}__reenter_to_confirm"
|
2023-08-11 15:57:32 +00:00
|
|
|
)
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
2023-11-21 15:55:46 +00:00
|
|
|
assert (yield).name == "pin_device" # Enter PIN again
|
2023-11-21 12:51:59 +00:00
|
|
|
assert "PinKeyboard" in self.debug.read_layout().all_components()
|
2023-07-21 09:38:28 +00:00
|
|
|
if second_different_pin is not None:
|
|
|
|
self.debug.input(second_different_pin)
|
|
|
|
else:
|
|
|
|
self.debug.input(pin)
|
|
|
|
|
|
|
|
|
|
|
|
class BackupFlow:
|
|
|
|
def __init__(self, client: Client):
|
|
|
|
self.client = client
|
|
|
|
self.debug = self.client.debug
|
|
|
|
|
|
|
|
def confirm_new_wallet(self) -> BRGeneratorType:
|
|
|
|
yield
|
2023-11-21 12:51:59 +00:00
|
|
|
TR.assert_in(self.debug.read_layout().text_content(), "reset__by_continuing")
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR:
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_right()
|
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
|
|
|
|
class RecoveryFlow:
|
|
|
|
def __init__(self, client: Client):
|
|
|
|
self.client = client
|
|
|
|
self.debug = self.client.debug
|
|
|
|
|
2023-08-11 15:57:32 +00:00
|
|
|
def _text_content(self) -> str:
|
2023-11-21 12:51:59 +00:00
|
|
|
layout = self.debug.read_layout()
|
2024-05-27 22:19:01 +00:00
|
|
|
return layout.title() + " " + layout.text_content()
|
2023-08-11 15:57:32 +00:00
|
|
|
|
2023-07-21 09:38:28 +00:00
|
|
|
def confirm_recovery(self) -> BRGeneratorType:
|
2023-11-21 15:55:46 +00:00
|
|
|
assert (yield).name == "recover_device"
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "reset__by_continuing")
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR:
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_right()
|
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def confirm_dry_run(self) -> BRGeneratorType:
|
2023-11-21 15:55:46 +00:00
|
|
|
assert (yield).name == "confirm_seedcheck"
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__check_dry_run")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def setup_slip39_recovery(self, num_words: int) -> BRGeneratorType:
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR:
|
2023-07-21 09:38:28 +00:00
|
|
|
yield from self.tr_recovery_homescreen()
|
|
|
|
yield from self.input_number_of_words(num_words)
|
|
|
|
yield from self.enter_any_share()
|
|
|
|
|
2024-04-23 10:26:46 +00:00
|
|
|
def setup_repeated_backup_recovery(self, num_words: int) -> BRGeneratorType:
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR:
|
2024-04-23 10:26:46 +00:00
|
|
|
yield from self.tr_recovery_homescreen()
|
|
|
|
yield from self.input_number_of_words(num_words)
|
|
|
|
yield from self.enter_your_backup()
|
|
|
|
|
2023-07-21 09:38:28 +00:00
|
|
|
def setup_bip39_recovery(self, num_words: int) -> BRGeneratorType:
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR:
|
2023-07-21 09:38:28 +00:00
|
|
|
yield from self.tr_recovery_homescreen()
|
|
|
|
yield from self.input_number_of_words(num_words)
|
|
|
|
yield from self.enter_your_backup()
|
|
|
|
|
|
|
|
def tr_recovery_homescreen(self) -> BRGeneratorType:
|
|
|
|
yield
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__num_of_words")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def enter_your_backup(self) -> BRGeneratorType:
|
2023-11-21 15:55:46 +00:00
|
|
|
assert (yield).name == "recovery"
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.debug.layout_type is LayoutType.Mercury:
|
2024-06-02 10:47:24 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__enter_each_word")
|
2024-05-27 22:19:01 +00:00
|
|
|
else:
|
|
|
|
TR.assert_in(self._text_content(), "recovery__enter_backup")
|
2023-08-11 15:57:32 +00:00
|
|
|
is_dry_run = any(
|
2023-11-21 12:51:59 +00:00
|
|
|
title in self.debug.read_layout().title().lower()
|
2023-08-11 15:57:32 +00:00
|
|
|
for title in TR.translate("recovery__title_dry_run", lower=True)
|
|
|
|
)
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR and not is_dry_run:
|
2023-07-21 09:38:28 +00:00
|
|
|
# Normal recovery has extra info (not dry run)
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_right()
|
|
|
|
self.debug.press_right()
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def enter_any_share(self) -> BRGeneratorType:
|
2023-11-21 15:55:46 +00:00
|
|
|
assert (yield).name == "recovery"
|
2024-05-27 22:19:01 +00:00
|
|
|
TR.assert_in_multiple(
|
|
|
|
self._text_content(),
|
2024-06-02 10:47:24 +00:00
|
|
|
["recovery__enter_any_share", "recovery__enter_each_word"],
|
2024-05-27 22:19:01 +00:00
|
|
|
)
|
2023-08-11 15:57:32 +00:00
|
|
|
is_dry_run = any(
|
2023-11-21 12:51:59 +00:00
|
|
|
title in self.debug.read_layout().title().lower()
|
2023-08-11 15:57:32 +00:00
|
|
|
for title in TR.translate("recovery__title_dry_run", lower=True)
|
|
|
|
)
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR and not is_dry_run:
|
2023-07-21 09:38:28 +00:00
|
|
|
# Normal recovery has extra info (not dry run)
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_right()
|
|
|
|
self.debug.press_right()
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def abort_recovery(self, confirm: bool) -> BRGeneratorType:
|
|
|
|
yield
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR:
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__num_of_words")
|
2024-07-28 16:54:42 +00:00
|
|
|
self.debug.press_no()
|
|
|
|
yield
|
|
|
|
TR.assert_in(self._text_content(), "recovery__wanna_cancel_recovery")
|
|
|
|
self.debug.press_right()
|
|
|
|
if confirm:
|
|
|
|
self.debug.press_yes()
|
|
|
|
else:
|
|
|
|
self.debug.press_no()
|
2024-09-02 11:01:16 +00:00
|
|
|
elif self.client.layout_type is LayoutType.Mercury:
|
2024-06-02 10:47:24 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__enter_each_word")
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
2024-07-28 16:54:42 +00:00
|
|
|
self.debug.synchronize_at("VerticalMenu")
|
|
|
|
if confirm:
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.VERTICAL_MENU[0])
|
2024-07-28 16:54:42 +00:00
|
|
|
else:
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
2023-07-21 09:38:28 +00:00
|
|
|
else:
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__enter_any_share")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_no()
|
2024-07-28 16:54:42 +00:00
|
|
|
yield
|
|
|
|
TR.assert_in(self._text_content(), "recovery__wanna_cancel_recovery")
|
|
|
|
if confirm:
|
|
|
|
self.debug.press_yes()
|
|
|
|
else:
|
|
|
|
self.debug.press_no()
|
2023-07-21 09:38:28 +00:00
|
|
|
|
2024-07-30 14:54:40 +00:00
|
|
|
def abort_recovery_between_shares(self) -> BRGeneratorType:
|
|
|
|
yield
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR:
|
2024-07-30 14:54:40 +00:00
|
|
|
TR.assert_template(
|
|
|
|
self._text_content(), "recovery__x_of_y_entered_template"
|
|
|
|
)
|
|
|
|
self.debug.press_no()
|
|
|
|
assert (yield).name == "abort_recovery"
|
|
|
|
TR.assert_in(self._text_content(), "recovery__wanna_cancel_recovery")
|
|
|
|
self.debug.press_right()
|
|
|
|
self.debug.press_yes()
|
2024-09-02 11:01:16 +00:00
|
|
|
elif self.client.layout_type is LayoutType.Mercury:
|
2024-07-30 14:54:40 +00:00
|
|
|
TR.assert_template(
|
|
|
|
self._text_content(), "recovery__x_of_y_entered_template"
|
|
|
|
)
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
2024-07-30 14:54:40 +00:00
|
|
|
self.debug.synchronize_at("VerticalMenu")
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.VERTICAL_MENU[0])
|
2024-07-30 14:54:40 +00:00
|
|
|
assert (yield).name == "abort_recovery"
|
2023-11-21 15:55:46 +00:00
|
|
|
layout = self.debug.swipe_up()
|
|
|
|
TR.assert_equals(layout.title(), "recovery__title_cancel_recovery")
|
2024-07-30 14:54:40 +00:00
|
|
|
self.debug.click(buttons.TAP_TO_CONFIRM)
|
|
|
|
else:
|
|
|
|
TR.assert_template(
|
|
|
|
self._text_content(), "recovery__x_of_y_entered_template"
|
|
|
|
)
|
|
|
|
self.debug.press_no()
|
|
|
|
assert (yield).name == "abort_recovery"
|
|
|
|
TR.assert_in(self._text_content(), "recovery__wanna_cancel_recovery")
|
|
|
|
self.debug.press_yes()
|
|
|
|
|
2023-07-21 09:38:28 +00:00
|
|
|
def input_number_of_words(self, num_words: int) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.MnemonicWordCount
|
2023-11-21 15:55:46 +00:00
|
|
|
assert br.name == "recovery_word_count"
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR:
|
2023-11-21 12:51:59 +00:00
|
|
|
TR.assert_in(self.debug.read_layout().title(), "word_count__title")
|
2023-07-21 09:38:28 +00:00
|
|
|
else:
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__num_of_words")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.input(str(num_words))
|
|
|
|
|
|
|
|
def warning_invalid_recovery_seed(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.Warning
|
2024-04-25 09:30:24 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__invalid_wallet_backup_entered")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def warning_invalid_recovery_share(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.Warning
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__invalid_share_entered")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def warning_group_threshold_reached(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.Warning
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__group_threshold_reached")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def warning_share_already_entered(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.Warning
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__share_already_entered")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def warning_share_from_another_shamir(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.Warning
|
2024-05-08 10:43:07 +00:00
|
|
|
TR.assert_in(
|
|
|
|
self._text_content(), "recovery__share_from_another_multi_share_backup"
|
|
|
|
)
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def success_share_group_entered(self) -> BRGeneratorType:
|
2023-11-21 15:55:46 +00:00
|
|
|
assert (yield).name == "share_success"
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__you_have_entered")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def success_wallet_recovered(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.Success
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(self._text_content(), "recovery__wallet_recovered")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def success_bip39_dry_run_valid(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.Success
|
2023-08-11 15:57:32 +00:00
|
|
|
text = get_text_possible_pagination(self.debug, br)
|
|
|
|
# TODO: make sure the translations fit on one page
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type not in (LayoutType.TT, LayoutType.Mercury):
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(text, "recovery__dry_run_bip39_valid_match")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def success_slip39_dryrun_valid(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.Success
|
2023-08-11 15:57:32 +00:00
|
|
|
text = get_text_possible_pagination(self.debug, br)
|
|
|
|
# TODO: make sure the translations fit on one page
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type not in (LayoutType.TT, LayoutType.Mercury):
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(text, "recovery__dry_run_slip39_valid_match")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def warning_slip39_dryrun_mismatch(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.Warning
|
2023-08-11 15:57:32 +00:00
|
|
|
text = get_text_possible_pagination(self.debug, br)
|
|
|
|
# TODO: make sure the translations fit on one page on TT
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type not in (LayoutType.TT, LayoutType.Mercury):
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(text, "recovery__dry_run_slip39_valid_mismatch")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def warning_bip39_dryrun_mismatch(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.Warning
|
2023-08-11 15:57:32 +00:00
|
|
|
text = get_text_possible_pagination(self.debug, br)
|
|
|
|
# TODO: make sure the translations fit on one page
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type not in (LayoutType.TT, LayoutType.Mercury):
|
2023-08-11 15:57:32 +00:00
|
|
|
TR.assert_in(text, "recovery__dry_run_bip39_valid_mismatch")
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def success_more_shares_needed(
|
2023-11-21 15:55:46 +00:00
|
|
|
self, count_needed: int | None = None, click_ok: bool = True
|
2023-07-21 09:38:28 +00:00
|
|
|
) -> BRGeneratorType:
|
2023-08-11 15:57:32 +00:00
|
|
|
br = yield
|
2023-11-21 15:55:46 +00:00
|
|
|
assert br.name == "recovery"
|
2023-08-11 15:57:32 +00:00
|
|
|
text = get_text_possible_pagination(self.debug, br)
|
2023-07-21 09:38:28 +00:00
|
|
|
if count_needed is not None:
|
2023-08-11 15:57:32 +00:00
|
|
|
assert str(count_needed) in text
|
2023-11-21 15:55:46 +00:00
|
|
|
if click_ok:
|
|
|
|
self.debug.press_yes()
|
2023-07-21 09:38:28 +00:00
|
|
|
|
|
|
|
def input_mnemonic(self, mnemonic: list[str]) -> BRGeneratorType:
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.MnemonicInput
|
2023-11-21 15:55:46 +00:00
|
|
|
assert br.name == "mnemonic"
|
2023-11-21 12:51:59 +00:00
|
|
|
assert "MnemonicKeyboard" in self.debug.read_layout().all_components()
|
2023-08-11 15:57:32 +00:00
|
|
|
for _, word in enumerate(mnemonic):
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.input(word)
|
|
|
|
|
|
|
|
def input_all_slip39_shares(
|
|
|
|
self,
|
|
|
|
shares: list[str],
|
|
|
|
has_groups: bool = False,
|
|
|
|
click_info: bool = False,
|
|
|
|
) -> BRGeneratorType:
|
|
|
|
for index, share in enumerate(shares):
|
|
|
|
mnemonic = share.split(" ")
|
|
|
|
yield from self.input_mnemonic(mnemonic)
|
|
|
|
|
|
|
|
if index < len(shares) - 1:
|
|
|
|
if has_groups:
|
|
|
|
yield from self.success_share_group_entered()
|
2023-11-21 15:55:46 +00:00
|
|
|
|
|
|
|
yield from self.success_more_shares_needed(click_ok=not click_info)
|
2024-05-27 22:19:01 +00:00
|
|
|
if click_info:
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TT:
|
2024-05-27 22:19:01 +00:00
|
|
|
yield from self.tt_click_info()
|
2024-09-02 11:01:16 +00:00
|
|
|
elif self.client.layout_type is LayoutType.Mercury:
|
2024-08-26 15:10:04 +00:00
|
|
|
yield from self.mercury_click_info()
|
2023-11-21 15:55:46 +00:00
|
|
|
else:
|
|
|
|
raise ValueError("Unknown model!")
|
|
|
|
yield from self.success_more_shares_needed()
|
2023-07-21 09:38:28 +00:00
|
|
|
|
2023-11-21 15:55:46 +00:00
|
|
|
def tt_click_info(self) -> t.Generator[t.Any, t.Any, None]:
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_info()
|
2023-11-21 15:55:46 +00:00
|
|
|
br = yield
|
|
|
|
assert br.name == "show_shares"
|
|
|
|
for _ in range(br.pages):
|
|
|
|
self.debug.swipe_up()
|
2023-07-21 09:38:28 +00:00
|
|
|
self.debug.press_yes()
|
2023-08-02 10:48:06 +00:00
|
|
|
|
2024-08-26 15:10:04 +00:00
|
|
|
def mercury_click_info(self) -> BRGeneratorType:
|
|
|
|
# Moving through the menu into the show_shares screen
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
2024-05-27 22:19:01 +00:00
|
|
|
self.debug.synchronize_at("VerticalMenu")
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.VERTICAL_MENU[0])
|
2024-08-26 15:10:04 +00:00
|
|
|
br = yield
|
|
|
|
assert br.name == "show_shares"
|
|
|
|
assert br.code == B.Other
|
|
|
|
# Getting back to the homepage
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
2024-05-27 22:19:01 +00:00
|
|
|
|
2023-08-02 10:48:06 +00:00
|
|
|
|
|
|
|
class EthereumFlow:
|
|
|
|
GO_BACK = (16, 220)
|
|
|
|
|
|
|
|
def __init__(self, client: Client):
|
|
|
|
self.client = client
|
|
|
|
self.debug = self.client.debug
|
|
|
|
|
|
|
|
def confirm_data(self, info: bool = False, cancel: bool = False) -> BRGeneratorType:
|
2024-11-08 10:37:09 +00:00
|
|
|
assert (yield).name == "confirm_data"
|
2023-11-21 12:51:59 +00:00
|
|
|
TR.assert_equals(self.debug.read_layout().title(), "ethereum__title_input_data")
|
2023-08-02 10:48:06 +00:00
|
|
|
if info:
|
|
|
|
self.debug.press_info()
|
|
|
|
elif cancel:
|
|
|
|
self.debug.press_no()
|
|
|
|
else:
|
|
|
|
self.debug.press_yes()
|
|
|
|
|
|
|
|
def paginate_data(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
2024-11-08 10:37:09 +00:00
|
|
|
assert br.name == "confirm_data"
|
2023-08-02 10:48:06 +00:00
|
|
|
assert br.pages is not None
|
2024-11-08 10:37:09 +00:00
|
|
|
TR.assert_equals(self.debug.read_layout().title(), "ethereum__title_input_data")
|
2024-11-11 12:40:25 +00:00
|
|
|
for _ in range(br.pages):
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout()
|
2024-11-11 12:40:25 +00:00
|
|
|
go_next(self.debug)
|
|
|
|
self.debug.read_layout()
|
|
|
|
|
|
|
|
if self.debug.layout_type is LayoutType.TR:
|
|
|
|
# TR is going back to the "show more" screen here
|
|
|
|
assert (yield).name == "confirm_data"
|
|
|
|
self.debug.press_yes()
|
2023-08-02 10:48:06 +00:00
|
|
|
|
|
|
|
def paginate_data_go_back(self) -> BRGeneratorType:
|
|
|
|
br = yield
|
2024-11-08 10:37:09 +00:00
|
|
|
assert br.name == "confirm_data"
|
2023-08-02 10:48:06 +00:00
|
|
|
assert br.pages is not None
|
|
|
|
assert br.pages > 2
|
2024-11-08 10:37:09 +00:00
|
|
|
TR.assert_equals(self.debug.read_layout().title(), "ethereum__title_input_data")
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TR:
|
2023-08-02 10:48:06 +00:00
|
|
|
self.debug.press_right()
|
|
|
|
self.debug.press_right()
|
|
|
|
self.debug.press_left()
|
|
|
|
self.debug.press_left()
|
|
|
|
self.debug.press_left()
|
2024-09-02 11:01:16 +00:00
|
|
|
elif self.client.layout_type in (LayoutType.TT, LayoutType.Mercury):
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.swipe_up()
|
|
|
|
self.debug.swipe_up()
|
2024-09-02 11:01:16 +00:00
|
|
|
self.debug.click(self.GO_BACK)
|
|
|
|
else:
|
|
|
|
raise ValueError(f"Unknown layout: {self.client.layout_type}")
|
2023-08-02 10:48:06 +00:00
|
|
|
|
2024-11-11 12:40:25 +00:00
|
|
|
def _confirm_tx_tt(
|
|
|
|
self, cancel: bool, info: bool, go_back_from_summary: bool
|
|
|
|
) -> BRGeneratorType:
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
TR.assert_equals(self.debug.read_layout().title(), "words__address")
|
|
|
|
if cancel:
|
|
|
|
self.debug.press_no()
|
|
|
|
return
|
|
|
|
|
|
|
|
self.debug.press_yes()
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
TR.assert_equals(self.debug.read_layout().title(), "words__title_summary")
|
|
|
|
TR.assert_in(self.debug.read_layout().text_content(), "send__maximum_fee")
|
|
|
|
if go_back_from_summary:
|
|
|
|
self.debug.press_no()
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
self.debug.press_yes()
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
if info:
|
|
|
|
self.debug.press_info()
|
|
|
|
TR.assert_in(self.debug.read_layout().text_content(), "ethereum__gas_limit")
|
|
|
|
TR.assert_in(self.debug.read_layout().text_content(), "ethereum__gas_price")
|
|
|
|
self.debug.press_no()
|
|
|
|
self.debug.press_yes()
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
|
|
|
|
def _confirm_tx_tr(
|
|
|
|
self, cancel: bool, info: bool, go_back_from_summary: bool
|
|
|
|
) -> BRGeneratorType:
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
TR.assert_in_multiple(
|
|
|
|
self.debug.read_layout().title(),
|
|
|
|
["ethereum__interaction_contract", "words__recipient"],
|
|
|
|
)
|
|
|
|
if cancel:
|
|
|
|
self.debug.press_left()
|
|
|
|
return
|
|
|
|
self.debug.press_right()
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
TR.assert_in(self.debug.read_layout().text_content(), "send__maximum_fee")
|
|
|
|
if go_back_from_summary:
|
|
|
|
self.debug.press_left()
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
self.debug.press_right()
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
if info:
|
|
|
|
self.debug.press_right()
|
|
|
|
TR.assert_in(self.debug.read_layout().text_content(), "ethereum__gas_limit")
|
|
|
|
self.debug.press_right()
|
|
|
|
TR.assert_in(self.debug.read_layout().text_content(), "ethereum__gas_price")
|
|
|
|
self.debug.press_left()
|
|
|
|
self.debug.press_left()
|
|
|
|
self.debug.press_middle()
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
|
|
|
|
def _confirm_tx_mercury(
|
|
|
|
self, cancel: bool, info: bool, go_back_from_summary: bool
|
|
|
|
) -> BRGeneratorType:
|
|
|
|
assert (yield).name == "confirm_output"
|
|
|
|
title = self.debug.read_layout().title()
|
|
|
|
TR.assert_in(title, "words__address")
|
|
|
|
TR.assert_in(title, "words__recipient")
|
|
|
|
|
|
|
|
if cancel:
|
|
|
|
self.debug.press_no()
|
|
|
|
return
|
|
|
|
|
|
|
|
self.debug.swipe_up()
|
|
|
|
assert (yield).name == "confirm_total"
|
|
|
|
layout = self.debug.read_layout()
|
|
|
|
TR.assert_equals(layout.title(), "words__title_summary")
|
|
|
|
TR.assert_in(layout.text_content(), "send__maximum_fee")
|
|
|
|
if go_back_from_summary:
|
|
|
|
self.debug.press_no()
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
self.debug.press_yes()
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
if info:
|
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
|
|
|
self.debug.synchronize_at("VerticalMenu")
|
|
|
|
self.debug.click(buttons.VERTICAL_MENU[0])
|
|
|
|
text = self.debug.read_layout().text_content()
|
|
|
|
TR.assert_in(text, "ethereum__gas_limit")
|
|
|
|
TR.assert_in(text, "ethereum__gas_price")
|
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
|
|
|
self.debug.swipe_up()
|
|
|
|
self.debug.read_layout()
|
|
|
|
self.debug.click(buttons.TAP_TO_CONFIRM)
|
|
|
|
assert (yield).name == "confirm_ethereum_tx"
|
|
|
|
|
2023-12-05 10:50:13 +00:00
|
|
|
def confirm_tx(
|
|
|
|
self,
|
|
|
|
cancel: bool = False,
|
|
|
|
info: bool = False,
|
|
|
|
go_back_from_summary: bool = False,
|
|
|
|
) -> BRGeneratorType:
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TT:
|
2024-11-11 12:40:25 +00:00
|
|
|
yield from self._confirm_tx_tt(cancel, info, go_back_from_summary)
|
2024-09-02 11:01:16 +00:00
|
|
|
elif self.client.layout_type is LayoutType.TR:
|
2024-11-11 12:40:25 +00:00
|
|
|
yield from self._confirm_tx_tr(cancel, info, go_back_from_summary)
|
2024-09-02 11:01:16 +00:00
|
|
|
elif self.client.layout_type is LayoutType.Mercury:
|
2024-11-11 12:40:25 +00:00
|
|
|
yield from self._confirm_tx_mercury(cancel, info, go_back_from_summary)
|
2024-08-14 09:00:06 +00:00
|
|
|
else:
|
|
|
|
raise ValueError("Unknown model!")
|
|
|
|
|
2024-02-21 15:03:48 +00:00
|
|
|
def confirm_tx_staking(
|
|
|
|
self,
|
|
|
|
info: bool = False,
|
|
|
|
) -> BRGeneratorType:
|
2024-09-03 13:07:51 +00:00
|
|
|
br = yield
|
|
|
|
assert br.code == B.SignTx
|
|
|
|
assert br.name == "confirm_ethereum_staking_tx"
|
2024-02-21 15:03:48 +00:00
|
|
|
TR.assert_equals_multiple(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().title(),
|
2024-02-21 15:03:48 +00:00
|
|
|
[
|
|
|
|
"ethereum__staking_stake",
|
|
|
|
"ethereum__staking_unstake",
|
|
|
|
"ethereum__staking_claim",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
TR.assert_equals_multiple(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().text_content(),
|
2024-02-21 15:03:48 +00:00
|
|
|
[
|
|
|
|
"ethereum__staking_stake_intro",
|
|
|
|
"ethereum__staking_unstake_intro",
|
|
|
|
"ethereum__staking_claim_intro",
|
|
|
|
],
|
|
|
|
)
|
2024-09-02 11:01:16 +00:00
|
|
|
if self.client.layout_type is LayoutType.TT:
|
2024-02-21 15:03:48 +00:00
|
|
|
# confirm intro
|
|
|
|
if info:
|
2024-09-04 09:03:20 +00:00
|
|
|
self.debug.click(
|
|
|
|
buttons.CORNER_BUTTON,
|
|
|
|
)
|
2024-02-21 15:03:48 +00:00
|
|
|
TR.assert_equals_multiple(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().title(),
|
2024-02-21 15:03:48 +00:00
|
|
|
[
|
|
|
|
"ethereum__staking_stake_address",
|
|
|
|
"ethereum__staking_claim_address",
|
|
|
|
],
|
|
|
|
)
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_no()
|
2024-02-21 15:03:48 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
yield
|
|
|
|
|
|
|
|
# confirm summary
|
2024-09-03 13:07:51 +00:00
|
|
|
if info:
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_info()
|
2024-02-21 15:03:48 +00:00
|
|
|
TR.assert_in(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().text_content(), "ethereum__gas_limit"
|
2024-02-21 15:03:48 +00:00
|
|
|
)
|
|
|
|
TR.assert_in(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().text_content(), "ethereum__gas_price"
|
2024-02-21 15:03:48 +00:00
|
|
|
)
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_no()
|
2024-02-21 15:03:48 +00:00
|
|
|
self.debug.press_yes()
|
|
|
|
yield
|
2024-08-14 09:00:06 +00:00
|
|
|
|
|
|
|
self.debug.press_yes()
|
2024-09-02 11:01:16 +00:00
|
|
|
|
|
|
|
elif self.client.layout_type is LayoutType.Mercury:
|
2024-09-03 13:07:51 +00:00
|
|
|
# confirm intro
|
|
|
|
if info:
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
2024-09-03 13:07:51 +00:00
|
|
|
self.debug.synchronize_at("VerticalMenu")
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.VERTICAL_MENU[0])
|
2024-09-03 13:07:51 +00:00
|
|
|
TR.assert_equals_multiple(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().title(),
|
2024-09-03 13:07:51 +00:00
|
|
|
[
|
|
|
|
"ethereum__staking_stake_address",
|
|
|
|
"ethereum__staking_claim_address",
|
|
|
|
],
|
|
|
|
)
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
2024-09-03 13:07:51 +00:00
|
|
|
|
|
|
|
self.debug.swipe_up()
|
|
|
|
br = yield
|
|
|
|
assert br.code == B.SignTx
|
|
|
|
assert br.name == "confirm_total"
|
|
|
|
|
|
|
|
# confirm summary
|
|
|
|
if info:
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
2024-09-03 13:07:51 +00:00
|
|
|
self.debug.synchronize_at("VerticalMenu")
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.VERTICAL_MENU[0])
|
2024-09-03 13:07:51 +00:00
|
|
|
TR.assert_in(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().text_content(), "ethereum__gas_limit"
|
2024-09-03 13:07:51 +00:00
|
|
|
)
|
|
|
|
TR.assert_in(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().text_content(), "ethereum__gas_price"
|
2024-09-03 13:07:51 +00:00
|
|
|
)
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
|
|
|
self.debug.click(buttons.CORNER_BUTTON)
|
2024-09-03 13:07:51 +00:00
|
|
|
self.debug.swipe_up()
|
|
|
|
# br = yield # FIXME: no BR on sign transaction
|
|
|
|
|
|
|
|
self.debug.press_yes()
|
|
|
|
|
2024-09-02 11:01:16 +00:00
|
|
|
elif self.client.layout_type is LayoutType.TR:
|
2024-02-21 15:03:48 +00:00
|
|
|
# confirm intro
|
|
|
|
if info:
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_right()
|
2024-02-21 15:03:48 +00:00
|
|
|
TR.assert_equals_multiple(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().title(),
|
2024-02-21 15:03:48 +00:00
|
|
|
[
|
|
|
|
"ethereum__staking_stake_address",
|
|
|
|
"ethereum__staking_claim_address",
|
|
|
|
],
|
|
|
|
)
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_left()
|
2024-02-21 15:03:48 +00:00
|
|
|
self.debug.press_middle()
|
|
|
|
yield
|
|
|
|
|
|
|
|
# confirm summary
|
|
|
|
if info:
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_right()
|
2024-02-21 15:03:48 +00:00
|
|
|
TR.assert_in(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().text_content(), "ethereum__gas_limit"
|
2024-02-21 15:03:48 +00:00
|
|
|
)
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_right()
|
2024-02-21 15:03:48 +00:00
|
|
|
TR.assert_in(
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.read_layout().text_content(), "ethereum__gas_price"
|
2024-02-21 15:03:48 +00:00
|
|
|
)
|
2023-11-21 12:51:59 +00:00
|
|
|
self.debug.press_left()
|
|
|
|
self.debug.press_left()
|
2024-02-21 15:03:48 +00:00
|
|
|
self.debug.press_middle()
|
|
|
|
yield
|
2024-08-14 09:00:06 +00:00
|
|
|
|
|
|
|
self.debug.press_yes()
|
2024-09-02 11:01:16 +00:00
|
|
|
|
2024-09-03 13:07:51 +00:00
|
|
|
else:
|
|
|
|
raise ValueError("Unknown model!")
|