From 44dc417c0e0609e4e562fbf6f3eef8f9fed1d670 Mon Sep 17 00:00:00 2001 From: gabrielkerekes Date: Wed, 18 Oct 2023 11:43:41 +0200 Subject: [PATCH] feat(solana): add `get_address` --- common/protob/messages-solana.proto | 20 + common/protob/messages.proto | 2 + common/tests/fixtures/solana/get_address.json | 32 ++ core/src/all_modules.py | 2 + core/src/apps/solana/get_address.py | 37 ++ core/src/apps/workflow_handlers.py | 2 + core/src/trezor/enums/MessageType.py | 2 + core/src/trezor/enums/__init__.py | 2 + core/src/trezor/messages.py | 32 ++ python/src/trezorlib/cli/solana.py | 16 + python/src/trezorlib/messages.py | 36 ++ python/src/trezorlib/solana.py | 16 + rust/trezor-client/src/messages/generated.rs | 2 + .../src/protos/generated/messages.rs | 62 +-- .../src/protos/generated/messages_solana.rs | 370 +++++++++++++++++- tests/device_tests/solana/test_address.py | 40 ++ 16 files changed, 647 insertions(+), 26 deletions(-) create mode 100644 common/tests/fixtures/solana/get_address.json create mode 100644 core/src/apps/solana/get_address.py create mode 100644 tests/device_tests/solana/test_address.py diff --git a/common/protob/messages-solana.proto b/common/protob/messages-solana.proto index c6e99b226..5fa509225 100644 --- a/common/protob/messages-solana.proto +++ b/common/protob/messages-solana.proto @@ -22,3 +22,23 @@ message SolanaPublicKey { required bytes public_key = 1; } +/** + * Request: Ask device for Solana address + * @start + * @next SolanaAddress + * @next Failure + */ +message SolanaGetAddress { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional bool show_display = 2; // optionally show on display before sending the result + optional bool chunkify = 3; // display the address in chunks of 4 characters +} + +/** + * Response: Contains a Solana address derived from device private seed + * @end + */ +message SolanaAddress { + required string address = 1; // Solana address as Base58 encoded string +} + diff --git a/common/protob/messages.proto b/common/protob/messages.proto index 6f1f24774..91aef61c6 100644 --- a/common/protob/messages.proto +++ b/common/protob/messages.proto @@ -366,4 +366,6 @@ enum MessageType { // Solana MessageType_SolanaGetPublicKey = 900 [(wire_in) = true]; MessageType_SolanaPublicKey = 901 [(wire_out) = true]; + MessageType_SolanaGetAddress = 902 [(wire_in) = true]; + MessageType_SolanaAddress = 903 [(wire_out) = true]; } diff --git a/common/tests/fixtures/solana/get_address.json b/common/tests/fixtures/solana/get_address.json new file mode 100644 index 000000000..05e4fd333 --- /dev/null +++ b/common/tests/fixtures/solana/get_address.json @@ -0,0 +1,32 @@ +{ + "setup": { + "mnemonic": "all all all all all all all all all all all all", + "passphrase": "" + }, + "tests": [ + { + "parameters": { + "path": "m/44'/501'" + }, + "result": { + "expected_address": "zZqNUDNijfbMXFy2wVCdJSm9MeMfxBMdxBqseSuiSW6" + } + }, + { + "parameters": { + "path": "m/44'/501'/0'" + }, + "result": { + "expected_address": "4UR47Kp4FxGJiJZZGSPAzXqRgMmZ27oVfGhHoLmcHakE" + } + }, + { + "parameters": { + "path": "m/44'/501'/0'/0'" + }, + "result": { + "expected_address": "14CCvQzQzHCVgZM3j9soPnXuJXh1RmCfwLVUcdfbZVBS" + } + } + ] +} diff --git a/core/src/all_modules.py b/core/src/all_modules.py index 6789ca9d1..6779184d6 100644 --- a/core/src/all_modules.py +++ b/core/src/all_modules.py @@ -683,6 +683,8 @@ if not utils.BITCOIN_ONLY: import apps.ripple.sign_tx apps.solana import apps.solana + apps.solana.get_address + import apps.solana.get_address apps.solana.get_public_key import apps.solana.get_public_key apps.stellar diff --git a/core/src/apps/solana/get_address.py b/core/src/apps/solana/get_address.py new file mode 100644 index 000000000..b543b8245 --- /dev/null +++ b/core/src/apps/solana/get_address.py @@ -0,0 +1,37 @@ +from typing import TYPE_CHECKING + +from trezor.crypto import base58 + +from apps.common.keychain import with_slip44_keychain + +from . import CURVE, PATTERNS, SLIP44_ID + +if TYPE_CHECKING: + from trezor.messages import SolanaAddress, SolanaGetAddress + + from apps.common.keychain import Keychain + + +@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE) +async def get_address( + msg: SolanaGetAddress, + keychain: Keychain, +) -> SolanaAddress: + from trezor.messages import SolanaAddress + from trezor.ui.layouts import show_address + + from apps.common import paths + + from .get_public_key import derive_public_key + + public_key = derive_public_key(keychain, msg.address_n) + address = base58.encode(public_key) + + if msg.show_display: + await show_address( + address, + path=paths.address_n_to_str(msg.address_n), + chunkify=bool(msg.chunkify), + ) + + return SolanaAddress(address=address) diff --git a/core/src/apps/workflow_handlers.py b/core/src/apps/workflow_handlers.py index 3cc4c996a..69b72638c 100644 --- a/core/src/apps/workflow_handlers.py +++ b/core/src/apps/workflow_handlers.py @@ -193,6 +193,8 @@ def _find_message_handler_module(msg_type: int) -> str: # solana if msg_type == MessageType.SolanaGetPublicKey: return "apps.solana.get_public_key" + if msg_type == MessageType.SolanaGetAddress: + return "apps.solana.get_address" raise ValueError diff --git a/core/src/trezor/enums/MessageType.py b/core/src/trezor/enums/MessageType.py index 59266e80b..0ea3565db 100644 --- a/core/src/trezor/enums/MessageType.py +++ b/core/src/trezor/enums/MessageType.py @@ -238,3 +238,5 @@ if not utils.BITCOIN_ONLY: WebAuthnRemoveResidentCredential = 803 SolanaGetPublicKey = 900 SolanaPublicKey = 901 + SolanaGetAddress = 902 + SolanaAddress = 903 diff --git a/core/src/trezor/enums/__init__.py b/core/src/trezor/enums/__init__.py index 039e37a07..bca4a8502 100644 --- a/core/src/trezor/enums/__init__.py +++ b/core/src/trezor/enums/__init__.py @@ -256,6 +256,8 @@ if TYPE_CHECKING: WebAuthnRemoveResidentCredential = 803 SolanaGetPublicKey = 900 SolanaPublicKey = 901 + SolanaGetAddress = 902 + SolanaAddress = 903 class FailureType(IntEnum): UnexpectedMessage = 1 diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index 1ec0226ea..b007187e9 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -5225,6 +5225,38 @@ if TYPE_CHECKING: def is_type_of(cls, msg: Any) -> TypeGuard["SolanaPublicKey"]: return isinstance(msg, cls) + class SolanaGetAddress(protobuf.MessageType): + address_n: "list[int]" + show_display: "bool | None" + chunkify: "bool | None" + + def __init__( + self, + *, + address_n: "list[int] | None" = None, + show_display: "bool | None" = None, + chunkify: "bool | None" = None, + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["SolanaGetAddress"]: + return isinstance(msg, cls) + + class SolanaAddress(protobuf.MessageType): + address: "str" + + def __init__( + self, + *, + address: "str", + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["SolanaAddress"]: + return isinstance(msg, cls) + class StellarAsset(protobuf.MessageType): type: "StellarAssetType" code: "str | None" diff --git a/python/src/trezorlib/cli/solana.py b/python/src/trezorlib/cli/solana.py index 9c70ec922..c33e94662 100644 --- a/python/src/trezorlib/cli/solana.py +++ b/python/src/trezorlib/cli/solana.py @@ -29,3 +29,19 @@ def get_public_key( """Get Solana public key.""" address_n = tools.parse_path(address) return solana.get_public_key(client, address_n, show_display) + + +@cli.command() +@click.option("-n", "--address", default=DEFAULT_PATH, help=PATH_HELP) +@click.option("-d", "--show-display", is_flag=True) +@click.option("-C", "--chunkify", is_flag=True) +@with_client +def get_address( + client: "TrezorClient", + address: str, + show_display: bool, + chunkify: bool, +) -> messages.SolanaAddress: + """Get Solana address.""" + address_n = tools.parse_path(address) + return solana.get_address(client, address_n, show_display, chunkify) diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index 859abf98d..0d8999682 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -264,6 +264,8 @@ class MessageType(IntEnum): WebAuthnRemoveResidentCredential = 803 SolanaGetPublicKey = 900 SolanaPublicKey = 901 + SolanaGetAddress = 902 + SolanaAddress = 903 class FailureType(IntEnum): @@ -6678,6 +6680,40 @@ class SolanaPublicKey(protobuf.MessageType): self.public_key = public_key +class SolanaGetAddress(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 902 + FIELDS = { + 1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None), + 2: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), + 3: protobuf.Field("chunkify", "bool", repeated=False, required=False, default=None), + } + + def __init__( + self, + *, + address_n: Optional[Sequence["int"]] = None, + show_display: Optional["bool"] = None, + chunkify: Optional["bool"] = None, + ) -> None: + self.address_n: Sequence["int"] = address_n if address_n is not None else [] + self.show_display = show_display + self.chunkify = chunkify + + +class SolanaAddress(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 903 + FIELDS = { + 1: protobuf.Field("address", "string", repeated=False, required=True), + } + + def __init__( + self, + *, + address: "str", + ) -> None: + self.address = address + + class StellarAsset(protobuf.MessageType): MESSAGE_WIRE_TYPE = None FIELDS = { diff --git a/python/src/trezorlib/solana.py b/python/src/trezorlib/solana.py index 2f9b090b7..7f3bda818 100644 --- a/python/src/trezorlib/solana.py +++ b/python/src/trezorlib/solana.py @@ -17,3 +17,19 @@ def get_public_key( return client.call( messages.SolanaGetPublicKey(address_n=address_n, show_display=show_display) ) + + +@expect(messages.SolanaAddress) +def get_address( + client: "TrezorClient", + address_n: List[int], + show_display: bool, + chunkify: bool = False, +) -> "MessageType": + return client.call( + messages.SolanaGetAddress( + address_n=address_n, + show_display=show_display, + chunkify=chunkify, + ) + ) diff --git a/rust/trezor-client/src/messages/generated.rs b/rust/trezor-client/src/messages/generated.rs index e69648653..d170fc946 100644 --- a/rust/trezor-client/src/messages/generated.rs +++ b/rust/trezor-client/src/messages/generated.rs @@ -81,6 +81,8 @@ trezor_message_impl! { DebugLinkResetDebugEvents => MessageType_DebugLinkResetDebugEvents, SolanaGetPublicKey => MessageType_SolanaGetPublicKey, SolanaPublicKey => MessageType_SolanaPublicKey, + SolanaGetAddress => MessageType_SolanaGetAddress, + SolanaAddress => MessageType_SolanaAddress, } #[cfg(feature = "binance")] diff --git a/rust/trezor-client/src/protos/generated/messages.rs b/rust/trezor-client/src/protos/generated/messages.rs index dad070532..22e5f383b 100644 --- a/rust/trezor-client/src/protos/generated/messages.rs +++ b/rust/trezor-client/src/protos/generated/messages.rs @@ -498,6 +498,10 @@ pub enum MessageType { MessageType_SolanaGetPublicKey = 900, // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_SolanaPublicKey) MessageType_SolanaPublicKey = 901, + // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_SolanaGetAddress) + MessageType_SolanaGetAddress = 902, + // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_SolanaAddress) + MessageType_SolanaAddress = 903, } impl ::protobuf::Enum for MessageType { @@ -744,6 +748,8 @@ impl ::protobuf::Enum for MessageType { 803 => ::std::option::Option::Some(MessageType::MessageType_WebAuthnRemoveResidentCredential), 900 => ::std::option::Option::Some(MessageType::MessageType_SolanaGetPublicKey), 901 => ::std::option::Option::Some(MessageType::MessageType_SolanaPublicKey), + 902 => ::std::option::Option::Some(MessageType::MessageType_SolanaGetAddress), + 903 => ::std::option::Option::Some(MessageType::MessageType_SolanaAddress), _ => ::std::option::Option::None } } @@ -985,6 +991,8 @@ impl ::protobuf::Enum for MessageType { "MessageType_WebAuthnRemoveResidentCredential" => ::std::option::Option::Some(MessageType::MessageType_WebAuthnRemoveResidentCredential), "MessageType_SolanaGetPublicKey" => ::std::option::Option::Some(MessageType::MessageType_SolanaGetPublicKey), "MessageType_SolanaPublicKey" => ::std::option::Option::Some(MessageType::MessageType_SolanaPublicKey), + "MessageType_SolanaGetAddress" => ::std::option::Option::Some(MessageType::MessageType_SolanaGetAddress), + "MessageType_SolanaAddress" => ::std::option::Option::Some(MessageType::MessageType_SolanaAddress), _ => ::std::option::Option::None } } @@ -1225,6 +1233,8 @@ impl ::protobuf::Enum for MessageType { MessageType::MessageType_WebAuthnRemoveResidentCredential, MessageType::MessageType_SolanaGetPublicKey, MessageType::MessageType_SolanaPublicKey, + MessageType::MessageType_SolanaGetAddress, + MessageType::MessageType_SolanaAddress, ]; } @@ -1471,6 +1481,8 @@ impl ::protobuf::EnumFull for MessageType { MessageType::MessageType_WebAuthnRemoveResidentCredential => 232, MessageType::MessageType_SolanaGetPublicKey => 233, MessageType::MessageType_SolanaPublicKey => 234, + MessageType::MessageType_SolanaGetAddress => 235, + MessageType::MessageType_SolanaAddress => 236, }; Self::enum_descriptor().value_by_index(index) } @@ -1520,7 +1532,7 @@ pub mod exts { static file_descriptor_proto_data: &'static [u8] = b"\ \n\x0emessages.proto\x12\x12hw.trezor.messages\x1a\x20google/protobuf/de\ - scriptor.proto*\xa6Q\n\x0bMessageType\x12(\n\x16MessageType_Initialize\ + scriptor.proto*\xf5Q\n\x0bMessageType\x12(\n\x16MessageType_Initialize\ \x10\0\x1a\x0c\x80\xa6\x1d\x01\xb0\xb5\x18\x01\x90\xb5\x18\x01\x12\x1e\n\ \x10MessageType_Ping\x10\x01\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x12\ %\n\x13MessageType_Success\x10\x02\x1a\x0c\x80\xa6\x1d\x01\xa8\xb5\x18\ @@ -1785,29 +1797,31 @@ static file_descriptor_proto_data: &'static [u8] = b"\ ntial\x10\xa2\x06\x1a\x04\x90\xb5\x18\x01\x127\n,MessageType_WebAuthnRem\ oveResidentCredential\x10\xa3\x06\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMess\ ageType_SolanaGetPublicKey\x10\x84\x07\x1a\x04\x90\xb5\x18\x01\x12&\n\ - \x1bMessageType_SolanaPublicKey\x10\x85\x07\x1a\x04\x98\xb5\x18\x01\x1a\ - \x04\xc8\xf3\x18\x01\"\x04\x08Z\x10\\\"\x04\x08r\x10z\"\x06\x08\xac\x02\ - \x10\xb0\x02\"\x06\x08\xb5\x02\x10\xb8\x02:<\n\x07wire_in\x18\xd2\x86\ - \x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x06wireIn:>\n\ - \x08wire_out\x18\xd3\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValue\ - OptionsR\x07wireOut:G\n\rwire_debug_in\x18\xd4\x86\x03\x20\x01(\x08\x12!\ - .google.protobuf.EnumValueOptionsR\x0bwireDebugIn:I\n\x0ewire_debug_out\ - \x18\xd5\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0c\ - wireDebugOut:@\n\twire_tiny\x18\xd6\x86\x03\x20\x01(\x08\x12!.google.pro\ - tobuf.EnumValueOptionsR\x08wireTiny:L\n\x0fwire_bootloader\x18\xd7\x86\ - \x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0ewireBootload\ - er:C\n\x0bwire_no_fsm\x18\xd8\x86\x03\x20\x01(\x08\x12!.google.protobuf.\ - EnumValueOptionsR\twireNoFsm:F\n\x0cbitcoin_only\x18\xe0\xd4\x03\x20\x01\ - (\x08\x12!.google.protobuf.EnumValueOptionsR\x0bbitcoinOnly:U\n\x17has_b\ - itcoin_only_values\x18\xb9\x8e\x03\x20\x01(\x08\x12\x1c.google.protobuf.\ - EnumOptionsR\x14hasBitcoinOnlyValues:T\n\x14experimental_message\x18\xa1\ - \x96\x03\x20\x01(\x08\x12\x1f.google.protobuf.MessageOptionsR\x13experim\ - entalMessage:>\n\twire_type\x18\xa2\x96\x03\x20\x01(\r\x12\x1f.google.pr\ - otobuf.MessageOptionsR\x08wireType:N\n\x12experimental_field\x18\x89\x9e\ - \x03\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x11experimentalF\ - ield:U\n\x17include_in_bitcoin_only\x18\xe0\xd4\x03\x20\x01(\x08\x12\x1c\ - .google.protobuf.FileOptionsR\x14includeInBitcoinOnlyB8\n#com.satoshilab\ - s.trezor.lib.protobufB\rTrezorMessage\x80\xa6\x1d\x01\ + \x1bMessageType_SolanaPublicKey\x10\x85\x07\x1a\x04\x98\xb5\x18\x01\x12'\ + \n\x1cMessageType_SolanaGetAddress\x10\x86\x07\x1a\x04\x90\xb5\x18\x01\ + \x12$\n\x19MessageType_SolanaAddress\x10\x87\x07\x1a\x04\x98\xb5\x18\x01\ + \x1a\x04\xc8\xf3\x18\x01\"\x04\x08Z\x10\\\"\x04\x08r\x10z\"\x06\x08\xac\ + \x02\x10\xb0\x02\"\x06\x08\xb5\x02\x10\xb8\x02:<\n\x07wire_in\x18\xd2\ + \x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x06wireIn:>\ + \n\x08wire_out\x18\xd3\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumVal\ + ueOptionsR\x07wireOut:G\n\rwire_debug_in\x18\xd4\x86\x03\x20\x01(\x08\ + \x12!.google.protobuf.EnumValueOptionsR\x0bwireDebugIn:I\n\x0ewire_debug\ + _out\x18\xd5\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\ + \x0cwireDebugOut:@\n\twire_tiny\x18\xd6\x86\x03\x20\x01(\x08\x12!.google\ + .protobuf.EnumValueOptionsR\x08wireTiny:L\n\x0fwire_bootloader\x18\xd7\ + \x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0ewireBoot\ + loader:C\n\x0bwire_no_fsm\x18\xd8\x86\x03\x20\x01(\x08\x12!.google.proto\ + buf.EnumValueOptionsR\twireNoFsm:F\n\x0cbitcoin_only\x18\xe0\xd4\x03\x20\ + \x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0bbitcoinOnly:U\n\x17h\ + as_bitcoin_only_values\x18\xb9\x8e\x03\x20\x01(\x08\x12\x1c.google.proto\ + buf.EnumOptionsR\x14hasBitcoinOnlyValues:T\n\x14experimental_message\x18\ + \xa1\x96\x03\x20\x01(\x08\x12\x1f.google.protobuf.MessageOptionsR\x13exp\ + erimentalMessage:>\n\twire_type\x18\xa2\x96\x03\x20\x01(\r\x12\x1f.googl\ + e.protobuf.MessageOptionsR\x08wireType:N\n\x12experimental_field\x18\x89\ + \x9e\x03\x20\x01(\x08\x12\x1d.google.protobuf.FieldOptionsR\x11experimen\ + talField:U\n\x17include_in_bitcoin_only\x18\xe0\xd4\x03\x20\x01(\x08\x12\ + \x1c.google.protobuf.FileOptionsR\x14includeInBitcoinOnlyB8\n#com.satosh\ + ilabs.trezor.lib.protobufB\rTrezorMessage\x80\xa6\x1d\x01\ "; /// `FileDescriptorProto` object which was a source for this generated file diff --git a/rust/trezor-client/src/protos/generated/messages_solana.rs b/rust/trezor-client/src/protos/generated/messages_solana.rs index 87b2398d1..73d1d4935 100644 --- a/rust/trezor-client/src/protos/generated/messages_solana.rs +++ b/rust/trezor-client/src/protos/generated/messages_solana.rs @@ -348,12 +348,376 @@ impl ::protobuf::reflect::ProtobufValue for SolanaPublicKey { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } +// @@protoc_insertion_point(message:hw.trezor.messages.solana.SolanaGetAddress) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct SolanaGetAddress { + // message fields + // @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaGetAddress.address_n) + pub address_n: ::std::vec::Vec, + // @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaGetAddress.show_display) + pub show_display: ::std::option::Option, + // @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaGetAddress.chunkify) + pub chunkify: ::std::option::Option, + // special fields + // @@protoc_insertion_point(special_field:hw.trezor.messages.solana.SolanaGetAddress.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a SolanaGetAddress { + fn default() -> &'a SolanaGetAddress { + ::default_instance() + } +} + +impl SolanaGetAddress { + pub fn new() -> SolanaGetAddress { + ::std::default::Default::default() + } + + // optional bool show_display = 2; + + pub fn show_display(&self) -> bool { + self.show_display.unwrap_or(false) + } + + pub fn clear_show_display(&mut self) { + self.show_display = ::std::option::Option::None; + } + + pub fn has_show_display(&self) -> bool { + self.show_display.is_some() + } + + // Param is passed by value, moved + pub fn set_show_display(&mut self, v: bool) { + self.show_display = ::std::option::Option::Some(v); + } + + // optional bool chunkify = 3; + + pub fn chunkify(&self) -> bool { + self.chunkify.unwrap_or(false) + } + + pub fn clear_chunkify(&mut self) { + self.chunkify = ::std::option::Option::None; + } + + pub fn has_chunkify(&self) -> bool { + self.chunkify.is_some() + } + + // Param is passed by value, moved + pub fn set_chunkify(&mut self, v: bool) { + self.chunkify = ::std::option::Option::Some(v); + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(3); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>( + "address_n", + |m: &SolanaGetAddress| { &m.address_n }, + |m: &mut SolanaGetAddress| { &mut m.address_n }, + )); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "show_display", + |m: &SolanaGetAddress| { &m.show_display }, + |m: &mut SolanaGetAddress| { &mut m.show_display }, + )); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "chunkify", + |m: &SolanaGetAddress| { &m.chunkify }, + |m: &mut SolanaGetAddress| { &mut m.chunkify }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "SolanaGetAddress", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for SolanaGetAddress { + const NAME: &'static str = "SolanaGetAddress"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + is.read_repeated_packed_uint32_into(&mut self.address_n)?; + }, + 8 => { + self.address_n.push(is.read_uint32()?); + }, + 16 => { + self.show_display = ::std::option::Option::Some(is.read_bool()?); + }, + 24 => { + self.chunkify = ::std::option::Option::Some(is.read_bool()?); + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + for value in &self.address_n { + my_size += ::protobuf::rt::uint32_size(1, *value); + }; + if let Some(v) = self.show_display { + my_size += 1 + 1; + } + if let Some(v) = self.chunkify { + my_size += 1 + 1; + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + for v in &self.address_n { + os.write_uint32(1, *v)?; + }; + if let Some(v) = self.show_display { + os.write_bool(2, v)?; + } + if let Some(v) = self.chunkify { + os.write_bool(3, v)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> SolanaGetAddress { + SolanaGetAddress::new() + } + + fn clear(&mut self) { + self.address_n.clear(); + self.show_display = ::std::option::Option::None; + self.chunkify = ::std::option::Option::None; + self.special_fields.clear(); + } + + fn default_instance() -> &'static SolanaGetAddress { + static instance: SolanaGetAddress = SolanaGetAddress { + address_n: ::std::vec::Vec::new(), + show_display: ::std::option::Option::None, + chunkify: ::std::option::Option::None, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for SolanaGetAddress { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("SolanaGetAddress").unwrap()).clone() + } +} + +impl ::std::fmt::Display for SolanaGetAddress { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SolanaGetAddress { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:hw.trezor.messages.solana.SolanaAddress) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct SolanaAddress { + // message fields + // @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaAddress.address) + pub address: ::std::option::Option<::std::string::String>, + // special fields + // @@protoc_insertion_point(special_field:hw.trezor.messages.solana.SolanaAddress.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a SolanaAddress { + fn default() -> &'a SolanaAddress { + ::default_instance() + } +} + +impl SolanaAddress { + pub fn new() -> SolanaAddress { + ::std::default::Default::default() + } + + // required string address = 1; + + pub fn address(&self) -> &str { + match self.address.as_ref() { + Some(v) => v, + None => "", + } + } + + pub fn clear_address(&mut self) { + self.address = ::std::option::Option::None; + } + + pub fn has_address(&self) -> bool { + self.address.is_some() + } + + // Param is passed by value, moved + pub fn set_address(&mut self, v: ::std::string::String) { + self.address = ::std::option::Option::Some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_address(&mut self) -> &mut ::std::string::String { + if self.address.is_none() { + self.address = ::std::option::Option::Some(::std::string::String::new()); + } + self.address.as_mut().unwrap() + } + + // Take field + pub fn take_address(&mut self) -> ::std::string::String { + self.address.take().unwrap_or_else(|| ::std::string::String::new()) + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "address", + |m: &SolanaAddress| { &m.address }, + |m: &mut SolanaAddress| { &mut m.address }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "SolanaAddress", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for SolanaAddress { + const NAME: &'static str = "SolanaAddress"; + + fn is_initialized(&self) -> bool { + if self.address.is_none() { + return false; + } + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + self.address = ::std::option::Option::Some(is.read_string()?); + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if let Some(v) = self.address.as_ref() { + my_size += ::protobuf::rt::string_size(1, &v); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if let Some(v) = self.address.as_ref() { + os.write_string(1, v)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> SolanaAddress { + SolanaAddress::new() + } + + fn clear(&mut self) { + self.address = ::std::option::Option::None; + self.special_fields.clear(); + } + + fn default_instance() -> &'static SolanaAddress { + static instance: SolanaAddress = SolanaAddress { + address: ::std::option::Option::None, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for SolanaAddress { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("SolanaAddress").unwrap()).clone() + } +} + +impl ::std::fmt::Display for SolanaAddress { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SolanaAddress { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + static file_descriptor_proto_data: &'static [u8] = b"\ \n\x15messages-solana.proto\x12\x19hw.trezor.messages.solana\x1a\x15mess\ ages-common.proto\"T\n\x12SolanaGetPublicKey\x12\x1b\n\taddress_n\x18\ \x01\x20\x03(\rR\x08addressN\x12!\n\x0cshow_display\x18\x02\x20\x01(\x08\ R\x0bshowDisplay\"0\n\x0fSolanaPublicKey\x12\x1d\n\npublic_key\x18\x01\ - \x20\x02(\x0cR\tpublicKey\ + \x20\x02(\x0cR\tpublicKey\"n\n\x10SolanaGetAddress\x12\x1b\n\taddress_n\ + \x18\x01\x20\x03(\rR\x08addressN\x12!\n\x0cshow_display\x18\x02\x20\x01(\ + \x08R\x0bshowDisplay\x12\x1a\n\x08chunkify\x18\x03\x20\x01(\x08R\x08chun\ + kify\")\n\rSolanaAddress\x12\x18\n\x07address\x18\x01\x20\x02(\tR\x07add\ + ress\ "; /// `FileDescriptorProto` object which was a source for this generated file @@ -372,9 +736,11 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { let mut deps = ::std::vec::Vec::with_capacity(1); deps.push(super::messages_common::file_descriptor().clone()); - let mut messages = ::std::vec::Vec::with_capacity(2); + let mut messages = ::std::vec::Vec::with_capacity(4); messages.push(SolanaGetPublicKey::generated_message_descriptor_data()); messages.push(SolanaPublicKey::generated_message_descriptor_data()); + messages.push(SolanaGetAddress::generated_message_descriptor_data()); + messages.push(SolanaAddress::generated_message_descriptor_data()); let mut enums = ::std::vec::Vec::with_capacity(0); ::protobuf::reflect::GeneratedFileDescriptor::new_generated( file_descriptor_proto(), diff --git a/tests/device_tests/solana/test_address.py b/tests/device_tests/solana/test_address.py new file mode 100644 index 000000000..0a14a02e3 --- /dev/null +++ b/tests/device_tests/solana/test_address.py @@ -0,0 +1,40 @@ +# This file is part of the Trezor project. +# +# Copyright (C) 2012-2023 SatoshiLabs and contributors +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the License along with this library. +# If not, see . + +import pytest + +from trezorlib.debuglink import TrezorClientDebugLink as Client +from trezorlib.solana import get_address +from trezorlib.tools import parse_path + +from ...common import parametrize_using_common_fixtures + +pytestmark = [ + pytest.mark.altcoin, + pytest.mark.solana, + pytest.mark.skip_t1, +] + + +@parametrize_using_common_fixtures( + "solana/get_address.json", +) +def test_solana_get_address(client: Client, parameters, result): + actual_result = get_address( + client, address_n=parse_path(parameters["path"]), show_display=True + ) + + assert actual_result.address == result["expected_address"]