You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/src/apps/ethereum/layout.py

293 lines
7.9 KiB

from typing import TYPE_CHECKING
from trezor import TR, ui
from trezor.enums import ButtonRequestType
from trezor.ui.layouts import (
confirm_blob,
confirm_ethereum_staking_tx,
confirm_text,
should_show_more,
)
from .helpers import address_from_bytes, decode_typed_data, format_ethereum_amount
if TYPE_CHECKING:
from typing import Awaitable, Iterable
from trezor.messages import (
EthereumFieldType,
EthereumNetworkInfo,
EthereumStructMember,
EthereumTokenInfo,
)
async def require_confirm_tx(
to_bytes: bytes,
value: int,
maximum_fee: str,
fee_info_items: Iterable[tuple[str, str]],
network: EthereumNetworkInfo,
token: EthereumTokenInfo | None,
chunkify: bool,
) -> None:
from trezor.ui.layouts import confirm_ethereum_tx
if to_bytes:
to_str = address_from_bytes(to_bytes, network)
else:
to_str = TR.ethereum__new_contract
chunkify = False
total_amount = format_ethereum_amount(value, token, network)
await confirm_ethereum_tx(
to_str, total_amount, maximum_fee, fee_info_items, chunkify=chunkify
)
async def require_confirm_stake(
addr_bytes: bytes,
value: int,
maximum_fee: str,
fee_info_items: Iterable[tuple[str, str]],
network: EthereumNetworkInfo,
chunkify: bool,
) -> None:
addr_str = address_from_bytes(addr_bytes, network)
total_amount = format_ethereum_amount(value, None, network)
await confirm_ethereum_staking_tx(
TR.ethereum__staking_title_stake, # title
TR.ethereum__staking_stake_intro, # intro_question
TR.ethereum__staking_title_stake, # verb
total_amount, # total_amount
maximum_fee, # maximum_fee
addr_str, # address
TR.ethereum__staking_title_stake_address, # address_title
fee_info_items, # info_items
chunkify=chunkify,
)
async def require_confirm_unstake(
addr_bytes: bytes,
value: int,
maximum_fee: str,
fee_info_items: Iterable[tuple[str, str]],
network: EthereumNetworkInfo,
chunkify: bool,
) -> None:
addr_str = address_from_bytes(addr_bytes, network)
total_amount = format_ethereum_amount(value, None, network)
await confirm_ethereum_staking_tx(
TR.ethereum__staking_title_unstake, # title
TR.ethereum__staking_unstake_intro, # intro_question
TR.ethereum__staking_title_unstake, # verb
total_amount, # total_amount
maximum_fee, # maximum_fee
addr_str, # address
TR.ethereum__staking_title_stake_address, # address_title
fee_info_items, # info_items
chunkify=chunkify,
)
async def require_confirm_claim(
addr_bytes: bytes,
maximum_fee: str,
fee_info_items: Iterable[tuple[str, str]],
network: EthereumNetworkInfo,
chunkify: bool,
) -> None:
addr_str = address_from_bytes(addr_bytes, network)
await confirm_ethereum_staking_tx(
TR.ethereum__staking_title_claim, # title
TR.ethereum__staking_claim_intro, # intro_question
TR.ethereum__staking_title_claim, # verb
"", # total_amount
maximum_fee, # maximum_fee
addr_str, # address
TR.ethereum__staking_title_claim_address, # address_title
fee_info_items, # info_items
chunkify=chunkify,
)
def require_confirm_unknown_token(address_bytes: bytes) -> Awaitable[None]:
from ubinascii import hexlify
from trezor.ui.layouts import confirm_address
contract_address_hex = "0x" + hexlify(address_bytes).decode()
return confirm_address(
TR.ethereum__unknown_token,
contract_address_hex,
TR.ethereum__contract,
"unknown_token",
br_code=ButtonRequestType.SignTx,
)
def require_confirm_address(address_bytes: bytes) -> Awaitable[None]:
from ubinascii import hexlify
from trezor.ui.layouts import confirm_address
address_hex = "0x" + hexlify(address_bytes).decode()
return confirm_address(
TR.ethereum__title_signing_address,
address_hex,
br_code=ButtonRequestType.SignTx,
)
def require_confirm_other_data(data: bytes, data_total: int) -> Awaitable[None]:
return confirm_blob(
"confirm_data",
TR.ethereum__title_confirm_data,
data,
TR.ethereum__data_size_template.format(data_total),
br_code=ButtonRequestType.SignTx,
ask_pagination=True,
)
async def confirm_typed_data_final() -> None:
from trezor.ui.layouts import confirm_action
await confirm_action(
"confirm_typed_data_final",
TR.ethereum__title_confirm_typed_data,
TR.ethereum__sign_eip712,
verb=TR.buttons__hold_to_confirm,
hold=True,
)
def confirm_empty_typed_message() -> Awaitable[None]:
return confirm_text(
"confirm_empty_typed_message",
TR.ethereum__title_confirm_message,
"",
TR.ethereum__no_message_field,
)
async def should_show_domain(name: bytes, version: bytes) -> bool:
domain_name = decode_typed_data(name, "string")
domain_version = decode_typed_data(version, "string")
para = (
(ui.NORMAL, TR.ethereum__name_and_version),
(ui.DEMIBOLD, domain_name),
(ui.DEMIBOLD, domain_version),
)
return await should_show_more(
TR.ethereum__title_confirm_domain,
para,
TR.ethereum__show_full_domain,
"should_show_domain",
)
async def should_show_struct(
description: str,
data_members: list[EthereumStructMember],
title: str | None = None,
button_text: str | None = None,
) -> bool:
from trezor.strings import format_plural
title = title or TR.ethereum__title_confirm_struct # def_arg
button_text = button_text or TR.ethereum__show_full_struct # def_arg
plural = format_plural(
"{count} {plural}", len(data_members), TR.plurals__contains_x_keys
)
contains_plural = f"{TR.words__contains} {plural}"
para = (
(ui.DEMIBOLD, description),
(
ui.NORMAL,
contains_plural,
),
(ui.NORMAL, ", ".join(field.name for field in data_members)),
)
return await should_show_more(
title,
para,
button_text,
"should_show_struct",
)
async def should_show_array(
parent_objects: Iterable[str],
data_type: str,
size: int,
) -> bool:
from trezor.strings import format_plural_english
# Leaving english plural form because of dynamic noun - data_type
plural = format_plural_english("{count} {plural}", size, data_type)
array_of_plural = f"{TR.words__array_of} {plural}"
para = ((ui.NORMAL, array_of_plural),)
return await should_show_more(
limit_str(".".join(parent_objects)),
para,
TR.ethereum__show_full_array,
"should_show_array",
)
async def confirm_typed_value(
name: str,
value: bytes,
parent_objects: list[str],
field: EthereumFieldType,
array_index: int | None = None,
) -> None:
from trezor.enums import EthereumDataType
from .helpers import get_type_name
type_name = get_type_name(field)
if array_index is not None:
title = limit_str(".".join(parent_objects + [name]))
description = f"[{array_index}] ({type_name})"
else:
title = limit_str(".".join(parent_objects))
description = f"{name} ({type_name})"
data = decode_typed_data(value, type_name)
if field.data_type in (EthereumDataType.ADDRESS, EthereumDataType.BYTES):
await confirm_blob(
"confirm_typed_value",
title,
data,
description,
ask_pagination=True,
)
else:
await confirm_text(
"confirm_typed_value",
title,
data,
description,
)
def limit_str(s: str, limit: int = 16) -> str:
"""Shortens string to show the last <limit> characters."""
if len(s) <= limit + 2:
return s
return ".." + s[-limit:]