mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-08-02 20:08:31 +00:00
feat(solana): add additional info with token account
This commit is contained in:
parent
e3eb913b58
commit
79b04d72a3
@ -42,6 +42,23 @@ message SolanaAddress {
|
|||||||
required string address = 1; // Solana address as Base58 encoded string
|
required string address = 1; // Solana address as Base58 encoded string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @embed
|
||||||
|
*/
|
||||||
|
message SolanaTxTokenAccountInfo {
|
||||||
|
required string base_address = 1;
|
||||||
|
required string token_program = 2;
|
||||||
|
required string token_mint = 3;
|
||||||
|
required string token_account = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @embed
|
||||||
|
*/
|
||||||
|
message SolanaTxAdditionalInfo {
|
||||||
|
repeated SolanaTxTokenAccountInfo token_accounts_infos = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: Ask device to sign a Solana transaction
|
* Request: Ask device to sign a Solana transaction
|
||||||
* @start
|
* @start
|
||||||
@ -51,6 +68,7 @@ message SolanaAddress {
|
|||||||
message SolanaSignTx {
|
message SolanaSignTx {
|
||||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key to sign with
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key to sign with
|
||||||
required bytes serialized_tx = 2; // serialized tx to be signed
|
required bytes serialized_tx = 2; // serialized tx to be signed
|
||||||
|
optional SolanaTxAdditionalInfo additional_info = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -693,8 +693,12 @@ if not utils.BITCOIN_ONLY:
|
|||||||
import apps.solana.get_public_key
|
import apps.solana.get_public_key
|
||||||
apps.solana.layout
|
apps.solana.layout
|
||||||
import apps.solana.layout
|
import apps.solana.layout
|
||||||
|
apps.solana.predefined_transaction
|
||||||
|
import apps.solana.predefined_transaction
|
||||||
apps.solana.sign_tx
|
apps.solana.sign_tx
|
||||||
import apps.solana.sign_tx
|
import apps.solana.sign_tx
|
||||||
|
apps.solana.token_account
|
||||||
|
import apps.solana.token_account
|
||||||
apps.solana.transaction
|
apps.solana.transaction
|
||||||
import apps.solana.transaction
|
import apps.solana.transaction
|
||||||
apps.solana.transaction.instruction
|
apps.solana.transaction.instruction
|
||||||
|
@ -15,14 +15,7 @@ from apps.common.paths import address_n_to_str
|
|||||||
from .types import AddressType
|
from .types import AddressType
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.ui.layouts import PropertyType
|
from .transaction.instructions import Instruction, SystemProgramTransferInstruction
|
||||||
|
|
||||||
from .transaction.instructions import (
|
|
||||||
AssociatedTokenAccountProgramCreateInstruction,
|
|
||||||
Instruction,
|
|
||||||
SystemProgramTransferInstruction,
|
|
||||||
TokenProgramTransferCheckedInstruction,
|
|
||||||
)
|
|
||||||
from .types import AddressReference
|
from .types import AddressReference
|
||||||
|
|
||||||
|
|
||||||
@ -285,28 +278,30 @@ async def confirm_system_transfer(
|
|||||||
|
|
||||||
|
|
||||||
async def confirm_token_transfer(
|
async def confirm_token_transfer(
|
||||||
create_token_account_instruction: AssociatedTokenAccountProgramCreateInstruction
|
destination_account: bytes,
|
||||||
| None,
|
token_account: bytes,
|
||||||
transfer_token_instruction: TokenProgramTransferCheckedInstruction,
|
token_mint: bytes,
|
||||||
|
amount: int,
|
||||||
|
decimals: int,
|
||||||
fee: int,
|
fee: int,
|
||||||
signer_path: list[int],
|
signer_path: list[int],
|
||||||
blockhash: bytes,
|
blockhash: bytes,
|
||||||
):
|
):
|
||||||
recipient_props: list[PropertyType] = [
|
await confirm_value(
|
||||||
("", base58.encode(transfer_token_instruction.destination_account[0]))
|
title="Recipient",
|
||||||
]
|
value=base58.encode(destination_account),
|
||||||
if create_token_account_instruction is not None:
|
description="",
|
||||||
recipient_props.append(("(account will be created)", ""))
|
br_type="confirm_recipient",
|
||||||
|
br_code=ButtonRequestType.ConfirmOutput,
|
||||||
await confirm_properties(
|
verb="CONTINUE",
|
||||||
"confirm_recipient",
|
info_items=(("Associated token account:", base58.encode(token_account)),)
|
||||||
"Recipient",
|
if token_account != destination_account
|
||||||
recipient_props,
|
else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
await confirm_value(
|
await confirm_value(
|
||||||
title="Token address",
|
title="Token address",
|
||||||
value=base58.encode(transfer_token_instruction.token_mint[0]),
|
value=base58.encode(token_mint),
|
||||||
description="",
|
description="",
|
||||||
br_type="confirm_token_address",
|
br_type="confirm_token_address",
|
||||||
br_code=ButtonRequestType.ConfirmOutput,
|
br_code=ButtonRequestType.ConfirmOutput,
|
||||||
@ -314,8 +309,8 @@ async def confirm_token_transfer(
|
|||||||
)
|
)
|
||||||
|
|
||||||
await confirm_custom_transaction(
|
await confirm_custom_transaction(
|
||||||
transfer_token_instruction.amount,
|
amount,
|
||||||
transfer_token_instruction.decimals,
|
decimals,
|
||||||
"[TOKEN]",
|
"[TOKEN]",
|
||||||
fee,
|
fee,
|
||||||
signer_path,
|
signer_path,
|
||||||
|
191
core/src/apps/solana/predefined_transaction.py
Normal file
191
core/src/apps/solana/predefined_transaction.py
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from trezor.crypto import base58
|
||||||
|
|
||||||
|
from .transaction import Transaction
|
||||||
|
from .transaction.instructions import (
|
||||||
|
AssociatedTokenAccountProgramCreateInstruction,
|
||||||
|
Instruction,
|
||||||
|
Token2022ProgramTransferCheckedInstruction,
|
||||||
|
TokenProgramTransferCheckedInstruction,
|
||||||
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from trezor.messages import SolanaTxAdditionalInfo
|
||||||
|
|
||||||
|
TransferTokenInstruction = (
|
||||||
|
TokenProgramTransferCheckedInstruction
|
||||||
|
| Token2022ProgramTransferCheckedInstruction
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_token_transfer_instructions(
|
||||||
|
instructions: list[Instruction],
|
||||||
|
) -> list[TransferTokenInstruction]:
|
||||||
|
return [
|
||||||
|
instruction
|
||||||
|
for instruction in instructions
|
||||||
|
if TokenProgramTransferCheckedInstruction.is_type_of(instruction)
|
||||||
|
or Token2022ProgramTransferCheckedInstruction.is_type_of(instruction)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_create_associated_token_account_instructions(
|
||||||
|
instructions: list[Instruction],
|
||||||
|
) -> list[AssociatedTokenAccountProgramCreateInstruction]:
|
||||||
|
return [
|
||||||
|
instruction
|
||||||
|
for instruction in instructions
|
||||||
|
if AssociatedTokenAccountProgramCreateInstruction.is_type_of(instruction)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def is_predefined_token_transfer(
|
||||||
|
instructions: list[Instruction],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Checks that the transaction consists of one or zero create token account instructions
|
||||||
|
and one or more transfer token instructions. Also checks that the token program, token mint
|
||||||
|
and destination in the instructions are the same. I.e. valid instructions can be:
|
||||||
|
|
||||||
|
[transfer]
|
||||||
|
[transfer, *transfer]
|
||||||
|
[create account, transfer]
|
||||||
|
[create account, transfer, *transfer]
|
||||||
|
"""
|
||||||
|
create_token_account_instructions = (
|
||||||
|
get_create_associated_token_account_instructions(instructions)
|
||||||
|
)
|
||||||
|
transfer_token_instructions = get_token_transfer_instructions(instructions)
|
||||||
|
|
||||||
|
if len(create_token_account_instructions) + len(transfer_token_instructions) != len(
|
||||||
|
instructions
|
||||||
|
):
|
||||||
|
# there are also other instructions
|
||||||
|
return False
|
||||||
|
|
||||||
|
if len(create_token_account_instructions) > 1:
|
||||||
|
# there is more than one create token account instruction
|
||||||
|
return False
|
||||||
|
|
||||||
|
if (
|
||||||
|
len(create_token_account_instructions) == 1
|
||||||
|
and instructions[0] != create_token_account_instructions[0]
|
||||||
|
):
|
||||||
|
# create account instruction has to be the first instruction
|
||||||
|
return False
|
||||||
|
|
||||||
|
if len(transfer_token_instructions) == 0:
|
||||||
|
# there are no transfer token instructions
|
||||||
|
return False
|
||||||
|
|
||||||
|
token_program = transfer_token_instructions[0].program_id
|
||||||
|
token_mint = transfer_token_instructions[0].token_mint[0]
|
||||||
|
token_account = transfer_token_instructions[0].destination_account[0]
|
||||||
|
owner = transfer_token_instructions[0].owner[0]
|
||||||
|
|
||||||
|
for transfer_token_instruction in transfer_token_instructions:
|
||||||
|
if (
|
||||||
|
transfer_token_instruction.program_id != token_program
|
||||||
|
or transfer_token_instruction.token_mint[0] != token_mint
|
||||||
|
or transfer_token_instruction.destination_account[0] != token_account
|
||||||
|
or transfer_token_instruction.owner[0] != owner
|
||||||
|
):
|
||||||
|
# there are different token accounts, don't handle as predefined
|
||||||
|
return False
|
||||||
|
|
||||||
|
# at this point there can only be zero or one create token account instructions
|
||||||
|
create_token_account_instruction = (
|
||||||
|
create_token_account_instructions[0]
|
||||||
|
if len(create_token_account_instructions) == 1
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
if create_token_account_instruction is not None and (
|
||||||
|
create_token_account_instruction.spl_token[0] != base58.decode(token_program)
|
||||||
|
or create_token_account_instruction.token_mint[0] != token_mint
|
||||||
|
or create_token_account_instruction.associated_token_account[0] != token_account
|
||||||
|
):
|
||||||
|
# there are different token accounts, don't handle as predefined
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def try_confirm_token_transfer_transaction(
|
||||||
|
transaction: Transaction,
|
||||||
|
fee: int,
|
||||||
|
signer_path: list[int],
|
||||||
|
blockhash: bytes,
|
||||||
|
additional_info: SolanaTxAdditionalInfo | None = None,
|
||||||
|
) -> bool:
|
||||||
|
from .layout import confirm_token_transfer
|
||||||
|
from .token_account import try_get_token_account_base_address
|
||||||
|
|
||||||
|
if not is_predefined_token_transfer(
|
||||||
|
transaction.instructions,
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
|
||||||
|
transfer_token_instructions = get_token_transfer_instructions(
|
||||||
|
transaction.instructions
|
||||||
|
)
|
||||||
|
|
||||||
|
# in is_predefined_token_transfer we made sure that these values are the same
|
||||||
|
# for all the transfer token instructions
|
||||||
|
token_program = base58.decode(transfer_token_instructions[0].program_id)
|
||||||
|
token_mint = transfer_token_instructions[0].token_mint[0]
|
||||||
|
token_account = transfer_token_instructions[0].destination_account[0]
|
||||||
|
|
||||||
|
base_address = (
|
||||||
|
try_get_token_account_base_address(
|
||||||
|
token_account,
|
||||||
|
token_program,
|
||||||
|
token_mint,
|
||||||
|
additional_info.token_accounts_infos,
|
||||||
|
)
|
||||||
|
if additional_info is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
total_token_amount = sum(
|
||||||
|
[
|
||||||
|
transfer_token_instruction.amount
|
||||||
|
for transfer_token_instruction in transfer_token_instructions
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await confirm_token_transfer(
|
||||||
|
token_account if base_address is None else base_address,
|
||||||
|
token_account,
|
||||||
|
token_mint,
|
||||||
|
total_token_amount,
|
||||||
|
transfer_token_instructions[0].decimals,
|
||||||
|
fee,
|
||||||
|
signer_path,
|
||||||
|
blockhash,
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def try_confirm_predefined_transaction(
|
||||||
|
transaction: Transaction,
|
||||||
|
fee: int,
|
||||||
|
signer_path: list[int],
|
||||||
|
blockhash: bytes,
|
||||||
|
additional_info: SolanaTxAdditionalInfo | None = None,
|
||||||
|
) -> bool:
|
||||||
|
from .layout import confirm_system_transfer
|
||||||
|
from .transaction.instructions import SystemProgramTransferInstruction
|
||||||
|
|
||||||
|
instructions = transaction.instructions
|
||||||
|
instructions_count = len(instructions)
|
||||||
|
|
||||||
|
if instructions_count == 1:
|
||||||
|
if SystemProgramTransferInstruction.is_type_of(instructions[0]):
|
||||||
|
await confirm_system_transfer(instructions[0], fee, signer_path, blockhash)
|
||||||
|
return True
|
||||||
|
|
||||||
|
return await try_confirm_token_transfer_transaction(
|
||||||
|
transaction, fee, signer_path, blockhash, additional_info
|
||||||
|
)
|
@ -26,6 +26,7 @@ async def sign_tx(
|
|||||||
from apps.common import seed
|
from apps.common import seed
|
||||||
|
|
||||||
from .layout import confirm_transaction
|
from .layout import confirm_transaction
|
||||||
|
from .predefined_transaction import try_confirm_predefined_transaction
|
||||||
|
|
||||||
address_n = msg.address_n # local_cache_attribute
|
address_n = msg.address_n # local_cache_attribute
|
||||||
serialized_tx = msg.serialized_tx # local_cache_attribute
|
serialized_tx = msg.serialized_tx # local_cache_attribute
|
||||||
@ -54,7 +55,7 @@ async def sign_tx(
|
|||||||
fee = calculate_fee(transaction)
|
fee = calculate_fee(transaction)
|
||||||
|
|
||||||
if not await try_confirm_predefined_transaction(
|
if not await try_confirm_predefined_transaction(
|
||||||
transaction, fee, address_n, transaction.blockhash
|
transaction, fee, address_n, transaction.blockhash, msg.additional_info
|
||||||
):
|
):
|
||||||
await confirm_instructions(address_n, signer_public_key, transaction)
|
await confirm_instructions(address_n, signer_public_key, transaction)
|
||||||
await confirm_transaction(
|
await confirm_transaction(
|
||||||
@ -68,56 +69,6 @@ async def sign_tx(
|
|||||||
return SolanaTxSignature(signature=signature)
|
return SolanaTxSignature(signature=signature)
|
||||||
|
|
||||||
|
|
||||||
async def try_confirm_predefined_transaction(
|
|
||||||
transaction: Transaction, fee: int, signer_path: list[int], blockhash: bytes
|
|
||||||
) -> bool:
|
|
||||||
from .layout import confirm_system_transfer, confirm_token_transfer
|
|
||||||
from .transaction.instructions import (
|
|
||||||
AssociatedTokenAccountProgramCreateInstruction,
|
|
||||||
SystemProgramTransferInstruction,
|
|
||||||
TokenProgramTransferCheckedInstruction,
|
|
||||||
)
|
|
||||||
|
|
||||||
instructions = transaction.instructions
|
|
||||||
instructions_count = len(instructions)
|
|
||||||
|
|
||||||
if instructions_count == 1:
|
|
||||||
if SystemProgramTransferInstruction.is_type_of(instructions[0]):
|
|
||||||
await confirm_system_transfer(instructions[0], fee, signer_path, blockhash)
|
|
||||||
return True
|
|
||||||
|
|
||||||
if TokenProgramTransferCheckedInstruction.is_type_of(instructions[0]):
|
|
||||||
await confirm_token_transfer(
|
|
||||||
None, instructions[0], fee, signer_path, blockhash
|
|
||||||
)
|
|
||||||
return True
|
|
||||||
elif instructions_count == 2:
|
|
||||||
if AssociatedTokenAccountProgramCreateInstruction.is_type_of(
|
|
||||||
instructions[0]
|
|
||||||
) and TokenProgramTransferCheckedInstruction.is_type_of(instructions[1]):
|
|
||||||
create_token_account_instruction = instructions[0]
|
|
||||||
transfer_token_instruction = instructions[1]
|
|
||||||
|
|
||||||
# If the account being created is different from the recipient account we need
|
|
||||||
# to display all the instruction information.
|
|
||||||
if (
|
|
||||||
create_token_account_instruction.associated_token_account[0]
|
|
||||||
!= transfer_token_instruction.destination_account[0]
|
|
||||||
):
|
|
||||||
return False
|
|
||||||
|
|
||||||
await confirm_token_transfer(
|
|
||||||
instructions[0],
|
|
||||||
instructions[1],
|
|
||||||
fee,
|
|
||||||
signer_path,
|
|
||||||
blockhash,
|
|
||||||
)
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
async def confirm_instructions(
|
async def confirm_instructions(
|
||||||
signer_path: list[int], signer_public_key: bytes, transaction: Transaction
|
signer_path: list[int], signer_public_key: bytes, transaction: Transaction
|
||||||
) -> None:
|
) -> None:
|
||||||
|
65
core/src/apps/solana/token_account.py
Normal file
65
core/src/apps/solana/token_account.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from trezor.crypto import base58
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from trezor.messages import SolanaTxTokenAccountInfo
|
||||||
|
|
||||||
|
ASSOCIATED_TOKEN_ACCOUNT_PROGRAM = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
|
||||||
|
|
||||||
|
SEED_CONSTANT = "ProgramDerivedAddress"
|
||||||
|
|
||||||
|
|
||||||
|
def assert_is_associated_token_account(
|
||||||
|
base_address: bytes,
|
||||||
|
token_account_address: bytes,
|
||||||
|
token_program: bytes,
|
||||||
|
token_mint: bytes,
|
||||||
|
) -> None:
|
||||||
|
from trezor.crypto.hashlib import sha256
|
||||||
|
|
||||||
|
# based on the following sources:
|
||||||
|
# https://spl.solana.com/associated-token-account#finding-the-associated-token-account-address
|
||||||
|
# https://github.com/solana-labs/solana/blob/8fbe033eaca693ed8c3e90b19bc3f61b32885e5e/sdk/program/src/pubkey.rs#L495
|
||||||
|
for seed_bump in range(255, 0, -1):
|
||||||
|
seed = (
|
||||||
|
base_address
|
||||||
|
+ token_program
|
||||||
|
+ token_mint
|
||||||
|
+ bytes([seed_bump])
|
||||||
|
+ base58.decode(ASSOCIATED_TOKEN_ACCOUNT_PROGRAM)
|
||||||
|
+ SEED_CONSTANT.encode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
account = sha256(seed).digest()
|
||||||
|
|
||||||
|
if account == token_account_address:
|
||||||
|
return
|
||||||
|
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
|
||||||
|
def try_get_token_account_base_address(
|
||||||
|
token_account_address: bytes,
|
||||||
|
token_program: bytes,
|
||||||
|
token_mint: bytes,
|
||||||
|
token_accounts_infos: list[SolanaTxTokenAccountInfo],
|
||||||
|
) -> bytes | None:
|
||||||
|
for token_account_info in token_accounts_infos:
|
||||||
|
if (
|
||||||
|
base58.decode(token_account_info.token_account) == token_account_address
|
||||||
|
and base58.decode(token_account_info.token_program) == token_program
|
||||||
|
and base58.decode(token_account_info.token_mint) == token_mint
|
||||||
|
):
|
||||||
|
base_address = base58.decode(token_account_info.base_address)
|
||||||
|
|
||||||
|
assert_is_associated_token_account(
|
||||||
|
base_address,
|
||||||
|
token_account_address,
|
||||||
|
token_program,
|
||||||
|
token_mint,
|
||||||
|
)
|
||||||
|
|
||||||
|
return base_address
|
||||||
|
|
||||||
|
return None
|
@ -5257,15 +5257,51 @@ if TYPE_CHECKING:
|
|||||||
def is_type_of(cls, msg: Any) -> TypeGuard["SolanaAddress"]:
|
def is_type_of(cls, msg: Any) -> TypeGuard["SolanaAddress"]:
|
||||||
return isinstance(msg, cls)
|
return isinstance(msg, cls)
|
||||||
|
|
||||||
|
class SolanaTxTokenAccountInfo(protobuf.MessageType):
|
||||||
|
base_address: "str"
|
||||||
|
token_program: "str"
|
||||||
|
token_mint: "str"
|
||||||
|
token_account: "str"
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
base_address: "str",
|
||||||
|
token_program: "str",
|
||||||
|
token_mint: "str",
|
||||||
|
token_account: "str",
|
||||||
|
) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_type_of(cls, msg: Any) -> TypeGuard["SolanaTxTokenAccountInfo"]:
|
||||||
|
return isinstance(msg, cls)
|
||||||
|
|
||||||
|
class SolanaTxAdditionalInfo(protobuf.MessageType):
|
||||||
|
token_accounts_infos: "list[SolanaTxTokenAccountInfo]"
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
token_accounts_infos: "list[SolanaTxTokenAccountInfo] | None" = None,
|
||||||
|
) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_type_of(cls, msg: Any) -> TypeGuard["SolanaTxAdditionalInfo"]:
|
||||||
|
return isinstance(msg, cls)
|
||||||
|
|
||||||
class SolanaSignTx(protobuf.MessageType):
|
class SolanaSignTx(protobuf.MessageType):
|
||||||
address_n: "list[int]"
|
address_n: "list[int]"
|
||||||
serialized_tx: "bytes"
|
serialized_tx: "bytes"
|
||||||
|
additional_info: "SolanaTxAdditionalInfo | None"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
serialized_tx: "bytes",
|
serialized_tx: "bytes",
|
||||||
address_n: "list[int] | None" = None,
|
address_n: "list[int] | None" = None,
|
||||||
|
additional_info: "SolanaTxAdditionalInfo | None" = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
206
core/tests/test_apps.solana.predefined_transaction.py
Normal file
206
core/tests/test_apps.solana.predefined_transaction.py
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
from common import *
|
||||||
|
|
||||||
|
from trezor.crypto import base58
|
||||||
|
|
||||||
|
from apps.solana.predefined_transaction import is_predefined_token_transfer
|
||||||
|
from apps.solana.transaction.instruction import Instruction
|
||||||
|
from apps.solana.transaction.instructions import (
|
||||||
|
ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID,
|
||||||
|
ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID_INS_CREATE,
|
||||||
|
SYSTEM_PROGRAM_ID,
|
||||||
|
SYSTEM_PROGRAM_ID_INS_TRANSFER,
|
||||||
|
TOKEN_2022_PROGRAM_ID,
|
||||||
|
TOKEN_2022_PROGRAM_ID_INS_TRANSFER_CHECKED,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
TOKEN_PROGRAM_ID_INS_TRANSFER_CHECKED,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_mock_instruction(
|
||||||
|
program_id: str, instruction_id: int, parsed_data: dict[str, Any]
|
||||||
|
):
|
||||||
|
instruction = Instruction(
|
||||||
|
instruction_data=b"",
|
||||||
|
program_id=program_id,
|
||||||
|
accounts=[],
|
||||||
|
instruction_id=instruction_id,
|
||||||
|
property_templates=[],
|
||||||
|
accounts_template=[],
|
||||||
|
ui_properties=[],
|
||||||
|
ui_name="",
|
||||||
|
is_program_supported=True,
|
||||||
|
is_instruction_supported=True,
|
||||||
|
supports_multisig=False,
|
||||||
|
is_deprecated_warning=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
instruction.parsed_data = parsed_data
|
||||||
|
return instruction
|
||||||
|
|
||||||
|
|
||||||
|
def create_transfer_token_instruction(
|
||||||
|
program_id=TOKEN_PROGRAM_ID,
|
||||||
|
instruction_id=TOKEN_PROGRAM_ID_INS_TRANSFER_CHECKED,
|
||||||
|
token_mint="GHArwcWCuk9WkUG4XKUbt935rKfmBmywbEWyFxdH3mou",
|
||||||
|
destination_account="92YgwqTtTWB7qY92JT6mbL2WCmhAs7LPZL4jLcizNfwx",
|
||||||
|
owner="14CCvQzQzHCVgZM3j9soPnXuJXh1RmCfwLVUcdfbZVBS",
|
||||||
|
):
|
||||||
|
return create_mock_instruction(
|
||||||
|
program_id,
|
||||||
|
instruction_id,
|
||||||
|
{
|
||||||
|
"token_mint": (base58.decode(token_mint),),
|
||||||
|
"destination_account": (base58.decode(destination_account),),
|
||||||
|
"owner": (base58.decode(owner),),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_create_token_account_instruction(
|
||||||
|
token_mint="GHArwcWCuk9WkUG4XKUbt935rKfmBmywbEWyFxdH3mou",
|
||||||
|
associated_token_account="92YgwqTtTWB7qY92JT6mbL2WCmhAs7LPZL4jLcizNfwx",
|
||||||
|
spl_token=TOKEN_PROGRAM_ID,
|
||||||
|
):
|
||||||
|
return create_mock_instruction(
|
||||||
|
ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID,
|
||||||
|
ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID_INS_CREATE,
|
||||||
|
{
|
||||||
|
"token_mint": (base58.decode(token_mint),),
|
||||||
|
"associated_token_account": (base58.decode(associated_token_account),),
|
||||||
|
"spl_token": (base58.decode(spl_token),),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
|
||||||
|
class TestSolanaPredefinedTransactions(unittest.TestCase):
|
||||||
|
def test_is_predefined_token_transfer(self):
|
||||||
|
# note: if there are multiple transfer instructions they are the same
|
||||||
|
# in the tests because that's the info the test cares about. In reality
|
||||||
|
# the instructions can differ in the destination account and amount.
|
||||||
|
valid_test_cases = [
|
||||||
|
[create_transfer_token_instruction()],
|
||||||
|
[create_transfer_token_instruction(), create_transfer_token_instruction()],
|
||||||
|
[
|
||||||
|
create_create_token_account_instruction(),
|
||||||
|
create_transfer_token_instruction(),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
create_create_token_account_instruction(),
|
||||||
|
create_transfer_token_instruction(),
|
||||||
|
create_transfer_token_instruction(),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
create_create_token_account_instruction(
|
||||||
|
spl_token=TOKEN_2022_PROGRAM_ID
|
||||||
|
),
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
program_id=TOKEN_2022_PROGRAM_ID,
|
||||||
|
instruction_id=TOKEN_2022_PROGRAM_ID_INS_TRANSFER_CHECKED,
|
||||||
|
),
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
program_id=TOKEN_2022_PROGRAM_ID,
|
||||||
|
instruction_id=TOKEN_2022_PROGRAM_ID_INS_TRANSFER_CHECKED,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
invalid_test_cases = [
|
||||||
|
# only create account
|
||||||
|
[
|
||||||
|
create_create_token_account_instruction(),
|
||||||
|
],
|
||||||
|
# there are other instructions
|
||||||
|
[
|
||||||
|
create_transfer_token_instruction(),
|
||||||
|
create_mock_instruction(
|
||||||
|
SYSTEM_PROGRAM_ID, SYSTEM_PROGRAM_ID_INS_TRANSFER, {}
|
||||||
|
),
|
||||||
|
],
|
||||||
|
# multiple create account instructions
|
||||||
|
[
|
||||||
|
create_create_token_account_instruction(),
|
||||||
|
create_create_token_account_instruction(),
|
||||||
|
create_transfer_token_instruction(),
|
||||||
|
],
|
||||||
|
# transfer instructions program_id mismatch
|
||||||
|
[
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
program_id=TOKEN_PROGRAM_ID,
|
||||||
|
instruction_id=TOKEN_PROGRAM_ID_INS_TRANSFER_CHECKED,
|
||||||
|
),
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
program_id=TOKEN_2022_PROGRAM_ID,
|
||||||
|
instruction_id=TOKEN_2022_PROGRAM_ID_INS_TRANSFER_CHECKED,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
# transfer instructions token_mint mismatch
|
||||||
|
[
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
token_mint="GHArwcWCuk9WkUG4XKUbt935rKfmBmywbEWyFxdH3mou"
|
||||||
|
),
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
token_mint="GZDphoFQJ9m7uRU7TdS8cVDGFvsiQbcaY3n5mdoQHmDj"
|
||||||
|
),
|
||||||
|
],
|
||||||
|
# transfer instructions destination mismatch
|
||||||
|
[
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
destination_account="92YgwqTtTWB7qY92JT6mbL2WCmhAs7LPZL4jLcizNfwx"
|
||||||
|
),
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
destination_account="74pZnim7gywyschy4MGkW6eZURv1DBXqwHTCqLRk63wz"
|
||||||
|
),
|
||||||
|
],
|
||||||
|
# transfer instructions owner mismatch
|
||||||
|
[
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
owner="14CCvQzQzHCVgZM3j9soPnXuJXh1RmCfwLVUcdfbZVBS"
|
||||||
|
),
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
owner="BVRFH6vt5bNXub6WnnFRgaHFTcbkjBrf7x1troU1izGg"
|
||||||
|
),
|
||||||
|
],
|
||||||
|
# token program mismatch
|
||||||
|
[
|
||||||
|
create_create_token_account_instruction(
|
||||||
|
spl_token=TOKEN_2022_PROGRAM_ID
|
||||||
|
),
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
program_id=TOKEN_PROGRAM_ID,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
# create account token_mint mismatch
|
||||||
|
[
|
||||||
|
create_create_token_account_instruction(
|
||||||
|
token_mint="GZDphoFQJ9m7uRU7TdS8cVDGFvsiQbcaY3n5mdoQHmDj"
|
||||||
|
),
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
token_mint="GHArwcWCuk9WkUG4XKUbt935rKfmBmywbEWyFxdH3mou",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
# create account associated_token_account mismatch
|
||||||
|
[
|
||||||
|
create_create_token_account_instruction(
|
||||||
|
associated_token_account="74pZnim7gywyschy4MGkW6eZURv1DBXqwHTCqLRk63wz"
|
||||||
|
),
|
||||||
|
create_transfer_token_instruction(
|
||||||
|
destination_account="92YgwqTtTWB7qY92JT6mbL2WCmhAs7LPZL4jLcizNfwx",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
# create account is not first
|
||||||
|
[
|
||||||
|
create_transfer_token_instruction(),
|
||||||
|
create_create_token_account_instruction(),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
for instructions in valid_test_cases:
|
||||||
|
self.assertTrue(is_predefined_token_transfer(instructions))
|
||||||
|
|
||||||
|
for instructions in invalid_test_cases:
|
||||||
|
self.assertFalse(is_predefined_token_transfer(instructions))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
@ -1,4 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING
|
import json
|
||||||
|
from typing import TYPE_CHECKING, Optional, TextIO
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
@ -50,12 +51,35 @@ def get_address(
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument("serialized_tx", type=str)
|
@click.argument("serialized_tx", type=str)
|
||||||
@click.option("-n", "--address", default=DEFAULT_PATH, help=PATH_HELP)
|
@click.option("-n", "--address", default=DEFAULT_PATH, help=PATH_HELP)
|
||||||
|
@click.option("-a", "--additional-information-file", type=click.File("r"))
|
||||||
@with_client
|
@with_client
|
||||||
def sign_tx(
|
def sign_tx(
|
||||||
client: "TrezorClient",
|
client: "TrezorClient",
|
||||||
address: str,
|
address: str,
|
||||||
serialized_tx: str,
|
serialized_tx: str,
|
||||||
|
additional_information_file: Optional[TextIO],
|
||||||
) -> messages.SolanaTxSignature:
|
) -> messages.SolanaTxSignature:
|
||||||
"""Sign Solana transaction."""
|
"""Sign Solana transaction."""
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return solana.sign_tx(client, address_n, bytes.fromhex(serialized_tx))
|
|
||||||
|
additional_information = None
|
||||||
|
if additional_information_file:
|
||||||
|
raw_additional_information = json.load(additional_information_file)
|
||||||
|
additional_information = messages.SolanaTxAdditionalInfo(
|
||||||
|
token_accounts_infos=[
|
||||||
|
messages.SolanaTxTokenAccountInfo(
|
||||||
|
base_address=token_account["base_address"],
|
||||||
|
token_program=token_account["token_program"],
|
||||||
|
token_mint=token_account["token_mint"],
|
||||||
|
token_account=token_account["token_account"],
|
||||||
|
)
|
||||||
|
for token_account in raw_additional_information["token_accounts_infos"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
return solana.sign_tx(
|
||||||
|
client,
|
||||||
|
address_n,
|
||||||
|
bytes.fromhex(serialized_tx),
|
||||||
|
additional_information,
|
||||||
|
)
|
||||||
|
@ -6716,11 +6716,49 @@ class SolanaAddress(protobuf.MessageType):
|
|||||||
self.address = address
|
self.address = address
|
||||||
|
|
||||||
|
|
||||||
|
class SolanaTxTokenAccountInfo(protobuf.MessageType):
|
||||||
|
MESSAGE_WIRE_TYPE = None
|
||||||
|
FIELDS = {
|
||||||
|
1: protobuf.Field("base_address", "string", repeated=False, required=True),
|
||||||
|
2: protobuf.Field("token_program", "string", repeated=False, required=True),
|
||||||
|
3: protobuf.Field("token_mint", "string", repeated=False, required=True),
|
||||||
|
4: protobuf.Field("token_account", "string", repeated=False, required=True),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
base_address: "str",
|
||||||
|
token_program: "str",
|
||||||
|
token_mint: "str",
|
||||||
|
token_account: "str",
|
||||||
|
) -> None:
|
||||||
|
self.base_address = base_address
|
||||||
|
self.token_program = token_program
|
||||||
|
self.token_mint = token_mint
|
||||||
|
self.token_account = token_account
|
||||||
|
|
||||||
|
|
||||||
|
class SolanaTxAdditionalInfo(protobuf.MessageType):
|
||||||
|
MESSAGE_WIRE_TYPE = None
|
||||||
|
FIELDS = {
|
||||||
|
1: protobuf.Field("token_accounts_infos", "SolanaTxTokenAccountInfo", repeated=True, required=False, default=None),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
token_accounts_infos: Optional[Sequence["SolanaTxTokenAccountInfo"]] = None,
|
||||||
|
) -> None:
|
||||||
|
self.token_accounts_infos: Sequence["SolanaTxTokenAccountInfo"] = token_accounts_infos if token_accounts_infos is not None else []
|
||||||
|
|
||||||
|
|
||||||
class SolanaSignTx(protobuf.MessageType):
|
class SolanaSignTx(protobuf.MessageType):
|
||||||
MESSAGE_WIRE_TYPE = 904
|
MESSAGE_WIRE_TYPE = 904
|
||||||
FIELDS = {
|
FIELDS = {
|
||||||
1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None),
|
1: protobuf.Field("address_n", "uint32", repeated=True, required=False, default=None),
|
||||||
2: protobuf.Field("serialized_tx", "bytes", repeated=False, required=True),
|
2: protobuf.Field("serialized_tx", "bytes", repeated=False, required=True),
|
||||||
|
3: protobuf.Field("additional_info", "SolanaTxAdditionalInfo", repeated=False, required=False, default=None),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -6728,9 +6766,11 @@ class SolanaSignTx(protobuf.MessageType):
|
|||||||
*,
|
*,
|
||||||
serialized_tx: "bytes",
|
serialized_tx: "bytes",
|
||||||
address_n: Optional[Sequence["int"]] = None,
|
address_n: Optional[Sequence["int"]] = None,
|
||||||
|
additional_info: Optional["SolanaTxAdditionalInfo"] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.address_n: Sequence["int"] = address_n if address_n is not None else []
|
self.address_n: Sequence["int"] = address_n if address_n is not None else []
|
||||||
self.serialized_tx = serialized_tx
|
self.serialized_tx = serialized_tx
|
||||||
|
self.additional_info = additional_info
|
||||||
|
|
||||||
|
|
||||||
class SolanaTxSignature(protobuf.MessageType):
|
class SolanaTxSignature(protobuf.MessageType):
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import TYPE_CHECKING, List
|
from typing import TYPE_CHECKING, List, Optional
|
||||||
|
|
||||||
from . import messages
|
from . import messages
|
||||||
from .tools import expect
|
from .tools import expect
|
||||||
@ -40,10 +40,12 @@ def sign_tx(
|
|||||||
client: "TrezorClient",
|
client: "TrezorClient",
|
||||||
address_n: List[int],
|
address_n: List[int],
|
||||||
serialized_tx: bytes,
|
serialized_tx: bytes,
|
||||||
|
additional_info: Optional[messages.SolanaTxAdditionalInfo],
|
||||||
) -> "MessageType":
|
) -> "MessageType":
|
||||||
return client.call(
|
return client.call(
|
||||||
messages.SolanaSignTx(
|
messages.SolanaSignTx(
|
||||||
address_n=address_n,
|
address_n=address_n,
|
||||||
serialized_tx=serialized_tx,
|
serialized_tx=serialized_tx,
|
||||||
|
additional_info=additional_info,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -708,6 +708,466 @@ impl ::protobuf::reflect::ProtobufValue for SolanaAddress {
|
|||||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @@protoc_insertion_point(message:hw.trezor.messages.solana.SolanaTxTokenAccountInfo)
|
||||||
|
#[derive(PartialEq,Clone,Default,Debug)]
|
||||||
|
pub struct SolanaTxTokenAccountInfo {
|
||||||
|
// message fields
|
||||||
|
// @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaTxTokenAccountInfo.base_address)
|
||||||
|
pub base_address: ::std::option::Option<::std::string::String>,
|
||||||
|
// @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaTxTokenAccountInfo.token_program)
|
||||||
|
pub token_program: ::std::option::Option<::std::string::String>,
|
||||||
|
// @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaTxTokenAccountInfo.token_mint)
|
||||||
|
pub token_mint: ::std::option::Option<::std::string::String>,
|
||||||
|
// @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaTxTokenAccountInfo.token_account)
|
||||||
|
pub token_account: ::std::option::Option<::std::string::String>,
|
||||||
|
// special fields
|
||||||
|
// @@protoc_insertion_point(special_field:hw.trezor.messages.solana.SolanaTxTokenAccountInfo.special_fields)
|
||||||
|
pub special_fields: ::protobuf::SpecialFields,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ::std::default::Default for &'a SolanaTxTokenAccountInfo {
|
||||||
|
fn default() -> &'a SolanaTxTokenAccountInfo {
|
||||||
|
<SolanaTxTokenAccountInfo as ::protobuf::Message>::default_instance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SolanaTxTokenAccountInfo {
|
||||||
|
pub fn new() -> SolanaTxTokenAccountInfo {
|
||||||
|
::std::default::Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
// required string base_address = 1;
|
||||||
|
|
||||||
|
pub fn base_address(&self) -> &str {
|
||||||
|
match self.base_address.as_ref() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_base_address(&mut self) {
|
||||||
|
self.base_address = ::std::option::Option::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_base_address(&self) -> bool {
|
||||||
|
self.base_address.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param is passed by value, moved
|
||||||
|
pub fn set_base_address(&mut self, v: ::std::string::String) {
|
||||||
|
self.base_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_base_address(&mut self) -> &mut ::std::string::String {
|
||||||
|
if self.base_address.is_none() {
|
||||||
|
self.base_address = ::std::option::Option::Some(::std::string::String::new());
|
||||||
|
}
|
||||||
|
self.base_address.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take field
|
||||||
|
pub fn take_base_address(&mut self) -> ::std::string::String {
|
||||||
|
self.base_address.take().unwrap_or_else(|| ::std::string::String::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
// required string token_program = 2;
|
||||||
|
|
||||||
|
pub fn token_program(&self) -> &str {
|
||||||
|
match self.token_program.as_ref() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_token_program(&mut self) {
|
||||||
|
self.token_program = ::std::option::Option::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_token_program(&self) -> bool {
|
||||||
|
self.token_program.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param is passed by value, moved
|
||||||
|
pub fn set_token_program(&mut self, v: ::std::string::String) {
|
||||||
|
self.token_program = ::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_token_program(&mut self) -> &mut ::std::string::String {
|
||||||
|
if self.token_program.is_none() {
|
||||||
|
self.token_program = ::std::option::Option::Some(::std::string::String::new());
|
||||||
|
}
|
||||||
|
self.token_program.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take field
|
||||||
|
pub fn take_token_program(&mut self) -> ::std::string::String {
|
||||||
|
self.token_program.take().unwrap_or_else(|| ::std::string::String::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
// required string token_mint = 3;
|
||||||
|
|
||||||
|
pub fn token_mint(&self) -> &str {
|
||||||
|
match self.token_mint.as_ref() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_token_mint(&mut self) {
|
||||||
|
self.token_mint = ::std::option::Option::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_token_mint(&self) -> bool {
|
||||||
|
self.token_mint.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param is passed by value, moved
|
||||||
|
pub fn set_token_mint(&mut self, v: ::std::string::String) {
|
||||||
|
self.token_mint = ::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_token_mint(&mut self) -> &mut ::std::string::String {
|
||||||
|
if self.token_mint.is_none() {
|
||||||
|
self.token_mint = ::std::option::Option::Some(::std::string::String::new());
|
||||||
|
}
|
||||||
|
self.token_mint.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take field
|
||||||
|
pub fn take_token_mint(&mut self) -> ::std::string::String {
|
||||||
|
self.token_mint.take().unwrap_or_else(|| ::std::string::String::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
// required string token_account = 4;
|
||||||
|
|
||||||
|
pub fn token_account(&self) -> &str {
|
||||||
|
match self.token_account.as_ref() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_token_account(&mut self) {
|
||||||
|
self.token_account = ::std::option::Option::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_token_account(&self) -> bool {
|
||||||
|
self.token_account.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param is passed by value, moved
|
||||||
|
pub fn set_token_account(&mut self, v: ::std::string::String) {
|
||||||
|
self.token_account = ::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_token_account(&mut self) -> &mut ::std::string::String {
|
||||||
|
if self.token_account.is_none() {
|
||||||
|
self.token_account = ::std::option::Option::Some(::std::string::String::new());
|
||||||
|
}
|
||||||
|
self.token_account.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take field
|
||||||
|
pub fn take_token_account(&mut self) -> ::std::string::String {
|
||||||
|
self.token_account.take().unwrap_or_else(|| ::std::string::String::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||||
|
let mut fields = ::std::vec::Vec::with_capacity(4);
|
||||||
|
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||||
|
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
|
||||||
|
"base_address",
|
||||||
|
|m: &SolanaTxTokenAccountInfo| { &m.base_address },
|
||||||
|
|m: &mut SolanaTxTokenAccountInfo| { &mut m.base_address },
|
||||||
|
));
|
||||||
|
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
|
||||||
|
"token_program",
|
||||||
|
|m: &SolanaTxTokenAccountInfo| { &m.token_program },
|
||||||
|
|m: &mut SolanaTxTokenAccountInfo| { &mut m.token_program },
|
||||||
|
));
|
||||||
|
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
|
||||||
|
"token_mint",
|
||||||
|
|m: &SolanaTxTokenAccountInfo| { &m.token_mint },
|
||||||
|
|m: &mut SolanaTxTokenAccountInfo| { &mut m.token_mint },
|
||||||
|
));
|
||||||
|
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
|
||||||
|
"token_account",
|
||||||
|
|m: &SolanaTxTokenAccountInfo| { &m.token_account },
|
||||||
|
|m: &mut SolanaTxTokenAccountInfo| { &mut m.token_account },
|
||||||
|
));
|
||||||
|
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<SolanaTxTokenAccountInfo>(
|
||||||
|
"SolanaTxTokenAccountInfo",
|
||||||
|
fields,
|
||||||
|
oneofs,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::protobuf::Message for SolanaTxTokenAccountInfo {
|
||||||
|
const NAME: &'static str = "SolanaTxTokenAccountInfo";
|
||||||
|
|
||||||
|
fn is_initialized(&self) -> bool {
|
||||||
|
if self.base_address.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if self.token_program.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if self.token_mint.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if self.token_account.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.base_address = ::std::option::Option::Some(is.read_string()?);
|
||||||
|
},
|
||||||
|
18 => {
|
||||||
|
self.token_program = ::std::option::Option::Some(is.read_string()?);
|
||||||
|
},
|
||||||
|
26 => {
|
||||||
|
self.token_mint = ::std::option::Option::Some(is.read_string()?);
|
||||||
|
},
|
||||||
|
34 => {
|
||||||
|
self.token_account = ::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.base_address.as_ref() {
|
||||||
|
my_size += ::protobuf::rt::string_size(1, &v);
|
||||||
|
}
|
||||||
|
if let Some(v) = self.token_program.as_ref() {
|
||||||
|
my_size += ::protobuf::rt::string_size(2, &v);
|
||||||
|
}
|
||||||
|
if let Some(v) = self.token_mint.as_ref() {
|
||||||
|
my_size += ::protobuf::rt::string_size(3, &v);
|
||||||
|
}
|
||||||
|
if let Some(v) = self.token_account.as_ref() {
|
||||||
|
my_size += ::protobuf::rt::string_size(4, &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.base_address.as_ref() {
|
||||||
|
os.write_string(1, v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = self.token_program.as_ref() {
|
||||||
|
os.write_string(2, v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = self.token_mint.as_ref() {
|
||||||
|
os.write_string(3, v)?;
|
||||||
|
}
|
||||||
|
if let Some(v) = self.token_account.as_ref() {
|
||||||
|
os.write_string(4, 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() -> SolanaTxTokenAccountInfo {
|
||||||
|
SolanaTxTokenAccountInfo::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.base_address = ::std::option::Option::None;
|
||||||
|
self.token_program = ::std::option::Option::None;
|
||||||
|
self.token_mint = ::std::option::Option::None;
|
||||||
|
self.token_account = ::std::option::Option::None;
|
||||||
|
self.special_fields.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_instance() -> &'static SolanaTxTokenAccountInfo {
|
||||||
|
static instance: SolanaTxTokenAccountInfo = SolanaTxTokenAccountInfo {
|
||||||
|
base_address: ::std::option::Option::None,
|
||||||
|
token_program: ::std::option::Option::None,
|
||||||
|
token_mint: ::std::option::Option::None,
|
||||||
|
token_account: ::std::option::Option::None,
|
||||||
|
special_fields: ::protobuf::SpecialFields::new(),
|
||||||
|
};
|
||||||
|
&instance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::protobuf::MessageFull for SolanaTxTokenAccountInfo {
|
||||||
|
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("SolanaTxTokenAccountInfo").unwrap()).clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Display for SolanaTxTokenAccountInfo {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
::protobuf::text_format::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::protobuf::reflect::ProtobufValue for SolanaTxTokenAccountInfo {
|
||||||
|
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@protoc_insertion_point(message:hw.trezor.messages.solana.SolanaTxAdditionalInfo)
|
||||||
|
#[derive(PartialEq,Clone,Default,Debug)]
|
||||||
|
pub struct SolanaTxAdditionalInfo {
|
||||||
|
// message fields
|
||||||
|
// @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaTxAdditionalInfo.token_accounts_infos)
|
||||||
|
pub token_accounts_infos: ::std::vec::Vec<SolanaTxTokenAccountInfo>,
|
||||||
|
// special fields
|
||||||
|
// @@protoc_insertion_point(special_field:hw.trezor.messages.solana.SolanaTxAdditionalInfo.special_fields)
|
||||||
|
pub special_fields: ::protobuf::SpecialFields,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ::std::default::Default for &'a SolanaTxAdditionalInfo {
|
||||||
|
fn default() -> &'a SolanaTxAdditionalInfo {
|
||||||
|
<SolanaTxAdditionalInfo as ::protobuf::Message>::default_instance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SolanaTxAdditionalInfo {
|
||||||
|
pub fn new() -> SolanaTxAdditionalInfo {
|
||||||
|
::std::default::Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
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_vec_simpler_accessor::<_, _>(
|
||||||
|
"token_accounts_infos",
|
||||||
|
|m: &SolanaTxAdditionalInfo| { &m.token_accounts_infos },
|
||||||
|
|m: &mut SolanaTxAdditionalInfo| { &mut m.token_accounts_infos },
|
||||||
|
));
|
||||||
|
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<SolanaTxAdditionalInfo>(
|
||||||
|
"SolanaTxAdditionalInfo",
|
||||||
|
fields,
|
||||||
|
oneofs,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::protobuf::Message for SolanaTxAdditionalInfo {
|
||||||
|
const NAME: &'static str = "SolanaTxAdditionalInfo";
|
||||||
|
|
||||||
|
fn is_initialized(&self) -> bool {
|
||||||
|
for v in &self.token_accounts_infos {
|
||||||
|
if !v.is_initialized() {
|
||||||
|
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.token_accounts_infos.push(is.read_message()?);
|
||||||
|
},
|
||||||
|
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.token_accounts_infos {
|
||||||
|
let len = value.compute_size();
|
||||||
|
my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
|
||||||
|
};
|
||||||
|
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.token_accounts_infos {
|
||||||
|
::protobuf::rt::write_message_field_with_cached_size(1, v, os)?;
|
||||||
|
};
|
||||||
|
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() -> SolanaTxAdditionalInfo {
|
||||||
|
SolanaTxAdditionalInfo::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.token_accounts_infos.clear();
|
||||||
|
self.special_fields.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_instance() -> &'static SolanaTxAdditionalInfo {
|
||||||
|
static instance: SolanaTxAdditionalInfo = SolanaTxAdditionalInfo {
|
||||||
|
token_accounts_infos: ::std::vec::Vec::new(),
|
||||||
|
special_fields: ::protobuf::SpecialFields::new(),
|
||||||
|
};
|
||||||
|
&instance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::protobuf::MessageFull for SolanaTxAdditionalInfo {
|
||||||
|
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("SolanaTxAdditionalInfo").unwrap()).clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Display for SolanaTxAdditionalInfo {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
::protobuf::text_format::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::protobuf::reflect::ProtobufValue for SolanaTxAdditionalInfo {
|
||||||
|
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
// @@protoc_insertion_point(message:hw.trezor.messages.solana.SolanaSignTx)
|
// @@protoc_insertion_point(message:hw.trezor.messages.solana.SolanaSignTx)
|
||||||
#[derive(PartialEq,Clone,Default,Debug)]
|
#[derive(PartialEq,Clone,Default,Debug)]
|
||||||
pub struct SolanaSignTx {
|
pub struct SolanaSignTx {
|
||||||
@ -716,6 +1176,8 @@ pub struct SolanaSignTx {
|
|||||||
pub address_n: ::std::vec::Vec<u32>,
|
pub address_n: ::std::vec::Vec<u32>,
|
||||||
// @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaSignTx.serialized_tx)
|
// @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaSignTx.serialized_tx)
|
||||||
pub serialized_tx: ::std::option::Option<::std::vec::Vec<u8>>,
|
pub serialized_tx: ::std::option::Option<::std::vec::Vec<u8>>,
|
||||||
|
// @@protoc_insertion_point(field:hw.trezor.messages.solana.SolanaSignTx.additional_info)
|
||||||
|
pub additional_info: ::protobuf::MessageField<SolanaTxAdditionalInfo>,
|
||||||
// special fields
|
// special fields
|
||||||
// @@protoc_insertion_point(special_field:hw.trezor.messages.solana.SolanaSignTx.special_fields)
|
// @@protoc_insertion_point(special_field:hw.trezor.messages.solana.SolanaSignTx.special_fields)
|
||||||
pub special_fields: ::protobuf::SpecialFields,
|
pub special_fields: ::protobuf::SpecialFields,
|
||||||
@ -769,7 +1231,7 @@ impl SolanaSignTx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||||
let mut fields = ::std::vec::Vec::with_capacity(2);
|
let mut fields = ::std::vec::Vec::with_capacity(3);
|
||||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||||
"address_n",
|
"address_n",
|
||||||
@ -781,6 +1243,11 @@ impl SolanaSignTx {
|
|||||||
|m: &SolanaSignTx| { &m.serialized_tx },
|
|m: &SolanaSignTx| { &m.serialized_tx },
|
||||||
|m: &mut SolanaSignTx| { &mut m.serialized_tx },
|
|m: &mut SolanaSignTx| { &mut m.serialized_tx },
|
||||||
));
|
));
|
||||||
|
fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, SolanaTxAdditionalInfo>(
|
||||||
|
"additional_info",
|
||||||
|
|m: &SolanaSignTx| { &m.additional_info },
|
||||||
|
|m: &mut SolanaSignTx| { &mut m.additional_info },
|
||||||
|
));
|
||||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<SolanaSignTx>(
|
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<SolanaSignTx>(
|
||||||
"SolanaSignTx",
|
"SolanaSignTx",
|
||||||
fields,
|
fields,
|
||||||
@ -796,6 +1263,11 @@ impl ::protobuf::Message for SolanaSignTx {
|
|||||||
if self.serialized_tx.is_none() {
|
if self.serialized_tx.is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
for v in &self.additional_info {
|
||||||
|
if !v.is_initialized() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,6 +1283,9 @@ impl ::protobuf::Message for SolanaSignTx {
|
|||||||
18 => {
|
18 => {
|
||||||
self.serialized_tx = ::std::option::Option::Some(is.read_bytes()?);
|
self.serialized_tx = ::std::option::Option::Some(is.read_bytes()?);
|
||||||
},
|
},
|
||||||
|
26 => {
|
||||||
|
::protobuf::rt::read_singular_message_into_field(is, &mut self.additional_info)?;
|
||||||
|
},
|
||||||
tag => {
|
tag => {
|
||||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||||
},
|
},
|
||||||
@ -829,6 +1304,10 @@ impl ::protobuf::Message for SolanaSignTx {
|
|||||||
if let Some(v) = self.serialized_tx.as_ref() {
|
if let Some(v) = self.serialized_tx.as_ref() {
|
||||||
my_size += ::protobuf::rt::bytes_size(2, &v);
|
my_size += ::protobuf::rt::bytes_size(2, &v);
|
||||||
}
|
}
|
||||||
|
if let Some(v) = self.additional_info.as_ref() {
|
||||||
|
let len = v.compute_size();
|
||||||
|
my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
|
||||||
|
}
|
||||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||||
self.special_fields.cached_size().set(my_size as u32);
|
self.special_fields.cached_size().set(my_size as u32);
|
||||||
my_size
|
my_size
|
||||||
@ -841,6 +1320,9 @@ impl ::protobuf::Message for SolanaSignTx {
|
|||||||
if let Some(v) = self.serialized_tx.as_ref() {
|
if let Some(v) = self.serialized_tx.as_ref() {
|
||||||
os.write_bytes(2, v)?;
|
os.write_bytes(2, v)?;
|
||||||
}
|
}
|
||||||
|
if let Some(v) = self.additional_info.as_ref() {
|
||||||
|
::protobuf::rt::write_message_field_with_cached_size(3, v, os)?;
|
||||||
|
}
|
||||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||||
::std::result::Result::Ok(())
|
::std::result::Result::Ok(())
|
||||||
}
|
}
|
||||||
@ -860,6 +1342,7 @@ impl ::protobuf::Message for SolanaSignTx {
|
|||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.address_n.clear();
|
self.address_n.clear();
|
||||||
self.serialized_tx = ::std::option::Option::None;
|
self.serialized_tx = ::std::option::Option::None;
|
||||||
|
self.additional_info.clear();
|
||||||
self.special_fields.clear();
|
self.special_fields.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -867,6 +1350,7 @@ impl ::protobuf::Message for SolanaSignTx {
|
|||||||
static instance: SolanaSignTx = SolanaSignTx {
|
static instance: SolanaSignTx = SolanaSignTx {
|
||||||
address_n: ::std::vec::Vec::new(),
|
address_n: ::std::vec::Vec::new(),
|
||||||
serialized_tx: ::std::option::Option::None,
|
serialized_tx: ::std::option::Option::None,
|
||||||
|
additional_info: ::protobuf::MessageField::none(),
|
||||||
special_fields: ::protobuf::SpecialFields::new(),
|
special_fields: ::protobuf::SpecialFields::new(),
|
||||||
};
|
};
|
||||||
&instance
|
&instance
|
||||||
@ -1060,10 +1544,17 @@ static file_descriptor_proto_data: &'static [u8] = b"\
|
|||||||
\x18\x01\x20\x03(\rR\x08addressN\x12!\n\x0cshow_display\x18\x02\x20\x01(\
|
\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\
|
\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\
|
kify\")\n\rSolanaAddress\x12\x18\n\x07address\x18\x01\x20\x02(\tR\x07add\
|
||||||
ress\"P\n\x0cSolanaSignTx\x12\x1b\n\taddress_n\x18\x01\x20\x03(\rR\x08ad\
|
ress\"\xa6\x01\n\x18SolanaTxTokenAccountInfo\x12!\n\x0cbase_address\x18\
|
||||||
dressN\x12#\n\rserialized_tx\x18\x02\x20\x02(\x0cR\x0cserializedTx\"1\n\
|
\x01\x20\x02(\tR\x0bbaseAddress\x12#\n\rtoken_program\x18\x02\x20\x02(\t\
|
||||||
\x11SolanaTxSignature\x12\x1c\n\tsignature\x18\x01\x20\x02(\x0cR\tsignat\
|
R\x0ctokenProgram\x12\x1d\n\ntoken_mint\x18\x03\x20\x02(\tR\ttokenMint\
|
||||||
ure\
|
\x12#\n\rtoken_account\x18\x04\x20\x02(\tR\x0ctokenAccount\"\x7f\n\x16So\
|
||||||
|
lanaTxAdditionalInfo\x12e\n\x14token_accounts_infos\x18\x01\x20\x03(\x0b\
|
||||||
|
23.hw.trezor.messages.solana.SolanaTxTokenAccountInfoR\x12tokenAccountsI\
|
||||||
|
nfos\"\xac\x01\n\x0cSolanaSignTx\x12\x1b\n\taddress_n\x18\x01\x20\x03(\r\
|
||||||
|
R\x08addressN\x12#\n\rserialized_tx\x18\x02\x20\x02(\x0cR\x0cserializedT\
|
||||||
|
x\x12Z\n\x0fadditional_info\x18\x03\x20\x01(\x0b21.hw.trezor.messages.so\
|
||||||
|
lana.SolanaTxAdditionalInfoR\x0eadditionalInfo\"1\n\x11SolanaTxSignature\
|
||||||
|
\x12\x1c\n\tsignature\x18\x01\x20\x02(\x0cR\tsignature\
|
||||||
";
|
";
|
||||||
|
|
||||||
/// `FileDescriptorProto` object which was a source for this generated file
|
/// `FileDescriptorProto` object which was a source for this generated file
|
||||||
@ -1082,11 +1573,13 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
|
|||||||
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
|
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
|
||||||
let mut deps = ::std::vec::Vec::with_capacity(1);
|
let mut deps = ::std::vec::Vec::with_capacity(1);
|
||||||
deps.push(super::messages_common::file_descriptor().clone());
|
deps.push(super::messages_common::file_descriptor().clone());
|
||||||
let mut messages = ::std::vec::Vec::with_capacity(6);
|
let mut messages = ::std::vec::Vec::with_capacity(8);
|
||||||
messages.push(SolanaGetPublicKey::generated_message_descriptor_data());
|
messages.push(SolanaGetPublicKey::generated_message_descriptor_data());
|
||||||
messages.push(SolanaPublicKey::generated_message_descriptor_data());
|
messages.push(SolanaPublicKey::generated_message_descriptor_data());
|
||||||
messages.push(SolanaGetAddress::generated_message_descriptor_data());
|
messages.push(SolanaGetAddress::generated_message_descriptor_data());
|
||||||
messages.push(SolanaAddress::generated_message_descriptor_data());
|
messages.push(SolanaAddress::generated_message_descriptor_data());
|
||||||
|
messages.push(SolanaTxTokenAccountInfo::generated_message_descriptor_data());
|
||||||
|
messages.push(SolanaTxAdditionalInfo::generated_message_descriptor_data());
|
||||||
messages.push(SolanaSignTx::generated_message_descriptor_data());
|
messages.push(SolanaSignTx::generated_message_descriptor_data());
|
||||||
messages.push(SolanaTxSignature::generated_message_descriptor_data());
|
messages.push(SolanaTxSignature::generated_message_descriptor_data());
|
||||||
let mut enums = ::std::vec::Vec::with_capacity(0);
|
let mut enums = ::std::vec::Vec::with_capacity(0);
|
||||||
|
Loading…
Reference in New Issue
Block a user