1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-03 12:00:59 +00:00

feat(cardano): show governance registration reward address credentials

This commit is contained in:
David Misiak 2022-12-10 18:25:44 +01:00 committed by matejcik
parent a94cfa1a13
commit ac58c1c25b
3 changed files with 108 additions and 37 deletions

View File

@ -44,6 +44,8 @@ ADDRESS_TYPES_PAYMENT_SCRIPT = (
CardanoAddressType.ENTERPRISE_SCRIPT,
)
ADDRESS_TYPES_PAYMENT = ADDRESS_TYPES_PAYMENT_KEY + ADDRESS_TYPES_PAYMENT_SCRIPT
_MIN_ADDRESS_BYTES_LENGTH = const(29)
_MAX_ADDRESS_BYTES_LENGTH = const(65)

View File

@ -2,7 +2,7 @@ from micropython import const
from typing import TYPE_CHECKING
from trezor.crypto import hashlib
from trezor.enums import CardanoGovernanceRegistrationFormat
from trezor.enums import CardanoAddressType, CardanoGovernanceRegistrationFormat
from apps.common import cbor
@ -137,6 +137,14 @@ async def show(
await layout.show_auxiliary_data_hash(ctx, auxiliary_data_hash)
def _should_show_payment_warning(address_type: CardanoAddressType) -> bool:
# For non-payment governance reward addresses, we show a warning that the address is not
# actually eligible for rewards. https://github.com/cardano-foundation/CIPs/pull/373
# However, the registration is otherwise valid, so we allow such addresses since we don't
# want to prevent the user from voting just because they use an outdated SW wallet.
return address_type not in addresses.ADDRESS_TYPES_PAYMENT
async def _show_governance_registration(
ctx: Context,
keychain: seed.Keychain,
@ -146,6 +154,7 @@ async def _show_governance_registration(
should_show_details: bool,
) -> None:
from .helpers import bech32
from .helpers.credential import Credential, should_show_credentials
for delegation in parameters.delegations:
encoded_public_key = bech32.encode(
@ -155,25 +164,34 @@ async def _show_governance_registration(
ctx, encoded_public_key, delegation.weight
)
if parameters.reward_address:
show_payment_warning = _should_show_payment_warning(
addresses.get_type(addresses.get_bytes_unsafe(parameters.reward_address))
)
await layout.confirm_governance_registration_reward_address(
ctx, parameters.reward_address, show_payment_warning
)
else:
address_parameters = parameters.reward_address_parameters
assert address_parameters # _validate_governance_registration_parameters
show_both_credentials = should_show_credentials(address_parameters)
show_payment_warning = _should_show_payment_warning(
address_parameters.address_type
)
await layout.show_governance_registration_reward_credentials(
ctx,
Credential.payment_credential(address_parameters),
Credential.stake_credential(address_parameters),
show_both_credentials,
show_payment_warning,
)
encoded_public_key: str | None = None
if parameters.voting_public_key:
encoded_public_key = bech32.encode(
bech32.HRP_GOVERNANCE_PUBLIC_KEY, parameters.voting_public_key
)
if parameters.reward_address:
reward_address = parameters.reward_address
else:
assert (
parameters.reward_address_parameters
) # _validate_governance_registration_parameters
reward_address = addresses.derive_human_readable(
keychain,
parameters.reward_address_parameters,
protocol_magic,
network_id,
)
voting_purpose: int | None = (
_get_voting_purpose_to_serialize(parameters) if should_show_details else None
)
@ -182,7 +200,6 @@ async def _show_governance_registration(
ctx,
encoded_public_key,
parameters.staking_path,
reward_address,
parameters.nonce,
voting_purpose,
)

View File

@ -68,6 +68,10 @@ CERTIFICATE_TYPE_NAMES = {
BRT_Other = ButtonRequestType.Other # global_import_cache
GOVERNANCE_REWARD_ELIGIBILITY_WARNING = (
"Warning: The address is not a payment address, it is not eligible for rewards."
)
def format_coin_amount(amount: int, network_id: int) -> str:
from .helpers import network_ids
@ -327,8 +331,8 @@ async def show_credentials(
stake_credential: Credential,
) -> None:
intro_text = "Address"
await _show_credential(ctx, payment_credential, intro_text, is_output=False)
await _show_credential(ctx, stake_credential, intro_text, is_output=False)
await _show_credential(ctx, payment_credential, intro_text, purpose="address")
await _show_credential(ctx, stake_credential, intro_text, purpose="address")
async def show_change_output_credentials(
@ -337,8 +341,8 @@ async def show_change_output_credentials(
stake_credential: Credential,
) -> None:
intro_text = "The following address is a change address. Its"
await _show_credential(ctx, payment_credential, intro_text, is_output=True)
await _show_credential(ctx, stake_credential, intro_text, is_output=True)
await _show_credential(ctx, payment_credential, intro_text, purpose="output")
await _show_credential(ctx, stake_credential, intro_text, purpose="output")
async def show_device_owned_output_credentials(
@ -348,22 +352,47 @@ async def show_device_owned_output_credentials(
show_both_credentials: bool,
) -> None:
intro_text = "The following address is owned by this device. Its"
await _show_credential(ctx, payment_credential, intro_text, is_output=True)
await _show_credential(ctx, payment_credential, intro_text, purpose="output")
if show_both_credentials:
await _show_credential(ctx, stake_credential, intro_text, is_output=True)
await _show_credential(ctx, stake_credential, intro_text, purpose="output")
async def show_governance_registration_reward_credentials(
ctx: Context,
payment_credential: Credential,
stake_credential: Credential,
show_both_credentials: bool,
show_payment_warning: bool,
) -> None:
intro_text = "The governance registration reward address is owned by this device. Its"
await _show_credential(
ctx, payment_credential, intro_text, purpose="gov_reg_reward_address"
)
if show_both_credentials or show_payment_warning:
extra_text = (
GOVERNANCE_REWARD_ELIGIBILITY_WARNING if show_payment_warning else None
)
await _show_credential(
ctx,
stake_credential,
intro_text,
purpose="gov_reg_reward_address",
extra_text=extra_text,
)
async def _show_credential(
ctx: Context,
credential: Credential,
intro_text: str,
is_output: bool,
purpose: Literal["address", "output", "gov_reg_reward_address"],
extra_text: str | None = None,
) -> None:
title = (
"Confirm transaction"
if is_output
else f"{ADDRESS_TYPE_NAMES[credential.address_type]} address"
)
title = {
"address": f"{ADDRESS_TYPE_NAMES[credential.address_type]} address",
"output": "Confirm transaction",
"gov_reg_reward_address": "Confirm transaction",
}[purpose]
props: list[PropertyType] = []
append = props.append # local_cache_attribute
@ -385,7 +414,8 @@ async def _show_credential(
append((None, "Path is unusual."))
if credential.is_mismatch:
append((None, "Credential doesn't match payment credential."))
if credential.is_reward:
if credential.is_reward and purpose != "gov_reg_reward_address":
# for governance registrations, this is handled by extra_text at the end
append(("Address is a reward address.", None))
if credential.is_no_staking:
append(
@ -395,13 +425,17 @@ async def _show_credential(
)
)
await confirm_properties(
ctx,
"confirm_credential",
title,
props,
br_code=BRT_Other,
)
if extra_text:
append((extra_text, None))
if len(props) > 0:
await confirm_properties(
ctx,
"confirm_credential",
title,
props,
br_code=BRT_Other,
)
async def warn_path(ctx: Context, path: list[int], title: str) -> None:
@ -762,11 +796,30 @@ async def confirm_governance_registration_delegation(
)
async def confirm_governance_registration_reward_address(
ctx: Context,
reward_address: str,
should_show_payment_warning: bool,
) -> None:
props = [
("Governance voting key registration", None),
("Rewards go to:", reward_address),
]
if should_show_payment_warning:
props.append((GOVERNANCE_REWARD_ELIGIBILITY_WARNING, None))
await confirm_properties(
ctx,
"confirm_governance_registration_reward_address",
title="Confirm transaction",
props=props,
br_code=ButtonRequestType.Other,
)
async def confirm_governance_registration(
ctx: Context,
public_key: str | None,
staking_path: list[int],
reward_address: str,
nonce: int,
voting_purpose: int | None,
) -> None:
@ -779,7 +832,6 @@ async def confirm_governance_registration(
f"Staking key for account {format_account_number(staking_path)}:",
address_n_to_str(staking_path),
),
("Rewards go to:", reward_address),
("Nonce:", str(nonce)),
]
)