mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 04:18:10 +00:00
feat(cardano): allow external reward addresses in governance registrations
This commit is contained in:
parent
e2416bcec2
commit
a94cfa1a13
@ -369,13 +369,14 @@ message CardanoGovernanceRegistrationDelegation {
|
||||
* @embed
|
||||
*/
|
||||
message CardanoGovernanceRegistrationParametersType {
|
||||
optional bytes voting_public_key = 1;
|
||||
optional bytes voting_public_key = 1; // mutually exclusive with delegations
|
||||
repeated uint32 staking_path = 2;
|
||||
required CardanoAddressParametersType reward_address_parameters = 3;
|
||||
optional CardanoAddressParametersType reward_address_parameters = 3; // mutually exclusive with reward_address
|
||||
required uint64 nonce = 4;
|
||||
optional CardanoGovernanceRegistrationFormat format = 5 [default=CIP15];
|
||||
repeated CardanoGovernanceRegistrationDelegation delegations = 6; // mutually exclusive with voting_public_key; max 32 delegations
|
||||
optional uint64 voting_purpose = 7;
|
||||
optional string reward_address = 8; // mutually exclusive with reward_address_parameters
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,6 +231,16 @@ def validate_output_address_parameters(
|
||||
assert_params_cond(parameters.address_type in ADDRESS_TYPES_PAYMENT_KEY)
|
||||
|
||||
|
||||
def validate_governance_reward_address_parameters(
|
||||
parameters: messages.CardanoAddressParametersType,
|
||||
) -> None:
|
||||
validate_address_parameters(parameters)
|
||||
|
||||
# Despite the name, the address doesn't have to be a REWARD address.
|
||||
# see also validate_governance_reward_address
|
||||
assert_params_cond(parameters.address_type in ADDRESS_TYPES_SHELLEY)
|
||||
|
||||
|
||||
def assert_cond(condition: bool) -> None:
|
||||
if not condition:
|
||||
raise ProcessError("Invalid address")
|
||||
@ -287,6 +297,13 @@ def validate_reward_address(address: str, protocol_magic: int, network_id: int)
|
||||
)
|
||||
|
||||
|
||||
def validate_governance_reward_address(
|
||||
address: str, protocol_magic: int, network_id: int
|
||||
) -> None:
|
||||
address_type = _validate_and_get_type(address, protocol_magic, network_id)
|
||||
assert_cond(address_type in ADDRESS_TYPES_SHELLEY)
|
||||
|
||||
|
||||
def get_bytes_unsafe(address: str) -> bytes:
|
||||
try:
|
||||
address_bytes = bech32.decode_unsafe(address)
|
||||
|
@ -2,7 +2,7 @@ from micropython import const
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from trezor.crypto import hashlib
|
||||
from trezor.enums import CardanoAddressType, CardanoGovernanceRegistrationFormat
|
||||
from trezor.enums import CardanoGovernanceRegistrationFormat
|
||||
|
||||
from apps.common import cbor
|
||||
|
||||
@ -38,7 +38,11 @@ def assert_cond(condition: bool) -> None:
|
||||
raise wire.ProcessError("Invalid auxiliary data")
|
||||
|
||||
|
||||
def validate(auxiliary_data: messages.CardanoTxAuxiliaryData) -> None:
|
||||
def validate(
|
||||
auxiliary_data: messages.CardanoTxAuxiliaryData,
|
||||
protocol_magic: int,
|
||||
network_id: int,
|
||||
) -> None:
|
||||
fields_provided = 0
|
||||
if auxiliary_data.hash:
|
||||
fields_provided += 1
|
||||
@ -47,13 +51,17 @@ def validate(auxiliary_data: messages.CardanoTxAuxiliaryData) -> None:
|
||||
if auxiliary_data.governance_registration_parameters:
|
||||
fields_provided += 1
|
||||
_validate_governance_registration_parameters(
|
||||
auxiliary_data.governance_registration_parameters
|
||||
auxiliary_data.governance_registration_parameters,
|
||||
protocol_magic,
|
||||
network_id,
|
||||
)
|
||||
assert_cond(fields_provided == 1)
|
||||
|
||||
|
||||
def _validate_governance_registration_parameters(
|
||||
parameters: messages.CardanoGovernanceRegistrationParametersType,
|
||||
protocol_magic: int,
|
||||
network_id: int,
|
||||
) -> None:
|
||||
voting_key_fields_provided = 0
|
||||
if parameters.voting_public_key is not None:
|
||||
@ -67,9 +75,18 @@ def _validate_governance_registration_parameters(
|
||||
|
||||
assert_cond(SCHEMA_STAKING_ANY_ACCOUNT.match(parameters.staking_path))
|
||||
|
||||
address_parameters = parameters.reward_address_parameters
|
||||
assert_cond(address_parameters.address_type != CardanoAddressType.BYRON)
|
||||
addresses.validate_address_parameters(address_parameters)
|
||||
reward_address_fields_provided = 0
|
||||
if parameters.reward_address is not None:
|
||||
reward_address_fields_provided += 1
|
||||
addresses.validate_governance_reward_address(
|
||||
parameters.reward_address, protocol_magic, network_id
|
||||
)
|
||||
if parameters.reward_address_parameters:
|
||||
reward_address_fields_provided += 1
|
||||
addresses.validate_governance_reward_address_parameters(
|
||||
parameters.reward_address_parameters
|
||||
)
|
||||
assert_cond(reward_address_fields_provided == 1)
|
||||
|
||||
if parameters.voting_purpose is not None:
|
||||
assert_cond(parameters.format == CardanoGovernanceRegistrationFormat.CIP36)
|
||||
@ -144,6 +161,12 @@ async def _show_governance_registration(
|
||||
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,
|
||||
@ -241,9 +264,14 @@ def _get_signed_governance_registration_payload(
|
||||
|
||||
staking_key = derive_public_key(keychain, parameters.staking_path)
|
||||
|
||||
if parameters.reward_address:
|
||||
reward_address = addresses.get_bytes_unsafe(parameters.reward_address)
|
||||
else:
|
||||
address_parameters = parameters.reward_address_parameters
|
||||
assert address_parameters # _validate_governance_registration_parameters
|
||||
reward_address = addresses.derive_bytes(
|
||||
keychain,
|
||||
parameters.reward_address_parameters,
|
||||
address_parameters,
|
||||
protocol_magic,
|
||||
network_id,
|
||||
)
|
||||
|
@ -824,7 +824,7 @@ class Signer:
|
||||
data: messages.CardanoTxAuxiliaryData = await self.ctx.call(
|
||||
CardanoTxItemAck(), messages.CardanoTxAuxiliaryData
|
||||
)
|
||||
auxiliary_data.validate(data)
|
||||
auxiliary_data.validate(data, msg.protocol_magic, msg.network_id)
|
||||
|
||||
(
|
||||
auxiliary_data_hash,
|
||||
|
@ -1657,22 +1657,24 @@ if TYPE_CHECKING:
|
||||
class CardanoGovernanceRegistrationParametersType(protobuf.MessageType):
|
||||
voting_public_key: "bytes | None"
|
||||
staking_path: "list[int]"
|
||||
reward_address_parameters: "CardanoAddressParametersType"
|
||||
reward_address_parameters: "CardanoAddressParametersType | None"
|
||||
nonce: "int"
|
||||
format: "CardanoGovernanceRegistrationFormat"
|
||||
delegations: "list[CardanoGovernanceRegistrationDelegation]"
|
||||
voting_purpose: "int | None"
|
||||
reward_address: "str | None"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
reward_address_parameters: "CardanoAddressParametersType",
|
||||
nonce: "int",
|
||||
staking_path: "list[int] | None" = None,
|
||||
delegations: "list[CardanoGovernanceRegistrationDelegation] | None" = None,
|
||||
voting_public_key: "bytes | None" = None,
|
||||
reward_address_parameters: "CardanoAddressParametersType | None" = None,
|
||||
format: "CardanoGovernanceRegistrationFormat | None" = None,
|
||||
voting_purpose: "int | None" = None,
|
||||
reward_address: "str | None" = None,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
@ -64,7 +64,6 @@ REQUIRED_FIELDS_TOKEN_GROUP = ("policy_id", "tokens")
|
||||
REQUIRED_FIELDS_GOVERNANCE_REGISTRATION = (
|
||||
"staking_path",
|
||||
"nonce",
|
||||
"reward_address_parameters",
|
||||
)
|
||||
REQUIRED_FIELDS_GOVERNANCE_DELEGATION = ("voting_public_key", "weight")
|
||||
|
||||
@ -596,10 +595,13 @@ def parse_auxiliary_data(
|
||||
),
|
||||
staking_path=tools.parse_path(governance_registration["staking_path"]),
|
||||
nonce=governance_registration["nonce"],
|
||||
reward_address=governance_registration.get("reward_address"),
|
||||
reward_address_parameters=_parse_address_parameters(
|
||||
governance_registration["reward_address_parameters"],
|
||||
str(AUXILIARY_DATA_MISSING_FIELDS_ERROR),
|
||||
),
|
||||
)
|
||||
if "reward_address_parameters" in governance_registration
|
||||
else None,
|
||||
format=serialization_format,
|
||||
delegations=delegations,
|
||||
voting_purpose=voting_purpose,
|
||||
|
@ -2658,31 +2658,34 @@ class CardanoGovernanceRegistrationParametersType(protobuf.MessageType):
|
||||
FIELDS = {
|
||||
1: protobuf.Field("voting_public_key", "bytes", repeated=False, required=False, default=None),
|
||||
2: protobuf.Field("staking_path", "uint32", repeated=True, required=False, default=None),
|
||||
3: protobuf.Field("reward_address_parameters", "CardanoAddressParametersType", repeated=False, required=True),
|
||||
3: protobuf.Field("reward_address_parameters", "CardanoAddressParametersType", repeated=False, required=False, default=None),
|
||||
4: protobuf.Field("nonce", "uint64", repeated=False, required=True),
|
||||
5: protobuf.Field("format", "CardanoGovernanceRegistrationFormat", repeated=False, required=False, default=CardanoGovernanceRegistrationFormat.CIP15),
|
||||
6: protobuf.Field("delegations", "CardanoGovernanceRegistrationDelegation", repeated=True, required=False, default=None),
|
||||
7: protobuf.Field("voting_purpose", "uint64", repeated=False, required=False, default=None),
|
||||
8: protobuf.Field("reward_address", "string", repeated=False, required=False, default=None),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
reward_address_parameters: "CardanoAddressParametersType",
|
||||
nonce: "int",
|
||||
staking_path: Optional[Sequence["int"]] = None,
|
||||
delegations: Optional[Sequence["CardanoGovernanceRegistrationDelegation"]] = None,
|
||||
voting_public_key: Optional["bytes"] = None,
|
||||
reward_address_parameters: Optional["CardanoAddressParametersType"] = None,
|
||||
format: Optional["CardanoGovernanceRegistrationFormat"] = CardanoGovernanceRegistrationFormat.CIP15,
|
||||
voting_purpose: Optional["int"] = None,
|
||||
reward_address: Optional["str"] = None,
|
||||
) -> None:
|
||||
self.staking_path: Sequence["int"] = staking_path if staking_path is not None else []
|
||||
self.delegations: Sequence["CardanoGovernanceRegistrationDelegation"] = delegations if delegations is not None else []
|
||||
self.reward_address_parameters = reward_address_parameters
|
||||
self.nonce = nonce
|
||||
self.voting_public_key = voting_public_key
|
||||
self.reward_address_parameters = reward_address_parameters
|
||||
self.format = format
|
||||
self.voting_purpose = voting_purpose
|
||||
self.reward_address = reward_address
|
||||
|
||||
|
||||
class CardanoTxAuxiliaryData(protobuf.MessageType):
|
||||
|
Loading…
Reference in New Issue
Block a user