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/cardano/layout.py

989 lines
29 KiB

from typing import TYPE_CHECKING
from trezor import TR, ui
from trezor.enums import (
ButtonRequestType,
CardanoAddressType,
CardanoCertificateType,
CardanoNativeScriptType,
)
from trezor.strings import format_amount
from trezor.ui import layouts
from trezor.ui.layouts import confirm_metadata, confirm_properties
from apps.common.paths import address_n_to_str
from . import addresses
from .helpers import bech32, protocol_magics
from .helpers.utils import (
format_account_number,
format_asset_fingerprint,
format_optional_int,
format_stake_pool_id,
)
if TYPE_CHECKING:
from typing import Literal
from trezor import messages
from trezor.enums import CardanoNativeScriptHashDisplayFormat
from trezor.ui.layouts import PropertyType
from .helpers.credential import Credential
from .seed import Keychain
ADDRESS_TYPE_NAMES = {
CardanoAddressType.BYRON: TR.cardano__addr_legacy,
CardanoAddressType.BASE: TR.cardano__addr_base,
CardanoAddressType.BASE_SCRIPT_KEY: TR.cardano__addr_base,
CardanoAddressType.BASE_KEY_SCRIPT: TR.cardano__addr_base,
CardanoAddressType.BASE_SCRIPT_SCRIPT: TR.cardano__addr_base,
CardanoAddressType.POINTER: TR.cardano__addr_pointer,
CardanoAddressType.POINTER_SCRIPT: TR.cardano__addr_pointer,
CardanoAddressType.ENTERPRISE: TR.cardano__addr_enterprise,
CardanoAddressType.ENTERPRISE_SCRIPT: TR.cardano__addr_enterprise,
CardanoAddressType.REWARD: TR.cardano__addr_reward,
CardanoAddressType.REWARD_SCRIPT: TR.cardano__addr_reward,
}
SCRIPT_TYPE_NAMES = {
CardanoNativeScriptType.PUB_KEY: TR.cardano__script_key,
CardanoNativeScriptType.ALL: TR.cardano__script_all,
CardanoNativeScriptType.ANY: TR.cardano__script_any,
CardanoNativeScriptType.N_OF_K: TR.cardano__script_n_of_k,
CardanoNativeScriptType.INVALID_BEFORE: TR.cardano__script_invalid_before,
CardanoNativeScriptType.INVALID_HEREAFTER: TR.cardano__script_invalid_hereafter,
}
CERTIFICATE_TYPE_NAMES = {
CardanoCertificateType.STAKE_REGISTRATION: TR.cardano__stake_registration,
CardanoCertificateType.STAKE_DEREGISTRATION: TR.cardano__stake_deregistration,
CardanoCertificateType.STAKE_DELEGATION: TR.cardano__stake_delegation,
CardanoCertificateType.STAKE_POOL_REGISTRATION: TR.cardano__stake_pool_registration,
}
BRT_Other = ButtonRequestType.Other # global_import_cache
CVOTE_REWARD_ELIGIBILITY_WARNING = TR.cardano__reward_eligibility_warning
def format_coin_amount(amount: int, network_id: int) -> str:
from .helpers import network_ids
currency = "ADA" if network_ids.is_mainnet(network_id) else "tADA"
return f"{format_amount(amount, 6)} {currency}"
async def show_native_script(
script: messages.CardanoNativeScript,
indices: list[int] | None = None,
) -> None:
CNST = CardanoNativeScriptType # local_cache_global
script_type = script.type # local_cache_attribute
key_path = script.key_path # local_cache_attribute
key_hash = script.key_hash # local_cache_attribute
scripts = script.scripts # local_cache_attribute
script_heading = "Script"
if indices is None:
indices = []
if indices:
script_heading += " " + ".".join(str(i) for i in indices)
script_type_name_suffix = ""
if script_type == CNST.PUB_KEY:
if key_path:
script_type_name_suffix = "path"
elif key_hash:
script_type_name_suffix = "hash"
props: list[PropertyType] = [
(
f"{script_heading} - {SCRIPT_TYPE_NAMES[script_type]} {script_type_name_suffix}:",
None,
)
]
append = props.append # local_cache_attribute
if script_type == CNST.PUB_KEY:
assert key_hash is not None or key_path # validate_script
if key_hash:
append((None, bech32.encode(bech32.HRP_SHARED_KEY_HASH, key_hash)))
elif key_path:
append((address_n_to_str(key_path), None))
elif script_type == CNST.N_OF_K:
assert script.required_signatures_count is not None # validate_script
append(
(
TR.cardano__x_of_y_signatures_template.format(
script.required_signatures_count, len(scripts)
),
None,
)
)
elif script_type == CNST.INVALID_BEFORE:
assert script.invalid_before is not None # validate_script
append((str(script.invalid_before), None))
elif script_type == CNST.INVALID_HEREAFTER:
assert script.invalid_hereafter is not None # validate_script
append((str(script.invalid_hereafter), None))
if script_type in (
CNST.ALL,
CNST.ANY,
CNST.N_OF_K,
):
assert scripts # validate_script
append((TR.cardano__nested_scripts_template.format(len(scripts)), None))
await confirm_properties(
"verify_script",
TR.cardano__verify_script,
props,
br_code=BRT_Other,
)
for i, sub_script in enumerate(scripts):
await show_native_script(sub_script, indices + [i + 1])
async def show_script_hash(
script_hash: bytes,
display_format: CardanoNativeScriptHashDisplayFormat,
) -> None:
from trezor.enums import CardanoNativeScriptHashDisplayFormat
assert display_format in (
CardanoNativeScriptHashDisplayFormat.BECH32,
CardanoNativeScriptHashDisplayFormat.POLICY_ID,
)
if display_format == CardanoNativeScriptHashDisplayFormat.BECH32:
await confirm_properties(
"verify_script",
TR.cardano__verify_script,
(
(
TR.cardano__script_hash,
bech32.encode(bech32.HRP_SCRIPT_HASH, script_hash),
),
),
br_code=BRT_Other,
)
elif display_format == CardanoNativeScriptHashDisplayFormat.POLICY_ID:
await layouts.confirm_blob(
"verify_script",
TR.cardano__verify_script,
script_hash,
TR.cardano__policy_id,
br_code=BRT_Other,
)
async def show_tx_init(title: str) -> bool:
should_show_details = await layouts.should_show_more(
TR.cardano__confirm_transaction,
(
(
ui.DEMIBOLD,
title,
),
(ui.NORMAL, TR.cardano__choose_level_of_details),
),
TR.buttons__show_all,
confirm=TR.cardano__show_simple,
)
return should_show_details
async def confirm_input(input: messages.CardanoTxInput) -> None:
await confirm_properties(
"confirm_input",
TR.cardano__confirm_transaction,
(
(TR.cardano__input_id, input.prev_hash),
(TR.cardano__input_index, str(input.prev_index)),
),
br_code=BRT_Other,
)
async def confirm_sending(
ada_amount: int,
to: str,
output_type: Literal["address", "change", "collateral-return"],
network_id: int,
chunkify: bool,
) -> None:
if output_type == "address":
title = TR.cardano__sending
elif output_type == "change":
title = TR.cardano__change_output
elif output_type == "collateral-return":
title = TR.cardano__collateral_return
else:
raise RuntimeError # should be unreachable
await layouts.confirm_output(
to,
format_coin_amount(ada_amount, network_id),
title,
br_code=ButtonRequestType.Other,
chunkify=chunkify,
)
async def confirm_sending_token(policy_id: bytes, token: messages.CardanoToken) -> None:
assert token.amount is not None # _validate_token
await confirm_properties(
"confirm_token",
TR.cardano__confirm_transaction,
(
(
TR.cardano__asset_fingerprint,
format_asset_fingerprint(
policy_id=policy_id,
asset_name_bytes=token.asset_name_bytes,
),
),
(TR.cardano__amount_sent_decimals_unknown, format_amount(token.amount, 0)),
),
br_code=BRT_Other,
)
async def confirm_datum_hash(datum_hash: bytes) -> None:
await confirm_properties(
"confirm_datum_hash",
TR.cardano__confirm_transaction,
(
(
TR.cardano__datum_hash,
bech32.encode(bech32.HRP_OUTPUT_DATUM_HASH, datum_hash),
),
),
br_code=BRT_Other,
)
async def confirm_inline_datum(first_chunk: bytes, inline_datum_size: int) -> None:
await _confirm_data_chunk(
"confirm_inline_datum",
TR.cardano__inline_datum,
first_chunk,
inline_datum_size,
)
async def confirm_reference_script(
first_chunk: bytes, reference_script_size: int
) -> None:
await _confirm_data_chunk(
"confirm_reference_script",
TR.cardano__reference_script,
first_chunk,
reference_script_size,
)
async def _confirm_data_chunk(
br_type: str, title: str, first_chunk: bytes, data_size: int
) -> None:
MAX_DISPLAYED_SIZE = 56
displayed_bytes = first_chunk[:MAX_DISPLAYED_SIZE]
bytes_optional_plural = "byte" if data_size == 1 else "bytes"
props: list[tuple[str, bytes | None]] = [
(
f"{title} ({data_size} {bytes_optional_plural}):",
displayed_bytes,
)
]
if data_size > MAX_DISPLAYED_SIZE:
props.append(("...", None))
await confirm_properties(
br_type,
title=TR.cardano__confirm_transaction,
props=props,
br_code=BRT_Other,
)
async def show_credentials(
payment_credential: Credential,
stake_credential: Credential,
) -> None:
intro_text = TR.words__address
await _show_credential(payment_credential, intro_text, purpose="address")
await _show_credential(stake_credential, intro_text, purpose="address")
async def show_change_output_credentials(
payment_credential: Credential,
stake_credential: Credential,
) -> None:
intro_text = TR.cardano__intro_text_change
await _show_credential(payment_credential, intro_text, purpose="output")
await _show_credential(stake_credential, intro_text, purpose="output")
async def show_device_owned_output_credentials(
payment_credential: Credential,
stake_credential: Credential,
show_both_credentials: bool,
) -> None:
intro_text = TR.cardano__intro_text_owned_by_device
await _show_credential(payment_credential, intro_text, purpose="output")
if show_both_credentials:
await _show_credential(stake_credential, intro_text, purpose="output")
async def show_cvote_registration_payment_credentials(
payment_credential: Credential,
stake_credential: Credential,
show_both_credentials: bool,
show_payment_warning: bool,
) -> None:
intro_text = TR.cardano__intro_text_registration_payment
await _show_credential(
payment_credential, intro_text, purpose="cvote_reg_payment_address"
)
if show_both_credentials or show_payment_warning:
extra_text = CVOTE_REWARD_ELIGIBILITY_WARNING if show_payment_warning else None
await _show_credential(
stake_credential,
intro_text,
purpose="cvote_reg_payment_address",
extra_text=extra_text,
)
async def _show_credential(
credential: Credential,
intro_text: str,
purpose: Literal["address", "output", "cvote_reg_payment_address"],
extra_text: str | None = None,
) -> None:
title = {
"address": f"{ADDRESS_TYPE_NAMES[credential.address_type]} address",
"output": TR.cardano__confirm_transaction,
"cvote_reg_payment_address": TR.cardano__confirm_transaction,
}[purpose]
props: list[PropertyType] = []
append = props.append # local_cache_attribute
# Credential can be empty in case of enterprise address stake credential
# and reward address payment credential. In that case we don't want to
# show some of the "props".
if credential.is_set():
credential_title = credential.get_title()
# TODO: handle translation
append(
(
f"{intro_text} {credential.type_name} credential is a {credential_title}:",
None,
)
)
props.extend(credential.format())
if credential.is_unusual_path:
append((None, TR.cardano__unusual_path))
if credential.is_mismatch:
append((None, TR.cardano__credential_mismatch))
if credential.is_reward and purpose != "cvote_reg_payment_address":
# for cvote registrations, this is handled by extra_text at the end
append((TR.cardano__reward_address, None))
if credential.is_no_staking:
append(
(
f"{ADDRESS_TYPE_NAMES[credential.address_type]} {TR.cardano__address_no_staking}",
None,
)
)
if extra_text:
append((extra_text, None))
if len(props) > 0:
await confirm_properties(
"confirm_credential",
title,
props,
br_code=BRT_Other,
)
async def warn_path(path: list[int], title: str) -> None:
await layouts.confirm_path_warning(address_n_to_str(path), path_type=title)
async def warn_tx_output_contains_tokens(is_collateral_return: bool = False) -> None:
content = (
TR.cardano__collateral_output_contains_tokens
if is_collateral_return
else TR.cardano__transaction_output_contains_tokens
)
await confirm_metadata(
"confirm_tokens",
TR.cardano__confirm_transaction,
content,
br_code=BRT_Other,
)
async def warn_tx_contains_mint() -> None:
await confirm_metadata(
"confirm_tokens",
TR.cardano__confirm_transaction,
TR.cardano__transaction_contains_minting_or_burning,
br_code=BRT_Other,
)
async def warn_tx_output_no_datum() -> None:
await confirm_metadata(
"confirm_no_datum_hash",
TR.cardano__confirm_transaction,
TR.cardano__transaction_contains_script_address_no_datum,
br_code=BRT_Other,
)
async def warn_no_script_data_hash() -> None:
await confirm_metadata(
"confirm_no_script_data_hash",
TR.cardano__confirm_transaction,
TR.cardano__transaction_no_script_data_hash,
br_code=BRT_Other,
)
async def warn_no_collateral_inputs() -> None:
await confirm_metadata(
"confirm_no_collateral_inputs",
TR.cardano__confirm_transaction,
TR.cardano__transaction_no_collateral_input,
br_code=BRT_Other,
)
async def warn_unknown_total_collateral() -> None:
await layouts.show_warning(
"confirm_unknown_total_collateral",
TR.cardano__unknown_collateral_amount,
TR.cardano__check_all_items,
br_code=BRT_Other,
)
async def confirm_witness_request(
witness_path: list[int],
) -> None:
from . import seed
if seed.is_multisig_path(witness_path):
path_title = TR.cardano__multisig_path
elif seed.is_minting_path(witness_path):
path_title = TR.cardano__token_minting_path
else:
path_title = TR.cardano__path
await layouts.confirm_text(
"confirm_total",
TR.cardano__confirm_transaction,
address_n_to_str(witness_path),
TR.cardano__sign_tx_path_template.format(path_title),
BRT_Other,
)
async def confirm_tx(
fee: int,
network_id: int,
protocol_magic: int,
ttl: int | None,
validity_interval_start: int | None,
total_collateral: int | None,
is_network_id_verifiable: bool,
tx_hash: bytes | None,
) -> None:
props: list[PropertyType] = [
(TR.cardano__transaction_fee, format_coin_amount(fee, network_id)),
]
append = props.append # local_cache_attribute
if total_collateral is not None:
append(
(
TR.cardano__total_collateral,
format_coin_amount(total_collateral, network_id),
)
)
if is_network_id_verifiable:
append(
(
f"{TR.cardano__network} {protocol_magics.to_ui_string(protocol_magic)}",
None,
)
)
append(
(
f"{TR.cardano__valid_since} {format_optional_int(validity_interval_start)}",
None,
)
)
append((f"{TR.cardano__ttl} {format_optional_int(ttl)}", None))
if tx_hash:
append((TR.cardano__transaction_id, tx_hash))
await confirm_properties(
"confirm_total",
TR.cardano__confirm_transaction,
props,
hold=True,
br_code=BRT_Other,
)
async def confirm_certificate(certificate: messages.CardanoTxCertificate) -> None:
# stake pool registration requires custom confirmation logic not covered
# in this call
assert certificate.type != CardanoCertificateType.STAKE_POOL_REGISTRATION
props: list[PropertyType] = [
(TR.cardano__confirm, CERTIFICATE_TYPE_NAMES[certificate.type]),
_format_stake_credential(
certificate.path, certificate.script_hash, certificate.key_hash
),
]
if certificate.type == CardanoCertificateType.STAKE_DELEGATION:
assert certificate.pool is not None # validate_certificate
props.append((TR.cardano__to_pool, format_stake_pool_id(certificate.pool)))
await confirm_properties(
"confirm_certificate",
TR.cardano__confirm_transaction,
props,
br_code=BRT_Other,
)
async def confirm_stake_pool_parameters(
pool_parameters: messages.CardanoPoolParametersType,
network_id: int,
) -> None:
margin_percentage = (
100.0 * pool_parameters.margin_numerator / pool_parameters.margin_denominator
)
percentage_formatted = str(float(margin_percentage)).rstrip("0").rstrip(".")
await confirm_properties(
"confirm_pool_registration",
TR.cardano__confirm_transaction,
(
(
TR.cardano__stake_pool_registration_pool_id,
format_stake_pool_id(pool_parameters.pool_id),
),
(TR.cardano__pool_reward_account, pool_parameters.reward_account),
(
f"{TR.cardano__pledge}: {format_coin_amount(pool_parameters.pledge, network_id)}\n"
+ f"{TR.cardano__cost}: {format_coin_amount(pool_parameters.cost, network_id)}\n"
+ f"{TR.cardano__margin}: {percentage_formatted}%",
None,
),
),
br_code=BRT_Other,
)
async def confirm_stake_pool_owner(
keychain: Keychain,
owner: messages.CardanoPoolOwner,
protocol_magic: int,
network_id: int,
) -> None:
from trezor import messages
props: list[tuple[str, str | None]] = []
if owner.staking_key_path:
props.append((TR.cardano__pool_owner, address_n_to_str(owner.staking_key_path)))
props.append(
(
addresses.derive_human_readable(
keychain,
messages.CardanoAddressParametersType(
address_type=CardanoAddressType.REWARD,
address_n=owner.staking_key_path,
),
protocol_magic,
network_id,
),
None,
)
)
else:
assert owner.staking_key_hash is not None # validate_pool_owners
props.append(
(
TR.cardano__pool_owner,
addresses.derive_human_readable(
keychain,
messages.CardanoAddressParametersType(
address_type=CardanoAddressType.REWARD,
staking_key_hash=owner.staking_key_hash,
),
protocol_magic,
network_id,
),
)
)
await confirm_properties(
"confirm_pool_owners",
TR.cardano__confirm_transaction,
props,
br_code=BRT_Other,
)
async def confirm_stake_pool_metadata(
metadata: messages.CardanoPoolMetadataType | None,
) -> None:
if metadata is None:
await confirm_properties(
"confirm_pool_metadata",
TR.cardano__confirm_transaction,
((TR.cardano__anonymous_pool, None),),
br_code=BRT_Other,
)
return
await confirm_properties(
"confirm_pool_metadata",
TR.cardano__confirm_transaction,
(
(TR.cardano__pool_metadata_url, metadata.url),
(TR.cardano__pool_metadata_hash, metadata.hash),
),
br_code=BRT_Other,
)
async def confirm_stake_pool_registration_final(
protocol_magic: int,
ttl: int | None,
validity_interval_start: int | None,
) -> None:
await confirm_properties(
"confirm_pool_final",
TR.cardano__confirm_transaction,
(
(TR.cardano__confirm_signing_stake_pool, None),
(TR.cardano__network, protocol_magics.to_ui_string(protocol_magic)),
(
TR.cardano__valid_since,
format_optional_int(validity_interval_start),
),
(TR.cardano__ttl, format_optional_int(ttl)),
),
hold=True,
br_code=BRT_Other,
)
async def confirm_withdrawal(
withdrawal: messages.CardanoTxWithdrawal,
address_bytes: bytes,
network_id: int,
) -> None:
address_type_name = (
TR.cardano__script_reward if withdrawal.script_hash else TR.cardano__reward
)
address = addresses.encode_human_readable(address_bytes)
props: list[PropertyType] = [
(
TR.cardano__withdrawal_for_address_template.format(address_type_name),
address,
),
]
if withdrawal.path:
props.append(
_format_stake_credential(
withdrawal.path, withdrawal.script_hash, withdrawal.key_hash
)
)
props.append(
(f"{TR.words__amount}:", format_coin_amount(withdrawal.amount, network_id))
)
await confirm_properties(
"confirm_withdrawal",
TR.cardano__confirm_transaction,
props,
br_code=BRT_Other,
)
def _format_stake_credential(
path: list[int], script_hash: bytes | None, key_hash: bytes | None
) -> tuple[str, str]:
from .helpers.paths import ADDRESS_INDEX_PATH_INDEX, RECOMMENDED_ADDRESS_INDEX
if path:
account_number = format_account_number(path)
address_index = path[ADDRESS_INDEX_PATH_INDEX]
if address_index == RECOMMENDED_ADDRESS_INDEX:
return (
TR.cardano__for_account_template.format(account_number),
address_n_to_str(path),
)
return (
TR.cardano__for_account_and_index_template.format(
account_number, address_index
),
address_n_to_str(path),
)
elif key_hash:
return (
TR.cardano__for_key_hash,
bech32.encode(bech32.HRP_STAKE_KEY_HASH, key_hash),
)
elif script_hash:
return (
TR.cardano__for_script,
bech32.encode(bech32.HRP_SCRIPT_HASH, script_hash),
)
else:
# should be unreachable unless there's a bug in validation
raise ValueError
async def confirm_cvote_registration_delegation(
public_key: str,
weight: int,
) -> None:
props: list[PropertyType] = [
(TR.cardano__vote_key_registration, None),
(TR.cardano__delegating_to, public_key),
]
if weight is not None:
props.append((TR.cardano__weight, str(weight)))
await confirm_properties(
"confirm_cvote_registration_delegation",
title=TR.cardano__confirm_transaction,
props=props,
br_code=ButtonRequestType.Other,
)
async def confirm_cvote_registration_payment_address(
payment_address: str,
should_show_payment_warning: bool,
) -> None:
props = [
(TR.cardano__vote_key_registration, None),
(TR.cardano__rewards_go_to, payment_address),
]
if should_show_payment_warning:
props.append((CVOTE_REWARD_ELIGIBILITY_WARNING, None))
await confirm_properties(
"confirm_cvote_registration_payment_address",
title=TR.cardano__confirm_transaction,
props=props,
br_code=ButtonRequestType.Other,
)
async def confirm_cvote_registration(
vote_public_key: str | None,
staking_path: list[int],
nonce: int,
voting_purpose: int | None,
) -> None:
props: list[PropertyType] = [(TR.cardano__vote_key_registration, None)]
if vote_public_key is not None:
props.append((TR.cardano__vote_public_key, vote_public_key))
props.extend(
[
(
f"{TR.cardano__staking_key_for_account} {format_account_number(staking_path)}:",
address_n_to_str(staking_path),
),
(TR.cardano__nonce, str(nonce)),
]
)
if voting_purpose is not None:
props.append(
(
TR.cardano__voting_purpose,
(
TR.cardano__catalyst
if voting_purpose == 0
else f"{voting_purpose} ({TR.cardano__other})"
),
)
)
await confirm_properties(
"confirm_cvote_registration",
title=TR.cardano__confirm_transaction,
props=props,
br_code=ButtonRequestType.Other,
)
async def show_auxiliary_data_hash(auxiliary_data_hash: bytes) -> None:
await confirm_properties(
"confirm_auxiliary_data",
TR.cardano__confirm_transaction,
((TR.cardano__auxiliary_data_hash, auxiliary_data_hash),),
br_code=BRT_Other,
)
async def confirm_token_minting(policy_id: bytes, token: messages.CardanoToken) -> None:
assert token.mint_amount is not None # _validate_token
await confirm_properties(
"confirm_mint",
TR.cardano__confirm_transaction,
(
(
TR.cardano__asset_fingerprint,
format_asset_fingerprint(
policy_id,
token.asset_name_bytes,
),
),
(
(
TR.cardano__amount_minted_decimals_unknown
if token.mint_amount >= 0
else TR.cardano__amount_burned_decimals_unknown
),
format_amount(token.mint_amount, 0),
),
),
br_code=BRT_Other,
)
async def warn_tx_network_unverifiable() -> None:
await confirm_metadata(
"warning_no_outputs",
TR.cardano__warning,
TR.cardano__no_output_tx,
br_code=BRT_Other,
)
async def confirm_script_data_hash(script_data_hash: bytes) -> None:
await confirm_properties(
"confirm_script_data_hash",
TR.cardano__confirm_transaction,
(
(
TR.cardano__script_data_hash,
bech32.encode(bech32.HRP_SCRIPT_DATA_HASH, script_data_hash),
),
),
br_code=BRT_Other,
)
async def confirm_collateral_input(
collateral_input: messages.CardanoTxCollateralInput,
) -> None:
await confirm_properties(
"confirm_collateral_input",
TR.cardano__confirm_transaction,
(
(TR.cardano__collateral_input_id, collateral_input.prev_hash),
(
TR.cardano__collateral_input_index,
str(collateral_input.prev_index),
),
),
br_code=BRT_Other,
)
async def confirm_reference_input(
reference_input: messages.CardanoTxReferenceInput,
) -> None:
await confirm_properties(
"confirm_reference_input",
TR.cardano__confirm_transaction,
(
(TR.cardano__reference_input_id, reference_input.prev_hash),
(TR.cardano__reference_input_index, str(reference_input.prev_index)),
),
br_code=BRT_Other,
)
async def confirm_required_signer(
required_signer: messages.CardanoTxRequiredSigner,
) -> None:
assert (
required_signer.key_hash is not None or required_signer.key_path
) # _validate_required_signer
formatted_signer = (
bech32.encode(bech32.HRP_REQUIRED_SIGNER_KEY_HASH, required_signer.key_hash)
if required_signer.key_hash is not None
else address_n_to_str(required_signer.key_path)
)
await confirm_properties(
"confirm_required_signer",
TR.cardano__confirm_transaction,
((TR.cardano__required_signer, formatted_signer),),
br_code=BRT_Other,
)
async def show_cardano_address(
address_parameters: messages.CardanoAddressParametersType,
address: str,
protocol_magic: int,
chunkify: bool,
) -> None:
CAT = CardanoAddressType # local_cache_global
network_name = None
if not protocol_magics.is_mainnet(protocol_magic):
network_name = protocol_magics.to_ui_string(protocol_magic)
path = None
account = ADDRESS_TYPE_NAMES[address_parameters.address_type]
if address_parameters.address_type in (
CAT.BYRON,
CAT.BASE,
CAT.BASE_KEY_SCRIPT,
CAT.POINTER,
CAT.ENTERPRISE,
CAT.REWARD,
):
if address_parameters.address_n:
path = address_n_to_str(address_parameters.address_n)
elif address_parameters.address_n_staking:
path = address_n_to_str(address_parameters.address_n_staking)
await layouts.show_address(
address,
path=path,
account=account,
network=network_name,
chunkify=chunkify,
)