mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 15:38:11 +00:00
feat(core/rust): add account and address labels into send flow
[no changelog]
This commit is contained in:
parent
570ffe2c0d
commit
64236e699f
@ -16,10 +16,12 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR___dict__;
|
MP_QSTR___dict__;
|
||||||
MP_QSTR___name__;
|
MP_QSTR___name__;
|
||||||
MP_QSTR_account;
|
MP_QSTR_account;
|
||||||
|
MP_QSTR_account_label;
|
||||||
MP_QSTR_accounts;
|
MP_QSTR_accounts;
|
||||||
MP_QSTR_action;
|
MP_QSTR_action;
|
||||||
MP_QSTR_active;
|
MP_QSTR_active;
|
||||||
MP_QSTR_address;
|
MP_QSTR_address;
|
||||||
|
MP_QSTR_address_label;
|
||||||
MP_QSTR_address_title;
|
MP_QSTR_address_title;
|
||||||
MP_QSTR_allow_cancel;
|
MP_QSTR_allow_cancel;
|
||||||
MP_QSTR_amount;
|
MP_QSTR_amount;
|
||||||
|
@ -522,6 +522,7 @@ extern "C" fn new_confirm_modify_output(n_args: usize, args: *const Obj, kwargs:
|
|||||||
extern "C" fn new_confirm_output(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
extern "C" fn new_confirm_output(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||||
let block = |_args: &[Obj], kwargs: &Map| {
|
let block = |_args: &[Obj], kwargs: &Map| {
|
||||||
let address: StrBuffer = kwargs.get(Qstr::MP_QSTR_address)?.try_into()?;
|
let address: StrBuffer = kwargs.get(Qstr::MP_QSTR_address)?.try_into()?;
|
||||||
|
let address_label: StrBuffer = kwargs.get(Qstr::MP_QSTR_address_label)?.try_into()?;
|
||||||
let amount: StrBuffer = kwargs.get(Qstr::MP_QSTR_amount)?.try_into()?;
|
let amount: StrBuffer = kwargs.get(Qstr::MP_QSTR_amount)?.try_into()?;
|
||||||
let address_title: StrBuffer = kwargs.get(Qstr::MP_QSTR_address_title)?.try_into()?;
|
let address_title: StrBuffer = kwargs.get(Qstr::MP_QSTR_address_title)?.try_into()?;
|
||||||
let address_title_clone = address_title.clone();
|
let address_title_clone = address_title.clone();
|
||||||
@ -532,23 +533,27 @@ extern "C" fn new_confirm_output(n_args: usize, args: *const Obj, kwargs: *mut M
|
|||||||
match page_index {
|
match page_index {
|
||||||
0 => {
|
0 => {
|
||||||
// RECIPIENT + address
|
// RECIPIENT + address
|
||||||
let btn_layout = ButtonLayout::cancel_none_text("CONFIRM".into());
|
let btn_layout = ButtonLayout::cancel_none_text("CONTINUE".into());
|
||||||
let btn_actions = ButtonActions::cancel_none_next();
|
let btn_actions = ButtonActions::cancel_none_next();
|
||||||
// Not putting hyphens in the address
|
// Not putting hyphens in the address.
|
||||||
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
// Potentially adding address label in different font.
|
||||||
.line_breaking(LineBreaking::BreakWordsNoHyphen)
|
let mut ops = OpTextLayout::new(theme::TEXT_MONO)
|
||||||
.text_mono(address.clone());
|
.line_breaking(LineBreaking::BreakWordsNoHyphen);
|
||||||
let formatted = FormattedText::new(ops);
|
if !address_label.is_empty() {
|
||||||
|
ops = ops.text_normal(address_label.clone()).newline();
|
||||||
|
}
|
||||||
|
ops = ops.text_mono(address.clone());
|
||||||
|
let formatted =
|
||||||
|
FormattedText::new(ops).vertically_aligned(geometry::Alignment::Center);
|
||||||
Page::new(btn_layout, btn_actions, formatted).with_title(address_title.clone())
|
Page::new(btn_layout, btn_actions, formatted).with_title(address_title.clone())
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
// AMOUNT + amount
|
// AMOUNT + amount
|
||||||
let btn_layout = ButtonLayout::up_arrow_none_text("CONFIRM".into());
|
let btn_layout = ButtonLayout::up_arrow_none_text("CONFIRM".into());
|
||||||
let btn_actions = ButtonActions::prev_none_confirm();
|
let btn_actions = ButtonActions::prev_none_confirm();
|
||||||
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
let ops = OpTextLayout::new(theme::TEXT_MONO).text_mono(amount.clone());
|
||||||
.newline()
|
let formatted =
|
||||||
.text_mono(amount.clone());
|
FormattedText::new(ops).vertically_aligned(geometry::Alignment::Center);
|
||||||
let formatted = FormattedText::new(ops);
|
|
||||||
Page::new(btn_layout, btn_actions, formatted).with_title(amount_title.clone())
|
Page::new(btn_layout, btn_actions, formatted).with_title(amount_title.clone())
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@ -569,34 +574,75 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma
|
|||||||
let fee_rate_amount: Option<StrBuffer> = kwargs
|
let fee_rate_amount: Option<StrBuffer> = kwargs
|
||||||
.get(Qstr::MP_QSTR_fee_rate_amount)?
|
.get(Qstr::MP_QSTR_fee_rate_amount)?
|
||||||
.try_into_option()?;
|
.try_into_option()?;
|
||||||
|
let account_label: Option<StrBuffer> =
|
||||||
|
kwargs.get(Qstr::MP_QSTR_account_label)?.try_into_option()?;
|
||||||
let total_label: StrBuffer = kwargs.get(Qstr::MP_QSTR_total_label)?.try_into()?;
|
let total_label: StrBuffer = kwargs.get(Qstr::MP_QSTR_total_label)?.try_into()?;
|
||||||
let fee_label: StrBuffer = kwargs.get(Qstr::MP_QSTR_fee_label)?.try_into()?;
|
let fee_label: StrBuffer = kwargs.get(Qstr::MP_QSTR_fee_label)?.try_into()?;
|
||||||
|
|
||||||
let get_page = move |page_index| {
|
let get_page = move |page_index| {
|
||||||
// Total amount + fee
|
match page_index {
|
||||||
assert!(page_index == 0);
|
0 => {
|
||||||
|
// Total amount + fee
|
||||||
|
let btn_layout = ButtonLayout::cancel_armed_info("CONFIRM".into());
|
||||||
|
let btn_actions = ButtonActions::cancel_confirm_next();
|
||||||
|
|
||||||
let btn_layout = ButtonLayout::cancel_none_htc("HOLD TO CONFIRM".into());
|
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
||||||
let btn_actions = ButtonActions::cancel_none_confirm();
|
.text_bold(total_label.clone())
|
||||||
|
.newline()
|
||||||
|
.text_mono(total_amount.clone())
|
||||||
|
.newline()
|
||||||
|
.newline()
|
||||||
|
.text_bold(fee_label.clone())
|
||||||
|
.newline()
|
||||||
|
.text_mono(fee_amount.clone());
|
||||||
|
|
||||||
let mut ops = OpTextLayout::new(theme::TEXT_MONO)
|
let formatted = FormattedText::new(ops);
|
||||||
.text_bold(total_label.clone())
|
Page::new(btn_layout, btn_actions, formatted)
|
||||||
.newline()
|
}
|
||||||
.text_mono(total_amount.clone())
|
1 => {
|
||||||
.newline()
|
// Fee rate info
|
||||||
.text_bold(fee_label.clone())
|
let btn_layout = ButtonLayout::arrow_none_arrow();
|
||||||
.newline()
|
let btn_actions = ButtonActions::prev_none_next();
|
||||||
.text_mono(fee_amount.clone());
|
|
||||||
|
|
||||||
// Fee rate amount might not be there
|
let fee_rate_amount = fee_rate_amount.clone().unwrap_or_default();
|
||||||
if let Some(fee_rate_amount) = fee_rate_amount.clone() {
|
|
||||||
ops = ops.newline().text_mono(fee_rate_amount)
|
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
||||||
|
.text_bold("FEE INFORMATION".into())
|
||||||
|
.newline()
|
||||||
|
.newline()
|
||||||
|
.newline_half()
|
||||||
|
.text_bold("Fee rate:".into())
|
||||||
|
.newline()
|
||||||
|
.text_mono(fee_rate_amount);
|
||||||
|
|
||||||
|
let formatted = FormattedText::new(ops);
|
||||||
|
Page::new(btn_layout, btn_actions, formatted)
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
// Wallet and account info
|
||||||
|
let btn_layout = ButtonLayout::arrow_none_none();
|
||||||
|
let btn_actions = ButtonActions::prev_none_none();
|
||||||
|
|
||||||
|
let account_label = account_label.clone().unwrap_or_default();
|
||||||
|
|
||||||
|
// TODO: include wallet info when available
|
||||||
|
|
||||||
|
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
||||||
|
.text_bold("SENDING FROM".into())
|
||||||
|
.newline()
|
||||||
|
.newline()
|
||||||
|
.newline_half()
|
||||||
|
.text_bold("Account:".into())
|
||||||
|
.newline()
|
||||||
|
.text_mono(account_label);
|
||||||
|
|
||||||
|
let formatted = FormattedText::new(ops);
|
||||||
|
Page::new(btn_layout, btn_actions, formatted)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
let formatted = FormattedText::new(ops);
|
|
||||||
Page::new(btn_layout, btn_actions, formatted)
|
|
||||||
};
|
};
|
||||||
let pages = FlowPages::new(get_page, 1);
|
let pages = FlowPages::new(get_page, 3);
|
||||||
|
|
||||||
let obj = LayoutObj::new(Flow::new(pages))?;
|
let obj = LayoutObj::new(Flow::new(pages))?;
|
||||||
Ok(obj.into())
|
Ok(obj.into())
|
||||||
@ -612,7 +658,7 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut
|
|||||||
let get_page = move |page_index| {
|
let get_page = move |page_index| {
|
||||||
assert!(page_index == 0);
|
assert!(page_index == 0);
|
||||||
|
|
||||||
let btn_layout = ButtonLayout::cancel_armed_text("CONFIRM".into(), "i".into());
|
let btn_layout = ButtonLayout::cancel_armed_info("CONFIRM".into());
|
||||||
let btn_actions = ButtonActions::cancel_confirm_info();
|
let btn_actions = ButtonActions::cancel_confirm_info();
|
||||||
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
||||||
.line_breaking(LineBreaking::BreakWordsNoHyphen)
|
.line_breaking(LineBreaking::BreakWordsNoHyphen)
|
||||||
@ -1354,6 +1400,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// def confirm_output(
|
/// def confirm_output(
|
||||||
/// *,
|
/// *,
|
||||||
/// address: str,
|
/// address: str,
|
||||||
|
/// address_label: str,
|
||||||
/// amount: str,
|
/// amount: str,
|
||||||
/// address_title: str,
|
/// address_title: str,
|
||||||
/// amount_title: str,
|
/// amount_title: str,
|
||||||
@ -1366,6 +1413,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// total_amount: str,
|
/// total_amount: str,
|
||||||
/// fee_amount: str,
|
/// fee_amount: str,
|
||||||
/// fee_rate_amount: str | None,
|
/// fee_rate_amount: str | None,
|
||||||
|
/// account_label: str | None,
|
||||||
/// total_label: str,
|
/// total_label: str,
|
||||||
/// fee_label: str,
|
/// fee_label: str,
|
||||||
/// ) -> object:
|
/// ) -> object:
|
||||||
|
@ -123,6 +123,7 @@ def confirm_modify_output(
|
|||||||
def confirm_output(
|
def confirm_output(
|
||||||
*,
|
*,
|
||||||
address: str,
|
address: str,
|
||||||
|
address_label: str,
|
||||||
amount: str,
|
amount: str,
|
||||||
address_title: str,
|
address_title: str,
|
||||||
amount_title: str,
|
amount_title: str,
|
||||||
@ -136,6 +137,7 @@ def confirm_total(
|
|||||||
total_amount: str,
|
total_amount: str,
|
||||||
fee_amount: str,
|
fee_amount: str,
|
||||||
fee_rate_amount: str | None,
|
fee_rate_amount: str | None,
|
||||||
|
account_label: str | None,
|
||||||
total_label: str,
|
total_label: str,
|
||||||
fee_label: str,
|
fee_label: str,
|
||||||
) -> object:
|
) -> object:
|
||||||
|
@ -693,15 +693,13 @@ async def confirm_output(
|
|||||||
)
|
)
|
||||||
amount_title = "AMOUNT" if output_index is None else f"AMOUNT #{output_index + 1}"
|
amount_title = "AMOUNT" if output_index is None else f"AMOUNT #{output_index + 1}"
|
||||||
|
|
||||||
# TODO: implement `hold` to be consistent with `TT`?
|
|
||||||
# TODO: incorporate label? - label = f" ({address_label})" if address_label else ""
|
|
||||||
|
|
||||||
await raise_if_not_confirmed(
|
await raise_if_not_confirmed(
|
||||||
interact(
|
interact(
|
||||||
ctx,
|
ctx,
|
||||||
RustLayout(
|
RustLayout(
|
||||||
trezorui2.confirm_output(
|
trezorui2.confirm_output(
|
||||||
address=address,
|
address=address,
|
||||||
|
address_label=address_label or "",
|
||||||
address_title=address_title,
|
address_title=address_title,
|
||||||
amount_title=amount_title,
|
amount_title=amount_title,
|
||||||
amount=amount,
|
amount=amount,
|
||||||
@ -944,13 +942,11 @@ async def confirm_total(
|
|||||||
fee_rate_amount: str | None = None,
|
fee_rate_amount: str | None = None,
|
||||||
title: str = "SENDING",
|
title: str = "SENDING",
|
||||||
total_label: str = "TOTAL AMOUNT",
|
total_label: str = "TOTAL AMOUNT",
|
||||||
fee_label: str = "INCLUDING FEE",
|
fee_label: str = "Including fee:",
|
||||||
account_label: str | None = None,
|
account_label: str | None = None,
|
||||||
br_type: str = "confirm_total",
|
br_type: str = "confirm_total",
|
||||||
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
||||||
) -> None:
|
) -> None:
|
||||||
# TODO: incorporate account_label
|
|
||||||
# f"From {account_label}\r\n{total_label}" if account_label else total_label,
|
|
||||||
await raise_if_not_confirmed(
|
await raise_if_not_confirmed(
|
||||||
interact(
|
interact(
|
||||||
ctx,
|
ctx,
|
||||||
@ -960,8 +956,9 @@ async def confirm_total(
|
|||||||
total_amount=total_amount, # type: ignore [No parameter named]
|
total_amount=total_amount, # type: ignore [No parameter named]
|
||||||
fee_amount=fee_amount, # type: ignore [No parameter named]
|
fee_amount=fee_amount, # type: ignore [No parameter named]
|
||||||
fee_rate_amount=fee_rate_amount, # type: ignore [No parameter named]
|
fee_rate_amount=fee_rate_amount, # type: ignore [No parameter named]
|
||||||
|
account_label=account_label, # type: ignore [No parameter named]
|
||||||
total_label=total_label.upper(), # type: ignore [No parameter named]
|
total_label=total_label.upper(), # type: ignore [No parameter named]
|
||||||
fee_label=fee_label.upper(), # type: ignore [No parameter named]
|
fee_label=fee_label, # type: ignore [No parameter named]
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
br_type,
|
br_type,
|
||||||
|
@ -104,7 +104,6 @@ def test_autolock_interrupts_signing(device_handler: "BackgroundDeviceHandler"):
|
|||||||
layout = debug.click(buttons.OK, wait=True)
|
layout = debug.click(buttons.OK, wait=True)
|
||||||
assert "Total amount: 0.0039 BTC" in layout.text_content()
|
assert "Total amount: 0.0039 BTC" in layout.text_content()
|
||||||
elif debug.model == "R":
|
elif debug.model == "R":
|
||||||
debug.press_right(wait=True)
|
|
||||||
debug.press_right(wait=True)
|
debug.press_right(wait=True)
|
||||||
layout = debug.press_right(wait=True)
|
layout = debug.press_right(wait=True)
|
||||||
assert "TOTAL AMOUNT 0.0039 BTC" in layout.text_content()
|
assert "TOTAL AMOUNT 0.0039 BTC" in layout.text_content()
|
||||||
@ -165,7 +164,7 @@ def test_autolock_does_not_interrupt_signing(device_handler: "BackgroundDeviceHa
|
|||||||
if debug.model == "T":
|
if debug.model == "T":
|
||||||
debug.click(buttons.OK)
|
debug.click(buttons.OK)
|
||||||
elif debug.model == "R":
|
elif debug.model == "R":
|
||||||
debug.press_right_htc(1200)
|
debug.press_middle()
|
||||||
|
|
||||||
signatures, tx = device_handler.result()
|
signatures, tx = device_handler.result()
|
||||||
assert len(signatures) == 1
|
assert len(signatures) == 1
|
||||||
|
@ -27,6 +27,10 @@ from ...input_flows import (
|
|||||||
InputFlowLockTimeBlockHeight,
|
InputFlowLockTimeBlockHeight,
|
||||||
InputFlowLockTimeDatetime,
|
InputFlowLockTimeDatetime,
|
||||||
InputFlowSignTxHighFee,
|
InputFlowSignTxHighFee,
|
||||||
|
InputFlowSignTxInformation,
|
||||||
|
InputFlowSignTxInformationCancel,
|
||||||
|
InputFlowSignTxInformationMixed,
|
||||||
|
InputFlowSignTxInformationReplacement,
|
||||||
)
|
)
|
||||||
from ...tx_cache import TxCache
|
from ...tx_cache import TxCache
|
||||||
from .signtx import (
|
from .signtx import (
|
||||||
@ -1524,7 +1528,6 @@ def test_lock_time_datetime(client: Client, lock_time_str: str):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip_t1(reason="Cannot test layouts on T1")
|
@pytest.mark.skip_t1(reason="Cannot test layouts on T1")
|
||||||
@pytest.mark.skip_tr(reason="Not implemented yet")
|
|
||||||
def test_information(client: Client):
|
def test_information(client: Client):
|
||||||
# input tx: 0dac366fd8a67b2a89fbb0d31086e7acded7a5bbf9ef9daa935bc873229ef5b5
|
# input tx: 0dac366fd8a67b2a89fbb0d31086e7acded7a5bbf9ef9daa935bc873229ef5b5
|
||||||
|
|
||||||
@ -1542,29 +1545,9 @@ def test_information(client: Client):
|
|||||||
script_type=messages.OutputScriptType.PAYTOADDRESS,
|
script_type=messages.OutputScriptType.PAYTOADDRESS,
|
||||||
)
|
)
|
||||||
|
|
||||||
def input_flow():
|
|
||||||
yield # confirm output
|
|
||||||
client.debug.wait_layout()
|
|
||||||
client.debug.press_yes()
|
|
||||||
yield # confirm output
|
|
||||||
client.debug.wait_layout()
|
|
||||||
client.debug.press_yes()
|
|
||||||
|
|
||||||
yield # confirm transaction
|
|
||||||
client.debug.wait_layout()
|
|
||||||
client.debug.press_info()
|
|
||||||
|
|
||||||
layout = client.debug.wait_layout()
|
|
||||||
content = layout.text_content().lower()
|
|
||||||
assert "sending from" in content
|
|
||||||
assert "legacy #6" in content
|
|
||||||
assert "fee rate" in content
|
|
||||||
assert "71.56 sat" in content
|
|
||||||
client.debug.click(CORNER_BUTTON, wait=True)
|
|
||||||
client.debug.press_yes()
|
|
||||||
|
|
||||||
with client:
|
with client:
|
||||||
client.set_input_flow(input_flow)
|
IF = InputFlowSignTxInformation(client)
|
||||||
|
client.set_input_flow(IF.get())
|
||||||
client.watch_layout(True)
|
client.watch_layout(True)
|
||||||
|
|
||||||
btc.sign_tx(
|
btc.sign_tx(
|
||||||
@ -1577,7 +1560,6 @@ def test_information(client: Client):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip_t1(reason="Cannot test layouts on T1")
|
@pytest.mark.skip_t1(reason="Cannot test layouts on T1")
|
||||||
@pytest.mark.skip_tr(reason="Not implemented yet")
|
|
||||||
def test_information_mixed(client: Client):
|
def test_information_mixed(client: Client):
|
||||||
inp1 = messages.TxInputType(
|
inp1 = messages.TxInputType(
|
||||||
address_n=parse_path("m/44h/1h/0h/0/0"), # mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q
|
address_n=parse_path("m/44h/1h/0h/0/0"), # mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q
|
||||||
@ -1599,29 +1581,9 @@ def test_information_mixed(client: Client):
|
|||||||
script_type=messages.OutputScriptType.PAYTOADDRESS,
|
script_type=messages.OutputScriptType.PAYTOADDRESS,
|
||||||
)
|
)
|
||||||
|
|
||||||
def input_flow():
|
|
||||||
yield # confirm output
|
|
||||||
client.debug.wait_layout()
|
|
||||||
client.debug.press_yes()
|
|
||||||
yield # confirm output
|
|
||||||
client.debug.wait_layout()
|
|
||||||
client.debug.press_yes()
|
|
||||||
|
|
||||||
yield # confirm transaction
|
|
||||||
client.debug.wait_layout()
|
|
||||||
client.debug.press_info()
|
|
||||||
|
|
||||||
layout = client.debug.wait_layout()
|
|
||||||
content = layout.text_content().lower()
|
|
||||||
assert "sending from" in content
|
|
||||||
assert "multiple accounts" in content
|
|
||||||
assert "fee rate" in content
|
|
||||||
assert "18.33 sat" in content
|
|
||||||
client.debug.click(CORNER_BUTTON, wait=True)
|
|
||||||
client.debug.press_yes()
|
|
||||||
|
|
||||||
with client:
|
with client:
|
||||||
client.set_input_flow(input_flow)
|
IF = InputFlowSignTxInformationMixed(client)
|
||||||
|
client.set_input_flow(IF.get())
|
||||||
client.watch_layout(True)
|
client.watch_layout(True)
|
||||||
|
|
||||||
btc.sign_tx(
|
btc.sign_tx(
|
||||||
@ -1634,7 +1596,6 @@ def test_information_mixed(client: Client):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip_t1(reason="Cannot test layouts on T1")
|
@pytest.mark.skip_t1(reason="Cannot test layouts on T1")
|
||||||
@pytest.mark.skip_tr(reason="Not implemented yet")
|
|
||||||
def test_information_cancel(client: Client):
|
def test_information_cancel(client: Client):
|
||||||
# input tx: 0dac366fd8a67b2a89fbb0d31086e7acded7a5bbf9ef9daa935bc873229ef5b5
|
# input tx: 0dac366fd8a67b2a89fbb0d31086e7acded7a5bbf9ef9daa935bc873229ef5b5
|
||||||
|
|
||||||
@ -1652,24 +1613,9 @@ def test_information_cancel(client: Client):
|
|||||||
script_type=messages.OutputScriptType.PAYTOADDRESS,
|
script_type=messages.OutputScriptType.PAYTOADDRESS,
|
||||||
)
|
)
|
||||||
|
|
||||||
def input_flow():
|
|
||||||
yield # confirm output
|
|
||||||
client.debug.wait_layout()
|
|
||||||
client.debug.press_yes()
|
|
||||||
yield # confirm output
|
|
||||||
client.debug.wait_layout()
|
|
||||||
client.debug.press_yes()
|
|
||||||
|
|
||||||
yield # confirm transaction
|
|
||||||
client.debug.wait_layout()
|
|
||||||
client.debug.press_info()
|
|
||||||
|
|
||||||
client.debug.wait_layout()
|
|
||||||
client.debug.click(CORNER_BUTTON, wait=True)
|
|
||||||
client.debug.press_no()
|
|
||||||
|
|
||||||
with client, pytest.raises(Cancelled):
|
with client, pytest.raises(Cancelled):
|
||||||
client.set_input_flow(input_flow)
|
IF = InputFlowSignTxInformationCancel(client)
|
||||||
|
client.set_input_flow(IF.get())
|
||||||
client.watch_layout(True)
|
client.watch_layout(True)
|
||||||
|
|
||||||
btc.sign_tx(
|
btc.sign_tx(
|
||||||
@ -1682,7 +1628,6 @@ def test_information_cancel(client: Client):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip_t1(reason="Cannot test layouts on T1")
|
@pytest.mark.skip_t1(reason="Cannot test layouts on T1")
|
||||||
@pytest.mark.skip_tr(reason="Input flow different on TR")
|
|
||||||
def test_information_replacement(client: Client):
|
def test_information_replacement(client: Client):
|
||||||
# Use the change output and an external output to bump the fee.
|
# Use the change output and an external output to bump the fee.
|
||||||
# Originally fee was 3780, now 108060 (94280 from change and 10000 from external).
|
# Originally fee was 3780, now 108060 (94280 from change and 10000 from external).
|
||||||
@ -1715,25 +1660,9 @@ def test_information_replacement(client: Client):
|
|||||||
orig_index=0,
|
orig_index=0,
|
||||||
)
|
)
|
||||||
|
|
||||||
def input_flow():
|
|
||||||
yield # confirm txid
|
|
||||||
client.debug.press_yes()
|
|
||||||
yield # confirm address
|
|
||||||
client.debug.press_yes()
|
|
||||||
# go back to address
|
|
||||||
client.debug.press_no()
|
|
||||||
# confirm address
|
|
||||||
client.debug.press_yes()
|
|
||||||
yield # confirm amount
|
|
||||||
client.debug.press_yes()
|
|
||||||
|
|
||||||
yield # transaction summary, press info
|
|
||||||
client.debug.press_info(wait=True)
|
|
||||||
client.debug.click(CORNER_BUTTON, wait=True)
|
|
||||||
client.debug.press_yes()
|
|
||||||
|
|
||||||
with client:
|
with client:
|
||||||
client.set_input_flow(input_flow)
|
IF = InputFlowSignTxInformationReplacement(client)
|
||||||
|
client.set_input_flow(IF.get())
|
||||||
client.watch_layout(True)
|
client.watch_layout(True)
|
||||||
|
|
||||||
btc.sign_tx(
|
btc.sign_tx(
|
||||||
|
@ -446,6 +446,140 @@ class InputFlowSignTxHighFee(InputFlowBase):
|
|||||||
yield from self.go_through_all_screens(screens)
|
yield from self.go_through_all_screens(screens)
|
||||||
|
|
||||||
|
|
||||||
|
def sign_tx_go_to_info(client: Client) -> Generator[None, None, str]:
|
||||||
|
yield # confirm output
|
||||||
|
client.debug.wait_layout()
|
||||||
|
client.debug.press_yes()
|
||||||
|
yield # confirm output
|
||||||
|
client.debug.wait_layout()
|
||||||
|
client.debug.press_yes()
|
||||||
|
|
||||||
|
yield # confirm transaction
|
||||||
|
client.debug.wait_layout()
|
||||||
|
client.debug.press_info()
|
||||||
|
|
||||||
|
layout = client.debug.wait_layout()
|
||||||
|
content = layout.text_content().lower()
|
||||||
|
|
||||||
|
client.debug.click(buttons.CORNER_BUTTON, wait=True)
|
||||||
|
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
def sign_tx_go_to_info_tr(
|
||||||
|
client: Client,
|
||||||
|
) -> Generator[None, None, str]:
|
||||||
|
yield # confirm output
|
||||||
|
client.debug.wait_layout()
|
||||||
|
client.debug.press_right() # CONTINUE
|
||||||
|
client.debug.wait_layout()
|
||||||
|
client.debug.press_right() # CONFIRM
|
||||||
|
|
||||||
|
screen_texts: list[str] = []
|
||||||
|
|
||||||
|
yield # confirm total
|
||||||
|
layout = client.debug.press_right(wait=True)
|
||||||
|
screen_texts.append(layout.text_content())
|
||||||
|
|
||||||
|
layout = client.debug.press_right(wait=True)
|
||||||
|
screen_texts.append(layout.text_content())
|
||||||
|
|
||||||
|
client.debug.press_left()
|
||||||
|
client.debug.press_left()
|
||||||
|
|
||||||
|
return "\n".join(screen_texts)
|
||||||
|
|
||||||
|
|
||||||
|
class InputFlowSignTxInformation(InputFlowBase):
|
||||||
|
def __init__(self, client: Client):
|
||||||
|
super().__init__(client)
|
||||||
|
|
||||||
|
def assert_content(self, content: str) -> None:
|
||||||
|
assert "sending from" in content
|
||||||
|
assert "legacy #6" in content
|
||||||
|
assert "fee rate" in content
|
||||||
|
assert "71.56 sat" in content
|
||||||
|
|
||||||
|
def input_flow_tt(self) -> GeneratorType:
|
||||||
|
content = yield from sign_tx_go_to_info(self.client)
|
||||||
|
self.assert_content(content)
|
||||||
|
self.client.debug.press_yes()
|
||||||
|
|
||||||
|
def input_flow_tr(self) -> GeneratorType:
|
||||||
|
content = yield from sign_tx_go_to_info_tr(self.client)
|
||||||
|
self.assert_content(content.lower())
|
||||||
|
self.client.debug.press_yes()
|
||||||
|
|
||||||
|
|
||||||
|
class InputFlowSignTxInformationMixed(InputFlowBase):
|
||||||
|
def __init__(self, client: Client):
|
||||||
|
super().__init__(client)
|
||||||
|
|
||||||
|
def assert_content(self, content: str) -> None:
|
||||||
|
assert "sending from" in content
|
||||||
|
assert "multiple accounts" in content
|
||||||
|
assert "fee rate" in content
|
||||||
|
assert "18.33 sat" in content
|
||||||
|
|
||||||
|
def input_flow_tt(self) -> GeneratorType:
|
||||||
|
content = yield from sign_tx_go_to_info(self.client)
|
||||||
|
self.assert_content(content)
|
||||||
|
self.client.debug.press_yes()
|
||||||
|
|
||||||
|
def input_flow_tr(self) -> GeneratorType:
|
||||||
|
content = yield from sign_tx_go_to_info_tr(self.client)
|
||||||
|
self.assert_content(content.lower())
|
||||||
|
self.client.debug.press_yes()
|
||||||
|
|
||||||
|
|
||||||
|
class InputFlowSignTxInformationCancel(InputFlowBase):
|
||||||
|
def __init__(self, client: Client):
|
||||||
|
super().__init__(client)
|
||||||
|
|
||||||
|
def input_flow_tt(self) -> GeneratorType:
|
||||||
|
yield from sign_tx_go_to_info(self.client)
|
||||||
|
self.client.debug.press_no()
|
||||||
|
|
||||||
|
def input_flow_tr(self) -> GeneratorType:
|
||||||
|
yield from sign_tx_go_to_info_tr(self.client)
|
||||||
|
self.client.debug.press_left()
|
||||||
|
|
||||||
|
|
||||||
|
class InputFlowSignTxInformationReplacement(InputFlowBase):
|
||||||
|
def __init__(self, client: Client):
|
||||||
|
super().__init__(client)
|
||||||
|
|
||||||
|
def input_flow_tt(self) -> GeneratorType:
|
||||||
|
yield # confirm txid
|
||||||
|
self.client.debug.press_yes()
|
||||||
|
yield # confirm address
|
||||||
|
self.client.debug.press_yes()
|
||||||
|
# go back to address
|
||||||
|
self.client.debug.press_no()
|
||||||
|
# confirm address
|
||||||
|
self.client.debug.press_yes()
|
||||||
|
yield # confirm amount
|
||||||
|
self.client.debug.press_yes()
|
||||||
|
|
||||||
|
yield # transaction summary, press info
|
||||||
|
self.client.debug.press_info(wait=True)
|
||||||
|
self.client.debug.click(buttons.CORNER_BUTTON, wait=True)
|
||||||
|
self.client.debug.press_yes()
|
||||||
|
|
||||||
|
def input_flow_tr(self) -> GeneratorType:
|
||||||
|
yield # confirm txid
|
||||||
|
self.client.debug.press_right()
|
||||||
|
self.client.debug.press_right()
|
||||||
|
yield # confirm address
|
||||||
|
self.client.debug.press_right()
|
||||||
|
self.client.debug.press_right()
|
||||||
|
self.client.debug.press_right()
|
||||||
|
yield # confirm amount
|
||||||
|
self.client.debug.press_right()
|
||||||
|
self.client.debug.press_right()
|
||||||
|
self.client.debug.press_right()
|
||||||
|
|
||||||
|
|
||||||
def lock_time_input_flow_tt(
|
def lock_time_input_flow_tt(
|
||||||
debug: DebugLink,
|
debug: DebugLink,
|
||||||
layout_assert_func: Callable[[DebugLink], None],
|
layout_assert_func: Callable[[DebugLink], None],
|
||||||
|
Loading…
Reference in New Issue
Block a user