mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 12:28:09 +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
|
* @embed
|
||||||
*/
|
*/
|
||||||
message CardanoGovernanceRegistrationParametersType {
|
message CardanoGovernanceRegistrationParametersType {
|
||||||
optional bytes voting_public_key = 1;
|
optional bytes voting_public_key = 1; // mutually exclusive with delegations
|
||||||
repeated uint32 staking_path = 2;
|
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;
|
required uint64 nonce = 4;
|
||||||
optional CardanoGovernanceRegistrationFormat format = 5 [default=CIP15];
|
optional CardanoGovernanceRegistrationFormat format = 5 [default=CIP15];
|
||||||
repeated CardanoGovernanceRegistrationDelegation delegations = 6; // mutually exclusive with voting_public_key; max 32 delegations
|
repeated CardanoGovernanceRegistrationDelegation delegations = 6; // mutually exclusive with voting_public_key; max 32 delegations
|
||||||
optional uint64 voting_purpose = 7;
|
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)
|
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:
|
def assert_cond(condition: bool) -> None:
|
||||||
if not condition:
|
if not condition:
|
||||||
raise ProcessError("Invalid address")
|
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:
|
def get_bytes_unsafe(address: str) -> bytes:
|
||||||
try:
|
try:
|
||||||
address_bytes = bech32.decode_unsafe(address)
|
address_bytes = bech32.decode_unsafe(address)
|
||||||
|
@ -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 CardanoAddressType, CardanoGovernanceRegistrationFormat
|
from trezor.enums import CardanoGovernanceRegistrationFormat
|
||||||
|
|
||||||
from apps.common import cbor
|
from apps.common import cbor
|
||||||
|
|
||||||
@ -38,7 +38,11 @@ def assert_cond(condition: bool) -> None:
|
|||||||
raise wire.ProcessError("Invalid auxiliary data")
|
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
|
fields_provided = 0
|
||||||
if auxiliary_data.hash:
|
if auxiliary_data.hash:
|
||||||
fields_provided += 1
|
fields_provided += 1
|
||||||
@ -47,13 +51,17 @@ def validate(auxiliary_data: messages.CardanoTxAuxiliaryData) -> None:
|
|||||||
if auxiliary_data.governance_registration_parameters:
|
if auxiliary_data.governance_registration_parameters:
|
||||||
fields_provided += 1
|
fields_provided += 1
|
||||||
_validate_governance_registration_parameters(
|
_validate_governance_registration_parameters(
|
||||||
auxiliary_data.governance_registration_parameters
|
auxiliary_data.governance_registration_parameters,
|
||||||
|
protocol_magic,
|
||||||
|
network_id,
|
||||||
)
|
)
|
||||||
assert_cond(fields_provided == 1)
|
assert_cond(fields_provided == 1)
|
||||||
|
|
||||||
|
|
||||||
def _validate_governance_registration_parameters(
|
def _validate_governance_registration_parameters(
|
||||||
parameters: messages.CardanoGovernanceRegistrationParametersType,
|
parameters: messages.CardanoGovernanceRegistrationParametersType,
|
||||||
|
protocol_magic: int,
|
||||||
|
network_id: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
voting_key_fields_provided = 0
|
voting_key_fields_provided = 0
|
||||||
if parameters.voting_public_key is not None:
|
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))
|
assert_cond(SCHEMA_STAKING_ANY_ACCOUNT.match(parameters.staking_path))
|
||||||
|
|
||||||
address_parameters = parameters.reward_address_parameters
|
reward_address_fields_provided = 0
|
||||||
assert_cond(address_parameters.address_type != CardanoAddressType.BYRON)
|
if parameters.reward_address is not None:
|
||||||
addresses.validate_address_parameters(address_parameters)
|
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:
|
if parameters.voting_purpose is not None:
|
||||||
assert_cond(parameters.format == CardanoGovernanceRegistrationFormat.CIP36)
|
assert_cond(parameters.format == CardanoGovernanceRegistrationFormat.CIP36)
|
||||||
@ -144,6 +161,12 @@ async def _show_governance_registration(
|
|||||||
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(
|
reward_address = addresses.derive_human_readable(
|
||||||
keychain,
|
keychain,
|
||||||
parameters.reward_address_parameters,
|
parameters.reward_address_parameters,
|
||||||
@ -241,9 +264,14 @@ def _get_signed_governance_registration_payload(
|
|||||||
|
|
||||||
staking_key = derive_public_key(keychain, parameters.staking_path)
|
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(
|
reward_address = addresses.derive_bytes(
|
||||||
keychain,
|
keychain,
|
||||||
parameters.reward_address_parameters,
|
address_parameters,
|
||||||
protocol_magic,
|
protocol_magic,
|
||||||
network_id,
|
network_id,
|
||||||
)
|
)
|
||||||
|
@ -824,7 +824,7 @@ class Signer:
|
|||||||
data: messages.CardanoTxAuxiliaryData = await self.ctx.call(
|
data: messages.CardanoTxAuxiliaryData = await self.ctx.call(
|
||||||
CardanoTxItemAck(), messages.CardanoTxAuxiliaryData
|
CardanoTxItemAck(), messages.CardanoTxAuxiliaryData
|
||||||
)
|
)
|
||||||
auxiliary_data.validate(data)
|
auxiliary_data.validate(data, msg.protocol_magic, msg.network_id)
|
||||||
|
|
||||||
(
|
(
|
||||||
auxiliary_data_hash,
|
auxiliary_data_hash,
|
||||||
|
@ -1657,22 +1657,24 @@ if TYPE_CHECKING:
|
|||||||
class CardanoGovernanceRegistrationParametersType(protobuf.MessageType):
|
class CardanoGovernanceRegistrationParametersType(protobuf.MessageType):
|
||||||
voting_public_key: "bytes | None"
|
voting_public_key: "bytes | None"
|
||||||
staking_path: "list[int]"
|
staking_path: "list[int]"
|
||||||
reward_address_parameters: "CardanoAddressParametersType"
|
reward_address_parameters: "CardanoAddressParametersType | None"
|
||||||
nonce: "int"
|
nonce: "int"
|
||||||
format: "CardanoGovernanceRegistrationFormat"
|
format: "CardanoGovernanceRegistrationFormat"
|
||||||
delegations: "list[CardanoGovernanceRegistrationDelegation]"
|
delegations: "list[CardanoGovernanceRegistrationDelegation]"
|
||||||
voting_purpose: "int | None"
|
voting_purpose: "int | None"
|
||||||
|
reward_address: "str | None"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
reward_address_parameters: "CardanoAddressParametersType",
|
|
||||||
nonce: "int",
|
nonce: "int",
|
||||||
staking_path: "list[int] | None" = None,
|
staking_path: "list[int] | None" = None,
|
||||||
delegations: "list[CardanoGovernanceRegistrationDelegation] | None" = None,
|
delegations: "list[CardanoGovernanceRegistrationDelegation] | None" = None,
|
||||||
voting_public_key: "bytes | None" = None,
|
voting_public_key: "bytes | None" = None,
|
||||||
|
reward_address_parameters: "CardanoAddressParametersType | None" = None,
|
||||||
format: "CardanoGovernanceRegistrationFormat | None" = None,
|
format: "CardanoGovernanceRegistrationFormat | None" = None,
|
||||||
voting_purpose: "int | None" = None,
|
voting_purpose: "int | None" = None,
|
||||||
|
reward_address: "str | None" = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -64,7 +64,6 @@ REQUIRED_FIELDS_TOKEN_GROUP = ("policy_id", "tokens")
|
|||||||
REQUIRED_FIELDS_GOVERNANCE_REGISTRATION = (
|
REQUIRED_FIELDS_GOVERNANCE_REGISTRATION = (
|
||||||
"staking_path",
|
"staking_path",
|
||||||
"nonce",
|
"nonce",
|
||||||
"reward_address_parameters",
|
|
||||||
)
|
)
|
||||||
REQUIRED_FIELDS_GOVERNANCE_DELEGATION = ("voting_public_key", "weight")
|
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"]),
|
staking_path=tools.parse_path(governance_registration["staking_path"]),
|
||||||
nonce=governance_registration["nonce"],
|
nonce=governance_registration["nonce"],
|
||||||
|
reward_address=governance_registration.get("reward_address"),
|
||||||
reward_address_parameters=_parse_address_parameters(
|
reward_address_parameters=_parse_address_parameters(
|
||||||
governance_registration["reward_address_parameters"],
|
governance_registration["reward_address_parameters"],
|
||||||
str(AUXILIARY_DATA_MISSING_FIELDS_ERROR),
|
str(AUXILIARY_DATA_MISSING_FIELDS_ERROR),
|
||||||
),
|
)
|
||||||
|
if "reward_address_parameters" in governance_registration
|
||||||
|
else None,
|
||||||
format=serialization_format,
|
format=serialization_format,
|
||||||
delegations=delegations,
|
delegations=delegations,
|
||||||
voting_purpose=voting_purpose,
|
voting_purpose=voting_purpose,
|
||||||
|
@ -2658,31 +2658,34 @@ class CardanoGovernanceRegistrationParametersType(protobuf.MessageType):
|
|||||||
FIELDS = {
|
FIELDS = {
|
||||||
1: protobuf.Field("voting_public_key", "bytes", repeated=False, required=False, default=None),
|
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),
|
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),
|
4: protobuf.Field("nonce", "uint64", repeated=False, required=True),
|
||||||
5: protobuf.Field("format", "CardanoGovernanceRegistrationFormat", repeated=False, required=False, default=CardanoGovernanceRegistrationFormat.CIP15),
|
5: protobuf.Field("format", "CardanoGovernanceRegistrationFormat", repeated=False, required=False, default=CardanoGovernanceRegistrationFormat.CIP15),
|
||||||
6: protobuf.Field("delegations", "CardanoGovernanceRegistrationDelegation", repeated=True, required=False, default=None),
|
6: protobuf.Field("delegations", "CardanoGovernanceRegistrationDelegation", repeated=True, required=False, default=None),
|
||||||
7: protobuf.Field("voting_purpose", "uint64", repeated=False, 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__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
reward_address_parameters: "CardanoAddressParametersType",
|
|
||||||
nonce: "int",
|
nonce: "int",
|
||||||
staking_path: Optional[Sequence["int"]] = None,
|
staking_path: Optional[Sequence["int"]] = None,
|
||||||
delegations: Optional[Sequence["CardanoGovernanceRegistrationDelegation"]] = None,
|
delegations: Optional[Sequence["CardanoGovernanceRegistrationDelegation"]] = None,
|
||||||
voting_public_key: Optional["bytes"] = None,
|
voting_public_key: Optional["bytes"] = None,
|
||||||
|
reward_address_parameters: Optional["CardanoAddressParametersType"] = None,
|
||||||
format: Optional["CardanoGovernanceRegistrationFormat"] = CardanoGovernanceRegistrationFormat.CIP15,
|
format: Optional["CardanoGovernanceRegistrationFormat"] = CardanoGovernanceRegistrationFormat.CIP15,
|
||||||
voting_purpose: Optional["int"] = None,
|
voting_purpose: Optional["int"] = None,
|
||||||
|
reward_address: Optional["str"] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.staking_path: Sequence["int"] = staking_path if staking_path is not None else []
|
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.delegations: Sequence["CardanoGovernanceRegistrationDelegation"] = delegations if delegations is not None else []
|
||||||
self.reward_address_parameters = reward_address_parameters
|
|
||||||
self.nonce = nonce
|
self.nonce = nonce
|
||||||
self.voting_public_key = voting_public_key
|
self.voting_public_key = voting_public_key
|
||||||
|
self.reward_address_parameters = reward_address_parameters
|
||||||
self.format = format
|
self.format = format
|
||||||
self.voting_purpose = voting_purpose
|
self.voting_purpose = voting_purpose
|
||||||
|
self.reward_address = reward_address
|
||||||
|
|
||||||
|
|
||||||
class CardanoTxAuxiliaryData(protobuf.MessageType):
|
class CardanoTxAuxiliaryData(protobuf.MessageType):
|
||||||
|
Loading…
Reference in New Issue
Block a user