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:
parent
a94cfa1a13
commit
ac58c1c25b
@ -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)
|
||||||
|
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
@ -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)),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user