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, CardanoAddressType.ENTERPRISE_SCRIPT,
) )
ADDRESS_TYPES_PAYMENT = ADDRESS_TYPES_PAYMENT_KEY + ADDRESS_TYPES_PAYMENT_SCRIPT
_MIN_ADDRESS_BYTES_LENGTH = const(29) _MIN_ADDRESS_BYTES_LENGTH = const(29)
_MAX_ADDRESS_BYTES_LENGTH = const(65) _MAX_ADDRESS_BYTES_LENGTH = const(65)

View File

@ -2,7 +2,7 @@ from micropython import const
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from trezor.crypto import hashlib from trezor.crypto import hashlib
from trezor.enums import CardanoGovernanceRegistrationFormat from trezor.enums import CardanoAddressType, CardanoGovernanceRegistrationFormat
from apps.common import cbor from apps.common import cbor
@ -137,6 +137,14 @@ async def show(
await layout.show_auxiliary_data_hash(ctx, auxiliary_data_hash) 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( async def _show_governance_registration(
ctx: Context, ctx: Context,
keychain: seed.Keychain, keychain: seed.Keychain,
@ -146,6 +154,7 @@ async def _show_governance_registration(
should_show_details: bool, should_show_details: bool,
) -> None: ) -> None:
from .helpers import bech32 from .helpers import bech32
from .helpers.credential import Credential, should_show_credentials
for delegation in parameters.delegations: for delegation in parameters.delegations:
encoded_public_key = bech32.encode( encoded_public_key = bech32.encode(
@ -155,25 +164,34 @@ async def _show_governance_registration(
ctx, encoded_public_key, delegation.weight 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 encoded_public_key: str | None = None
if parameters.voting_public_key: if parameters.voting_public_key:
encoded_public_key = bech32.encode( encoded_public_key = bech32.encode(
bech32.HRP_GOVERNANCE_PUBLIC_KEY, parameters.voting_public_key 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 = ( voting_purpose: int | None = (
_get_voting_purpose_to_serialize(parameters) if should_show_details else None _get_voting_purpose_to_serialize(parameters) if should_show_details else None
) )
@ -182,7 +200,6 @@ async def _show_governance_registration(
ctx, ctx,
encoded_public_key, encoded_public_key,
parameters.staking_path, parameters.staking_path,
reward_address,
parameters.nonce, parameters.nonce,
voting_purpose, voting_purpose,
) )

View File

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