mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-21 02:26:10 +00:00
feat(core/cardano): enable typing for Cardano app
This commit is contained in:
parent
32c37aa9cd
commit
ccd241fe55
@ -44,9 +44,9 @@ enum CardanoPoolRelayType {
|
||||
* @embed
|
||||
*/
|
||||
message CardanoBlockchainPointerType {
|
||||
optional uint32 block_index = 1;
|
||||
optional uint32 tx_index = 2;
|
||||
optional uint32 certificate_index = 3;
|
||||
required uint32 block_index = 1;
|
||||
required uint32 tx_index = 2;
|
||||
required uint32 certificate_index = 3;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,7 +58,7 @@ message CardanoBlockchainPointerType {
|
||||
* @embed
|
||||
*/
|
||||
message CardanoAddressParametersType {
|
||||
optional CardanoAddressType address_type = 1; // one of the CardanoAddressType-s
|
||||
required CardanoAddressType address_type = 1; // one of the CardanoAddressType-s
|
||||
repeated uint32 address_n = 2; // BIP-32-style path to derive the spending key from master node
|
||||
repeated uint32 address_n_staking = 3; // BIP-32-style path to derive staking key from master node
|
||||
optional bytes staking_key_hash = 4; // staking key can be derived from address_n_staking, or
|
||||
@ -75,10 +75,10 @@ message CardanoAddressParametersType {
|
||||
*/
|
||||
message CardanoGetAddress {
|
||||
// repeated uint32 address_n = 1; // moved to address_parameters
|
||||
optional bool show_display = 2; // optionally prompt for confirmation on trezor display
|
||||
optional uint32 protocol_magic = 3; // network's protocol magic - needed for Byron addresses on testnets
|
||||
optional uint32 network_id = 4; // network id - mainnet or testnet
|
||||
optional CardanoAddressParametersType address_parameters = 5; // parameters used to derive the address
|
||||
optional bool show_display = 2 [default=false]; // optionally prompt for confirmation on trezor display
|
||||
required uint32 protocol_magic = 3; // network's protocol magic - needed for Byron addresses on testnets
|
||||
required uint32 network_id = 4; // network id - mainnet or testnet
|
||||
required CardanoAddressParametersType address_parameters = 5; // parameters used to derive the address
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,7 +86,7 @@ message CardanoGetAddress {
|
||||
* @end
|
||||
*/
|
||||
message CardanoAddress {
|
||||
optional string address = 1; // Base58 cardano address
|
||||
required string address = 1; // Base58 cardano address
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,8 +105,8 @@ message CardanoGetPublicKey {
|
||||
* @end
|
||||
*/
|
||||
message CardanoPublicKey {
|
||||
optional string xpub = 1; // Xpub key
|
||||
optional hw.trezor.messages.common.HDNodeType node = 2; // BIP-32 public node
|
||||
required string xpub = 1; // Xpub key
|
||||
required hw.trezor.messages.common.HDNodeType node = 2; // BIP-32 public node
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,10 +119,10 @@ message CardanoSignTx {
|
||||
repeated CardanoTxInputType inputs = 1; // inputs to be used in transaction
|
||||
repeated CardanoTxOutputType outputs = 2; // outputs to be used in transaction
|
||||
// optional uint32 transactions_count = 3; // left as a comment so we know to skip the id 3 in the future
|
||||
optional uint32 protocol_magic = 5; // network's protocol magic
|
||||
optional uint64 fee = 6; // transaction fee - added in shelley
|
||||
required uint32 protocol_magic = 5; // network's protocol magic
|
||||
required uint64 fee = 6; // transaction fee - added in shelley
|
||||
optional uint64 ttl = 7; // transaction ttl - added in shelley
|
||||
optional uint32 network_id = 8; // network id - mainnet or testnet
|
||||
required uint32 network_id = 8; // network id - mainnet or testnet
|
||||
repeated CardanoTxCertificateType certificates = 9; // transaction certificates - added in shelley
|
||||
repeated CardanoTxWithdrawalType withdrawals = 10; // transaction withdrawals - added in shelley
|
||||
optional bytes metadata = 11; // transaction metadata - added in shelley
|
||||
@ -133,8 +133,8 @@ message CardanoSignTx {
|
||||
*/
|
||||
message CardanoTxInputType {
|
||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||
optional bytes prev_hash = 2; // hash of previous transaction output to spend by this input
|
||||
optional uint32 prev_index = 3; // index of previous output to spend
|
||||
required bytes prev_hash = 2; // hash of previous transaction output to spend by this input
|
||||
required uint32 prev_index = 3; // index of previous output to spend
|
||||
// left as a comment so we know to skip the id 4 in the future
|
||||
// optional uint32 type = 4;
|
||||
}
|
||||
@ -144,7 +144,7 @@ message CardanoSignTx {
|
||||
message CardanoTxOutputType {
|
||||
optional string address = 1; // target coin address in bech32 or base58
|
||||
// repeated uint32 address_n = 2; // moved to address_parameters
|
||||
optional uint64 amount = 3; // amount to spend
|
||||
required uint64 amount = 3; // amount to spend
|
||||
optional CardanoAddressParametersType address_parameters = 4; // parameters used to derive the address
|
||||
repeated CardanoAssetGroupType token_bundle = 5; // custom assets - added in mary
|
||||
}
|
||||
@ -206,7 +206,7 @@ message CardanoSignTx {
|
||||
* Structure representing cardano transaction certificate
|
||||
*/
|
||||
message CardanoTxCertificateType {
|
||||
optional CardanoCertificateType type = 1; // certificate type
|
||||
required CardanoCertificateType type = 1; // certificate type
|
||||
repeated uint32 path = 2; // BIP-32 path to derive (staking) key
|
||||
optional bytes pool = 3; // pool hash
|
||||
optional CardanoPoolParametersType pool_parameters = 4; // used for stake pool registration certificate
|
||||
@ -216,7 +216,7 @@ message CardanoSignTx {
|
||||
*/
|
||||
message CardanoTxWithdrawalType {
|
||||
repeated uint32 path = 1;
|
||||
optional uint64 amount = 2;
|
||||
required uint64 amount = 2;
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,6 +225,6 @@ message CardanoSignTx {
|
||||
* @end
|
||||
*/
|
||||
message CardanoSignedTx {
|
||||
optional bytes tx_hash = 1; // hash of the transaction body
|
||||
optional bytes serialized_tx = 2; // serialized, signed transaction
|
||||
required bytes tx_hash = 1; // hash of the transaction body
|
||||
required bytes serialized_tx = 2; // serialized, signed transaction
|
||||
}
|
||||
|
@ -107,6 +107,7 @@ mypy:
|
||||
mypy --config-file ../setup.cfg \
|
||||
src/main.py \
|
||||
src/apps/bitcoin \
|
||||
src/apps/cardano \
|
||||
src/apps/webauthn
|
||||
|
||||
## code generation:
|
||||
|
@ -586,7 +586,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_bip32_from_seed_obj,
|
||||
|
||||
#if !BITCOIN_ONLY
|
||||
|
||||
/// def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> bytes:
|
||||
/// def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> HDNode:
|
||||
/// """
|
||||
/// Construct a HD node from a BIP-0039 mnemonic using the Icarus derivation
|
||||
/// scheme, aka v2 derivation scheme.
|
||||
|
@ -117,7 +117,7 @@ def from_seed(seed: bytes, curve_name: str) -> HDNode:
|
||||
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-bip32.h
|
||||
def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> bytes:
|
||||
def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> HDNode:
|
||||
"""
|
||||
Construct a HD node from a BIP-0039 mnemonic using the Icarus derivation
|
||||
scheme, aka v2 derivation scheme.
|
||||
|
@ -1,6 +1,6 @@
|
||||
from trezor import wire
|
||||
from trezor.crypto import base58, hashlib
|
||||
from trezor.messages import CardanoAddressParametersType, CardanoAddressType
|
||||
from trezor.messages import CardanoAddressType
|
||||
|
||||
from apps.common.seed import remove_ed25519_prefix
|
||||
|
||||
@ -11,9 +11,14 @@ from .helpers.utils import variable_length_encode
|
||||
from .seed import is_byron_path, is_shelley_path
|
||||
|
||||
if False:
|
||||
from typing import List
|
||||
from trezor.messages import CardanoBlockchainPointerType
|
||||
from trezor.messages.CardanoAddressParametersType import EnumTypeCardanoAddressType
|
||||
from typing import List, Optional
|
||||
from trezor.messages.CardanoBlockchainPointerType import (
|
||||
CardanoBlockchainPointerType,
|
||||
)
|
||||
from trezor.messages.CardanoAddressParametersType import (
|
||||
CardanoAddressParametersType,
|
||||
EnumTypeCardanoAddressType,
|
||||
)
|
||||
from . import seed
|
||||
|
||||
ADDRESS_TYPES_SHELLEY = (
|
||||
@ -84,8 +89,8 @@ def get_address_bytes_unsafe(address: str) -> bytes:
|
||||
return address_bytes
|
||||
|
||||
|
||||
def _get_address_type(address: bytes) -> int:
|
||||
return address[0] >> 4
|
||||
def _get_address_type(address: bytes) -> EnumTypeCardanoAddressType:
|
||||
return address[0] >> 4 # type: ignore
|
||||
|
||||
|
||||
def _validate_shelley_address(
|
||||
@ -93,14 +98,12 @@ def _validate_shelley_address(
|
||||
) -> None:
|
||||
address_type = _get_address_type(address_bytes)
|
||||
|
||||
_validate_address_size(address_bytes, address_type)
|
||||
_validate_address_size(address_bytes)
|
||||
_validate_address_bech32_hrp(address_str, address_type, network_id)
|
||||
_validate_address_network_id(address_bytes, network_id)
|
||||
|
||||
|
||||
def _validate_address_size(
|
||||
address_bytes: bytes, address_type: EnumTypeCardanoAddressType
|
||||
) -> None:
|
||||
def _validate_address_size(address_bytes: bytes) -> None:
|
||||
if not (MIN_ADDRESS_BYTES_LENGTH <= len(address_bytes) <= MAX_ADDRESS_BYTES_LENGTH):
|
||||
raise INVALID_ADDRESS
|
||||
|
||||
@ -220,6 +223,8 @@ def _derive_shelley_address(
|
||||
elif parameters.address_type == CardanoAddressType.ENTERPRISE:
|
||||
address = _derive_enterprise_address(keychain, parameters.address_n, network_id)
|
||||
elif parameters.address_type == CardanoAddressType.POINTER:
|
||||
if parameters.certificate_pointer is None:
|
||||
raise wire.DataError("Certificate pointer data missing!")
|
||||
address = _derive_pointer_address(
|
||||
keychain,
|
||||
parameters.address_n,
|
||||
@ -245,7 +250,7 @@ def _derive_base_address(
|
||||
keychain: seed.Keychain,
|
||||
path: List[int],
|
||||
staking_path: List[int],
|
||||
staking_key_hash: bytes,
|
||||
staking_key_hash: Optional[bytes],
|
||||
network_id: int,
|
||||
) -> bytes:
|
||||
header = _create_address_header(CardanoAddressType.BASE, network_id)
|
||||
@ -261,7 +266,7 @@ def _derive_base_address(
|
||||
|
||||
def _validate_base_address_staking_info(
|
||||
staking_path: List[int],
|
||||
staking_key_hash: bytes,
|
||||
staking_key_hash: Optional[bytes],
|
||||
) -> None:
|
||||
if (staking_key_hash is None) == (not staking_path):
|
||||
raise wire.DataError(
|
||||
@ -286,14 +291,6 @@ def _derive_pointer_address(
|
||||
|
||||
|
||||
def _encode_certificate_pointer(pointer: CardanoBlockchainPointerType) -> bytes:
|
||||
if (
|
||||
pointer is None
|
||||
or pointer.block_index is None
|
||||
or pointer.tx_index is None
|
||||
or pointer.certificate_index is None
|
||||
):
|
||||
raise wire.DataError("Invalid pointer!")
|
||||
|
||||
block_index_encoded = variable_length_encode(pointer.block_index)
|
||||
tx_index_encoded = variable_length_encode(pointer.tx_index)
|
||||
certificate_index_encoded = variable_length_encode(pointer.certificate_index)
|
||||
|
@ -21,7 +21,7 @@ with base58 encoding and all the nuances of Byron addresses.
|
||||
"""
|
||||
|
||||
|
||||
def _encode_address_raw(address_data_encoded) -> bytes:
|
||||
def _encode_address_raw(address_data_encoded: bytes) -> bytes:
|
||||
return cbor.encode(
|
||||
[cbor.Tagged(24, address_data_encoded), crc.crc32(address_data_encoded)]
|
||||
)
|
||||
|
@ -11,6 +11,8 @@ from .helpers import INVALID_CERTIFICATE, LOVELACE_MAX_SUPPLY
|
||||
from .helpers.paths import SCHEMA_STAKING
|
||||
|
||||
if False:
|
||||
from typing import List, Optional
|
||||
|
||||
from trezor.messages.CardanoTxCertificateType import CardanoTxCertificateType
|
||||
from trezor.messages.CardanoPoolParametersType import CardanoPoolParametersType
|
||||
from trezor.messages.CardanoPoolRelayParametersType import (
|
||||
@ -18,10 +20,10 @@ if False:
|
||||
)
|
||||
from trezor.messages.CardanoPoolOwnerType import CardanoPoolOwnerType
|
||||
from trezor.messages.CardanoPoolMetadataType import CardanoPoolMetadataType
|
||||
from typing import List, Optional, Union, Tuple, Any
|
||||
from . import seed
|
||||
|
||||
CborSequence = Union[List[Any], Tuple[Any, ...]]
|
||||
from apps.common.cbor import CborSequence
|
||||
|
||||
from . import seed
|
||||
|
||||
POOL_HASH_SIZE = 28
|
||||
VRF_KEY_HASH_SIZE = 32
|
||||
|
@ -17,7 +17,10 @@ from .layout import (
|
||||
from .sign_tx import validate_network_info
|
||||
|
||||
if False:
|
||||
from trezor.messages import CardanoAddressParametersType, CardanoGetAddress
|
||||
from trezor.messages.CardanoAddressParametersType import (
|
||||
CardanoAddressParametersType,
|
||||
)
|
||||
from trezor.messages.CardanoGetAddress import CardanoGetAddress
|
||||
|
||||
|
||||
@seed.with_keychain
|
||||
@ -95,4 +98,6 @@ async def _show_staking_warnings(
|
||||
address_parameters.staking_key_hash,
|
||||
)
|
||||
elif staking_type == staking_use_cases.POINTER_ADDRESS:
|
||||
# ensured in _derive_shelley_address:
|
||||
assert address_parameters.certificate_pointer is not None
|
||||
await show_warning_address_pointer(ctx, address_parameters.certificate_pointer)
|
||||
|
@ -12,13 +12,13 @@ from .helpers.paths import SCHEMA_PUBKEY
|
||||
|
||||
if False:
|
||||
from typing import List
|
||||
from trezor.messages import CardanoGetPublicKey
|
||||
from trezor.messages.CardanoGetPublicKey import CardanoGetPublicKey
|
||||
|
||||
|
||||
@seed.with_keychain
|
||||
async def get_public_key(
|
||||
ctx: wire.Context, msg: CardanoGetPublicKey, keychain: seed.Keychain
|
||||
):
|
||||
) -> CardanoPublicKey:
|
||||
await paths.validate_path(
|
||||
ctx,
|
||||
keychain,
|
||||
|
@ -10,6 +10,8 @@ HRP_TESTNET_REWARD_ADDRESS = "stake_test"
|
||||
|
||||
def encode(hrp: str, data: bytes) -> str:
|
||||
converted_bits = bech32.convertbits(data, 8, 5)
|
||||
if converted_bits is None:
|
||||
raise ValueError
|
||||
return bech32.bech32_encode(hrp, converted_bits)
|
||||
|
||||
|
||||
@ -18,12 +20,14 @@ def decode_unsafe(bech: str) -> bytes:
|
||||
return decode(hrp, bech)
|
||||
|
||||
|
||||
def get_hrp(bech: str):
|
||||
def get_hrp(bech: str) -> str:
|
||||
return bech.rsplit(HRP_SEPARATOR, 1)[0]
|
||||
|
||||
|
||||
def decode(hrp: str, bech: str) -> bytes:
|
||||
decoded_hrp, data = bech32.bech32_decode(bech, 130)
|
||||
if data is None:
|
||||
raise ValueError
|
||||
if decoded_hrp != hrp:
|
||||
raise ValueError
|
||||
|
||||
|
@ -7,8 +7,10 @@ from .utils import to_account_path
|
||||
|
||||
if False:
|
||||
from typing import List
|
||||
from trezor.messages import CardanoAddressParametersType
|
||||
from .. import seed
|
||||
from trezor.messages.CardanoAddressParametersType import (
|
||||
CardanoAddressParametersType,
|
||||
)
|
||||
from ..seed import Keychain
|
||||
|
||||
|
||||
"""
|
||||
@ -24,9 +26,7 @@ MISMATCH = 2
|
||||
POINTER_ADDRESS = 3
|
||||
|
||||
|
||||
def get(
|
||||
keychain: seed.Keychain, address_parameters: CardanoAddressParametersType
|
||||
) -> int:
|
||||
def get(keychain: Keychain, address_parameters: CardanoAddressParametersType) -> int:
|
||||
address_type = address_parameters.address_type
|
||||
if address_type == CardanoAddressType.BASE:
|
||||
if not SCHEMA_ADDRESS.match(address_parameters.address_n):
|
||||
|
@ -6,8 +6,6 @@ from trezor.messages import (
|
||||
ButtonRequestType,
|
||||
CardanoAddressType,
|
||||
CardanoCertificateType,
|
||||
CardanoPoolMetadataType,
|
||||
CardanoPoolOwnerType,
|
||||
)
|
||||
from trezor.strings import format_amount
|
||||
from trezor.ui.button import ButtonDefault
|
||||
@ -30,14 +28,16 @@ from .helpers.utils import format_account_number, format_optional_int, to_accoun
|
||||
if False:
|
||||
from typing import List, Optional
|
||||
from trezor import wire
|
||||
from trezor.messages import (
|
||||
from trezor.messages.CardanoBlockchainPointerType import (
|
||||
CardanoBlockchainPointerType,
|
||||
CardanoTxCertificateType,
|
||||
CardanoTxWithdrawalType,
|
||||
CardanoPoolParametersType,
|
||||
CardanoAssetGroupType,
|
||||
CardanoTokenType,
|
||||
)
|
||||
from trezor.messages.CardanoTxCertificateType import CardanoTxCertificateType
|
||||
from trezor.messages.CardanoTxWithdrawalType import CardanoTxWithdrawalType
|
||||
from trezor.messages.CardanoPoolParametersType import CardanoPoolParametersType
|
||||
from trezor.messages.CardanoPoolOwnerType import CardanoPoolOwnerType
|
||||
from trezor.messages.CardanoPoolMetadataType import CardanoPoolMetadataType
|
||||
from trezor.messages.CardanoAssetGroupType import CardanoAssetGroupType
|
||||
from trezor.messages.CardanoTokenType import CardanoTokenType
|
||||
from trezor.messages.CardanoAddressParametersType import EnumTypeCardanoAddressType
|
||||
|
||||
|
||||
@ -85,7 +85,8 @@ async def confirm_sending(
|
||||
to_lines = list(chunks(to, 17))
|
||||
page1.bold(to_lines[0])
|
||||
|
||||
pages = [page1] + _paginate_lines(to_lines, 1, "Confirm transaction", ui.ICON_SEND)
|
||||
comp: ui.Component = page1 # otherwise `[page1]` is of the wrong type
|
||||
pages = [comp] + _paginate_lines(to_lines, 1, "Confirm transaction", ui.ICON_SEND)
|
||||
|
||||
await require_confirm(ctx, Paginated(pages))
|
||||
|
||||
@ -215,7 +216,7 @@ async def show_warning_tx_staking_key_hash(
|
||||
|
||||
|
||||
async def confirm_transaction(
|
||||
ctx,
|
||||
ctx: wire.Context,
|
||||
amount: int,
|
||||
fee: int,
|
||||
protocol_magic: int,
|
||||
@ -224,7 +225,7 @@ async def confirm_transaction(
|
||||
has_metadata: bool,
|
||||
is_network_id_verifiable: bool,
|
||||
) -> None:
|
||||
pages = []
|
||||
pages: List[ui.Component] = []
|
||||
|
||||
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page1.normal("Transaction amount:")
|
||||
@ -257,7 +258,7 @@ async def confirm_certificate(
|
||||
# in this call
|
||||
assert certificate.type != CardanoCertificateType.STAKE_POOL_REGISTRATION
|
||||
|
||||
pages = []
|
||||
pages: List[ui.Component] = []
|
||||
|
||||
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page1.normal("Confirm:")
|
||||
@ -267,6 +268,7 @@ async def confirm_certificate(
|
||||
pages.append(page1)
|
||||
|
||||
if certificate.type == CardanoCertificateType.STAKE_DELEGATION:
|
||||
assert certificate.pool is not None # validate_certificate
|
||||
page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page2.normal("to pool:")
|
||||
page2.bold(hexlify(certificate.pool).decode())
|
||||
@ -304,11 +306,11 @@ async def confirm_stake_pool_parameters(
|
||||
|
||||
async def confirm_stake_pool_owners(
|
||||
ctx: wire.Context,
|
||||
keychain: seed.keychain,
|
||||
keychain: seed.Keychain,
|
||||
owners: List[CardanoPoolOwnerType],
|
||||
network_id: int,
|
||||
) -> None:
|
||||
pages = []
|
||||
pages: List[ui.Component] = []
|
||||
for index, owner in enumerate(owners, 1):
|
||||
page = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page.normal("Pool owner #%d:" % (index))
|
||||
@ -324,6 +326,7 @@ async def confirm_stake_pool_owners(
|
||||
)
|
||||
)
|
||||
else:
|
||||
assert owner.staking_key_hash is not None # validate_pool_owners
|
||||
page.bold(
|
||||
encode_human_readable_address(
|
||||
pack_reward_address_bytes(owner.staking_key_hash, network_id)
|
||||
@ -360,7 +363,10 @@ async def confirm_stake_pool_metadata(
|
||||
|
||||
|
||||
async def confirm_transaction_network_ttl(
|
||||
ctx, protocol_magic: int, ttl: Optional[int], validity_interval_start: Optional[int]
|
||||
ctx: wire.Context,
|
||||
protocol_magic: int,
|
||||
ttl: Optional[int],
|
||||
validity_interval_start: Optional[int],
|
||||
) -> None:
|
||||
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||
page1.normal("Network:")
|
||||
@ -428,13 +434,17 @@ async def show_address(
|
||||
for address_line in address_lines[: lines_per_page - lines_used_on_first_page]:
|
||||
page1.bold(address_line)
|
||||
|
||||
pages: List[ui.Component] = []
|
||||
pages.append(page1)
|
||||
# append remaining pages containing the rest of the address
|
||||
pages = [page1] + _paginate_lines(
|
||||
address_lines,
|
||||
lines_per_page - lines_used_on_first_page,
|
||||
address_type_label,
|
||||
ui.ICON_RECEIVE,
|
||||
lines_per_page,
|
||||
pages.extend(
|
||||
_paginate_lines(
|
||||
address_lines,
|
||||
lines_per_page - lines_used_on_first_page,
|
||||
address_type_label,
|
||||
ui.ICON_RECEIVE,
|
||||
lines_per_page,
|
||||
)
|
||||
)
|
||||
|
||||
return await confirm(
|
||||
@ -449,7 +459,7 @@ async def show_address(
|
||||
def _paginate_lines(
|
||||
lines: List[str], offset: int, desc: str, icon: str, lines_per_page: int = 4
|
||||
) -> List[ui.Component]:
|
||||
pages = []
|
||||
pages: List[ui.Component] = []
|
||||
if len(lines) > offset:
|
||||
to_pages = list(chunks(lines[offset:], lines_per_page))
|
||||
for page in to_pages:
|
||||
@ -465,7 +475,7 @@ async def show_warning_address_foreign_staking_key(
|
||||
ctx: wire.Context,
|
||||
account_path: List[int],
|
||||
staking_account_path: List[int],
|
||||
staking_key_hash: bytes,
|
||||
staking_key_hash: Optional[bytes],
|
||||
) -> None:
|
||||
page1 = Text("Warning", ui.ICON_WRONG, ui.RED)
|
||||
page1.normal("Stake rights associated")
|
||||
@ -480,6 +490,7 @@ async def show_warning_address_foreign_staking_key(
|
||||
page2.bold(address_n_to_str(staking_account_path))
|
||||
page2.br_half()
|
||||
else:
|
||||
assert staking_key_hash is not None # _validate_base_address_staking_info
|
||||
page2.normal("Staking key:")
|
||||
page2.bold(hexlify(staking_key_hash).decode())
|
||||
page2.normal("Continue?")
|
||||
|
@ -9,8 +9,12 @@ from apps.common.seed import get_seed
|
||||
from .helpers import paths
|
||||
|
||||
if False:
|
||||
from typing import Callable, Awaitable
|
||||
|
||||
from apps.common.paths import Bip32Path
|
||||
from apps.common.keychain import MsgIn, MsgOut, Handler, HandlerWithKeychain
|
||||
from apps.common.keychain import MsgIn, MsgOut, Handler
|
||||
|
||||
HandlerWithKeychain = Callable[[wire.Context, MsgIn, "Keychain"], Awaitable[MsgOut]]
|
||||
|
||||
|
||||
class Keychain:
|
||||
@ -52,11 +56,11 @@ class Keychain:
|
||||
# self.root.__del__()
|
||||
|
||||
|
||||
def is_byron_path(path: Bip32Path):
|
||||
def is_byron_path(path: Bip32Path) -> bool:
|
||||
return path[: len(paths.BYRON_ROOT)] == paths.BYRON_ROOT
|
||||
|
||||
|
||||
def is_shelley_path(path: Bip32Path):
|
||||
def is_shelley_path(path: Bip32Path) -> bool:
|
||||
return path[: len(paths.SHELLEY_ROOT)] == paths.SHELLEY_ROOT
|
||||
|
||||
|
||||
@ -75,7 +79,9 @@ async def get_keychain(ctx: wire.Context) -> Keychain:
|
||||
if mnemonic.is_bip39():
|
||||
passphrase = await get_passphrase(ctx)
|
||||
# derive the root node from mnemonic and passphrase via Cardano Icarus algorithm
|
||||
root = bip32.from_mnemonic_cardano(mnemonic.get_secret().decode(), passphrase)
|
||||
secret_bytes = mnemonic.get_secret()
|
||||
assert secret_bytes is not None
|
||||
root = bip32.from_mnemonic_cardano(secret_bytes.decode(), passphrase)
|
||||
else:
|
||||
# derive the root node via SLIP-0023
|
||||
seed = await get_seed(ctx)
|
||||
|
@ -57,13 +57,16 @@ from .layout import (
|
||||
from .seed import is_byron_path, is_shelley_path
|
||||
|
||||
if False:
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from trezor.messages.CardanoSignTx import CardanoSignTx
|
||||
from trezor.messages.CardanoTxCertificateType import CardanoTxCertificateType
|
||||
from trezor.messages.CardanoTxInputType import CardanoTxInputType
|
||||
from trezor.messages.CardanoTxOutputType import CardanoTxOutputType
|
||||
from trezor.messages.CardanoTxWithdrawalType import CardanoTxWithdrawalType
|
||||
from trezor.messages.CardanoAssetGroupType import CardanoAssetGroupType
|
||||
from typing import Dict, List, Tuple, Union
|
||||
|
||||
from apps.common.cbor import CborSequence
|
||||
|
||||
CborizedTokenBundle = Dict[bytes, Dict[bytes, int]]
|
||||
CborizedTxOutput = Tuple[bytes, Union[int, Tuple[int, CborizedTokenBundle]]]
|
||||
@ -156,7 +159,7 @@ async def _sign_stake_pool_registration_tx(
|
||||
return tx
|
||||
|
||||
|
||||
def _has_stake_pool_registration(msg: CardanoSignTx):
|
||||
def _has_stake_pool_registration(msg: CardanoSignTx) -> bool:
|
||||
return any(
|
||||
cert.type == CardanoCertificateType.STAKE_POOL_REGISTRATION
|
||||
for cert in msg.certificates
|
||||
@ -176,7 +179,9 @@ def validate_network_info(network_id: int, protocol_magic: int) -> None:
|
||||
raise wire.ProcessError("Invalid network id/protocol magic combination!")
|
||||
|
||||
|
||||
def _validate_stake_pool_registration_tx_structure(msg: CardanoSignTx):
|
||||
def _validate_stake_pool_registration_tx_structure(msg: CardanoSignTx) -> None:
|
||||
# ensures that there is exactly one certificate, which is stake pool registration,
|
||||
# and no withdrawals
|
||||
if (
|
||||
len(msg.certificates) != 1
|
||||
or not _has_stake_pool_registration(msg)
|
||||
@ -264,7 +269,7 @@ def _validate_max_tx_output_size(
|
||||
)
|
||||
|
||||
|
||||
def _ensure_no_signing_inputs(inputs: List[CardanoTxInputType]):
|
||||
def _ensure_no_signing_inputs(inputs: List[CardanoTxInputType]) -> None:
|
||||
if any(i.address_n for i in inputs):
|
||||
raise INVALID_STAKEPOOL_REGISTRATION_TX_INPUTS
|
||||
|
||||
@ -285,7 +290,7 @@ def _validate_withdrawals(withdrawals: List[CardanoTxWithdrawalType]) -> None:
|
||||
raise INVALID_WITHDRAWAL
|
||||
|
||||
|
||||
def _validate_metadata(metadata: bytes) -> None:
|
||||
def _validate_metadata(metadata: Optional[bytes]) -> None:
|
||||
if not metadata:
|
||||
return
|
||||
|
||||
@ -388,7 +393,7 @@ def _cborize_output(
|
||||
keychain, output.address_parameters, protocol_magic, network_id
|
||||
)
|
||||
else:
|
||||
# output address is validated in _validate_outputs before this happens
|
||||
assert output.address is not None # _validate_outputs
|
||||
address = get_address_bytes_unsafe(output.address)
|
||||
|
||||
if not output.token_bundle:
|
||||
@ -400,11 +405,11 @@ def _cborize_output(
|
||||
def _cborize_token_bundle(
|
||||
token_bundle: List[CardanoAssetGroupType],
|
||||
) -> CborizedTokenBundle:
|
||||
result = {}
|
||||
result: CborizedTokenBundle = {}
|
||||
|
||||
for token_group in token_bundle:
|
||||
cborized_policy_id = bytes(token_group.policy_id)
|
||||
result[cborized_policy_id] = cborized_token_group = {}
|
||||
cborized_token_group = result[cborized_policy_id] = {}
|
||||
|
||||
for token in token_group.tokens:
|
||||
cborized_asset_name = bytes(token.asset_name_bytes)
|
||||
@ -416,7 +421,7 @@ def _cborize_token_bundle(
|
||||
def _cborize_certificates(
|
||||
keychain: seed.Keychain,
|
||||
certificates: List[CardanoTxCertificateType],
|
||||
) -> List[Tuple]:
|
||||
) -> List[CborSequence]:
|
||||
return [cborize_certificate(keychain, cert) for cert in certificates]
|
||||
|
||||
|
||||
@ -469,7 +474,7 @@ def _cborize_witnesses(
|
||||
|
||||
# use key 0 for shelley witnesses and key 2 for byron witnesses
|
||||
# according to the spec in shelley.cddl in cardano-ledger-specs
|
||||
witnesses = {}
|
||||
witnesses: Dict[Any, Any] = {}
|
||||
if shelley_witnesses:
|
||||
witnesses[0] = shelley_witnesses
|
||||
if byron_witnesses:
|
||||
@ -499,6 +504,8 @@ def _cborize_shelley_witnesses(
|
||||
):
|
||||
paths.add(tuple(certificate.path))
|
||||
elif certificate.type == CardanoCertificateType.STAKE_POOL_REGISTRATION:
|
||||
# ensured by validate_certificate:
|
||||
assert certificate.pool_parameters is not None # validate_certificate
|
||||
for pool_owner in certificate.pool_parameters.owners:
|
||||
if pool_owner.staking_key_path:
|
||||
paths.add(tuple(pool_owner.staking_key_path))
|
||||
@ -514,7 +521,7 @@ def _cborize_shelley_witnesses(
|
||||
|
||||
def _cborize_shelley_witness(
|
||||
keychain: seed.Keychain, tx_body_hash: bytes, path: List[int]
|
||||
) -> List[Tuple[bytes, bytes]]:
|
||||
) -> Tuple[bytes, bytes]:
|
||||
node = keychain.derive(path)
|
||||
|
||||
signature = ed25519.sign_ext(
|
||||
@ -587,6 +594,9 @@ async def _show_stake_pool_registration_tx(
|
||||
) -> None:
|
||||
stake_pool_registration_certificate = msg.certificates[0]
|
||||
pool_parameters = stake_pool_registration_certificate.pool_parameters
|
||||
# _validate_stake_pool_registration_tx_structure ensures that there is only one
|
||||
# certificate, and validate_certificate ensures that the structure is valid
|
||||
assert pool_parameters is not None
|
||||
|
||||
# display the transaction (certificate) in UI
|
||||
await confirm_stake_pool_parameters(
|
||||
@ -619,6 +629,7 @@ async def _show_outputs(
|
||||
if _should_hide_output(output.address_parameters.address_n, msg.inputs):
|
||||
continue
|
||||
else:
|
||||
assert output.address is not None # _validate_outputs
|
||||
address = output.address
|
||||
|
||||
total_amount += output.amount
|
||||
@ -637,13 +648,15 @@ async def _show_change_output_staking_warnings(
|
||||
address_parameters: CardanoAddressParametersType,
|
||||
address: str,
|
||||
amount: int,
|
||||
):
|
||||
) -> None:
|
||||
address_type = address_parameters.address_type
|
||||
|
||||
staking_use_case = staking_use_cases.get(keychain, address_parameters)
|
||||
if staking_use_case == staking_use_cases.NO_STAKING:
|
||||
await show_warning_tx_no_staking_info(ctx, address_type, amount)
|
||||
elif staking_use_case == staking_use_cases.POINTER_ADDRESS:
|
||||
# ensured in _derive_shelley_address:
|
||||
assert address_parameters.certificate_pointer is not None
|
||||
await show_warning_tx_pointer_address(
|
||||
ctx,
|
||||
address_parameters.certificate_pointer,
|
||||
@ -657,6 +670,8 @@ async def _show_change_output_staking_warnings(
|
||||
amount,
|
||||
)
|
||||
else:
|
||||
# ensured in _validate_base_address_staking_info:
|
||||
assert address_parameters.staking_key_hash
|
||||
await show_warning_tx_staking_key_hash(
|
||||
ctx,
|
||||
address_parameters.staking_key_hash,
|
||||
|
@ -8,9 +8,10 @@ from micropython import const
|
||||
from trezor import log
|
||||
|
||||
if False:
|
||||
from typing import Any, Iterable, List, Tuple
|
||||
from typing import Any, Iterable, List, Tuple, Union
|
||||
|
||||
Value = Any
|
||||
CborSequence = Union[List[Value], Tuple[Value, ...]]
|
||||
|
||||
_CBOR_TYPE_MASK = const(0xE0)
|
||||
_CBOR_INFO_BITS = const(0x1F)
|
||||
|
@ -22,9 +22,6 @@ if False:
|
||||
from typing_extensions import Protocol
|
||||
from trezor import wire
|
||||
|
||||
# XXX this is a circular import, but it's only for typing
|
||||
from .keychain import Keychain
|
||||
|
||||
Bip32Path = Sequence[int]
|
||||
Slip21Path = Sequence[bytes]
|
||||
PathType = TypeVar("PathType", Bip32Path, Slip21Path)
|
||||
@ -33,6 +30,13 @@ if False:
|
||||
def match(self, path: Bip32Path) -> bool:
|
||||
...
|
||||
|
||||
class KeychainValidatorType(Protocol):
|
||||
def is_in_keychain(self, path: Bip32Path) -> bool:
|
||||
...
|
||||
|
||||
def verify_path(self, path: Bip32Path) -> None:
|
||||
...
|
||||
|
||||
|
||||
class Interval:
|
||||
"""Helper for testing membership in an interval."""
|
||||
@ -247,7 +251,10 @@ PATTERN_SEP5 = "m/44'/coin_type'/account'"
|
||||
|
||||
|
||||
async def validate_path(
|
||||
ctx: wire.Context, keychain: Keychain, path: Bip32Path, *additional_checks: bool
|
||||
ctx: wire.Context,
|
||||
keychain: KeychainValidatorType,
|
||||
path: Bip32Path,
|
||||
*additional_checks: bool,
|
||||
) -> None:
|
||||
keychain.verify_path(path)
|
||||
if not keychain.is_in_keychain(path) or not all(additional_checks):
|
||||
|
@ -419,33 +419,6 @@ class TestCardanoAddress(unittest.TestCase):
|
||||
)
|
||||
derive_human_readable_address(keychain, address_parameters, 0, 0)
|
||||
|
||||
# block index is None
|
||||
with self.assertRaises(wire.DataError):
|
||||
address_parameters = CardanoAddressParametersType(
|
||||
address_type=CardanoAddressType.POINTER,
|
||||
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
|
||||
certificate_pointer=CardanoBlockchainPointerType(block_index=None, tx_index=2, certificate_index=3),
|
||||
)
|
||||
derive_human_readable_address(keychain, address_parameters, 0, 0)
|
||||
|
||||
# tx index is None
|
||||
with self.assertRaises(wire.DataError):
|
||||
address_parameters = CardanoAddressParametersType(
|
||||
address_type=CardanoAddressType.POINTER,
|
||||
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
|
||||
certificate_pointer=CardanoBlockchainPointerType(block_index=1, tx_index=None, certificate_index=3),
|
||||
)
|
||||
derive_human_readable_address(keychain, address_parameters, 0, 0)
|
||||
|
||||
# certificate index is None
|
||||
with self.assertRaises(wire.DataError):
|
||||
address_parameters = CardanoAddressParametersType(
|
||||
address_type=CardanoAddressType.POINTER,
|
||||
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
|
||||
certificate_pointer=CardanoBlockchainPointerType(block_index=1, tx_index=2, certificate_index=None),
|
||||
)
|
||||
derive_human_readable_address(keychain, address_parameters, 0, 0)
|
||||
|
||||
def test_reward_address(self):
|
||||
mnemonic = "test walk nut penalty hip pave soap entry language right filter choice"
|
||||
passphrase = ""
|
||||
|
Loading…
Reference in New Issue
Block a user