mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-09 06:50:58 +00:00
Update sign_tx
Add certificates, withdrawals and metadata hash
This commit is contained in:
parent
a25444efd1
commit
7bf5cab840
@ -256,11 +256,11 @@ def _validate_base_address_staking_info(
|
|||||||
"Base address needs either a staking path or a staking key hash!"
|
"Base address needs either a staking path or a staking key hash!"
|
||||||
)
|
)
|
||||||
|
|
||||||
if staking_key_hash is None and not _is_staking_path(staking_path):
|
if staking_key_hash is None and not is_staking_path(staking_path):
|
||||||
raise wire.DataError("Invalid staking path!")
|
raise wire.DataError("Invalid staking path!")
|
||||||
|
|
||||||
|
|
||||||
def _is_staking_path(path: List[int]) -> bool:
|
def is_staking_path(path: List[int]) -> bool:
|
||||||
"""
|
"""
|
||||||
Validates path to match 1852'/1815'/a'/2/0. Path must
|
Validates path to match 1852'/1815'/a'/2/0. Path must
|
||||||
be a valid Cardano path. It must have a Shelley purpose
|
be a valid Cardano path. It must have a Shelley purpose
|
||||||
@ -322,7 +322,7 @@ def _derive_enterprise_address(
|
|||||||
def _derive_reward_address(
|
def _derive_reward_address(
|
||||||
keychain: seed.Keychain, path: List[int], network_id: int,
|
keychain: seed.Keychain, path: List[int], network_id: int,
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
if not _is_staking_path(path):
|
if not is_staking_path(path):
|
||||||
raise wire.DataError("Invalid path for reward address!")
|
raise wire.DataError("Invalid path for reward address!")
|
||||||
|
|
||||||
header = _create_address_header(CardanoAddressType.REWARD, network_id)
|
header = _create_address_header(CardanoAddressType.REWARD, network_id)
|
||||||
|
@ -2,3 +2,5 @@ from trezor import wire
|
|||||||
|
|
||||||
INVALID_ADDRESS = wire.ProcessError("Invalid address")
|
INVALID_ADDRESS = wire.ProcessError("Invalid address")
|
||||||
NETWORK_MISMATCH = wire.ProcessError("Output address network mismatch!")
|
NETWORK_MISMATCH = wire.ProcessError("Output address network mismatch!")
|
||||||
|
INVALID_CERTIFICATE = wire.ProcessError("Invalid certificate")
|
||||||
|
INVALID_WITHDRAWAL = wire.ProcessError("Invalid withdrawal")
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
from micropython import const
|
from micropython import const
|
||||||
|
|
||||||
|
if False:
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
def variable_length_encode(number: int) -> bytes:
|
def variable_length_encode(number: int) -> bytes:
|
||||||
"""
|
"""
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
from ubinascii import hexlify
|
from ubinascii import hexlify
|
||||||
|
|
||||||
from trezor import ui
|
from trezor import ui
|
||||||
from trezor.messages import ButtonRequestType, CardanoAddressType
|
from trezor.messages import (
|
||||||
|
ButtonRequestType,
|
||||||
|
CardanoAddressType,
|
||||||
|
CardanoCertificateType,
|
||||||
|
)
|
||||||
from trezor.strings import format_amount
|
from trezor.strings import format_amount
|
||||||
from trezor.ui.button import ButtonDefault
|
from trezor.ui.button import ButtonDefault
|
||||||
from trezor.ui.scroll import Paginated
|
from trezor.ui.scroll import Paginated
|
||||||
@ -12,11 +16,16 @@ from apps.common.confirm import confirm, require_confirm, require_hold_to_confir
|
|||||||
from apps.common.layout import address_n_to_str, show_warning
|
from apps.common.layout import address_n_to_str, show_warning
|
||||||
|
|
||||||
from .helpers import protocol_magics
|
from .helpers import protocol_magics
|
||||||
|
from .helpers.utils import to_account_path
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from typing import List
|
from typing import List
|
||||||
from trezor import wire
|
from trezor import wire
|
||||||
from trezor.messages import CardanoBlockchainPointerType
|
from trezor.messages import (
|
||||||
|
CardanoBlockchainPointerType,
|
||||||
|
CardanoTxCertificateType,
|
||||||
|
CardanoTxWithdrawalType,
|
||||||
|
)
|
||||||
from trezor.messages.CardanoAddressParametersType import EnumTypeCardanoAddressType
|
from trezor.messages.CardanoAddressParametersType import EnumTypeCardanoAddressType
|
||||||
|
|
||||||
|
|
||||||
@ -28,6 +37,12 @@ ADDRESS_TYPE_NAMES = {
|
|||||||
CardanoAddressType.REWARD: "Reward",
|
CardanoAddressType.REWARD: "Reward",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CERTIFICATE_TYPE_NAMES = {
|
||||||
|
CardanoCertificateType.STAKE_REGISTRATION: "Stake key registration",
|
||||||
|
CardanoCertificateType.STAKE_DEREGISTRATION: "Stake key deregistration",
|
||||||
|
CardanoCertificateType.STAKE_DELEGATION: "Stake delegation",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def format_coin_amount(amount: int) -> str:
|
def format_coin_amount(amount: int) -> str:
|
||||||
return "%s %s" % (format_amount(amount, 6), "ADA")
|
return "%s %s" % (format_amount(amount, 6), "ADA")
|
||||||
@ -130,6 +145,48 @@ async def confirm_transaction(ctx, amount: int, fee: int, protocol_magic: int):
|
|||||||
await require_hold_to_confirm(ctx, Paginated([t1, t2]))
|
await require_hold_to_confirm(ctx, Paginated([t1, t2]))
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_certificate(
|
||||||
|
ctx: wire.Context, certificate: CardanoTxCertificateType
|
||||||
|
) -> bool:
|
||||||
|
pages = []
|
||||||
|
|
||||||
|
t1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||||
|
t1.normal("Confirm:")
|
||||||
|
t1.bold(CERTIFICATE_TYPE_NAMES[certificate.type])
|
||||||
|
t1.normal("for account:")
|
||||||
|
t1.bold(address_n_to_str(to_account_path(certificate.path)))
|
||||||
|
pages.append(t1)
|
||||||
|
|
||||||
|
if certificate.type == CardanoCertificateType.STAKE_DELEGATION:
|
||||||
|
t2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||||
|
t2.normal("to pool:")
|
||||||
|
t2.bold(hexlify(certificate.pool).decode())
|
||||||
|
pages.append(t2)
|
||||||
|
|
||||||
|
await require_confirm(ctx, Paginated(pages))
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_withdrawal(
|
||||||
|
ctx: wire.Context, withdrawal: CardanoTxWithdrawalType
|
||||||
|
) -> bool:
|
||||||
|
t1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||||
|
t1.normal("Confirm withdrawal")
|
||||||
|
t1.normal("for account:")
|
||||||
|
t1.bold(address_n_to_str(to_account_path(withdrawal.path)))
|
||||||
|
t1.normal("Amount:")
|
||||||
|
t1.bold(format_coin_amount(withdrawal.amount))
|
||||||
|
|
||||||
|
await require_confirm(ctx, t1)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_metadata_hash(ctx: wire.Context, metadata_hash: bytes) -> bool:
|
||||||
|
t1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
|
||||||
|
t1.normal("Confirm metadata hash:")
|
||||||
|
t1.bold(hexlify(metadata_hash).decode())
|
||||||
|
|
||||||
|
await require_confirm(ctx, t1)
|
||||||
|
|
||||||
|
|
||||||
async def show_address(
|
async def show_address(
|
||||||
ctx: wire.Context,
|
ctx: wire.Context,
|
||||||
address: str,
|
address: str,
|
||||||
|
@ -3,7 +3,8 @@ from micropython import const
|
|||||||
from trezor import log, wire
|
from trezor import log, wire
|
||||||
from trezor.crypto import hashlib
|
from trezor.crypto import hashlib
|
||||||
from trezor.crypto.curve import ed25519
|
from trezor.crypto.curve import ed25519
|
||||||
from trezor.messages import CardanoAddressParametersType
|
from trezor.messages import CardanoAddressType, CardanoCertificateType
|
||||||
|
from trezor.messages.CardanoAddressParametersType import CardanoAddressParametersType
|
||||||
from trezor.messages.CardanoSignedTx import CardanoSignedTx
|
from trezor.messages.CardanoSignedTx import CardanoSignedTx
|
||||||
|
|
||||||
from apps.common import cbor
|
from apps.common import cbor
|
||||||
@ -15,15 +16,26 @@ from .address import (
|
|||||||
derive_address_bytes,
|
derive_address_bytes,
|
||||||
derive_human_readable_address,
|
derive_human_readable_address,
|
||||||
get_address_bytes_unsafe,
|
get_address_bytes_unsafe,
|
||||||
|
get_public_key_hash,
|
||||||
|
is_staking_path,
|
||||||
validate_full_path,
|
validate_full_path,
|
||||||
validate_output_address,
|
validate_output_address,
|
||||||
)
|
)
|
||||||
from .byron_address import get_address_attributes
|
from .byron_address import get_address_attributes
|
||||||
from .helpers import network_ids, protocol_magics, staking_use_cases
|
from .helpers import (
|
||||||
|
INVALID_CERTIFICATE,
|
||||||
|
INVALID_WITHDRAWAL,
|
||||||
|
network_ids,
|
||||||
|
protocol_magics,
|
||||||
|
staking_use_cases,
|
||||||
|
)
|
||||||
from .helpers.utils import to_account_path
|
from .helpers.utils import to_account_path
|
||||||
from .layout import (
|
from .layout import (
|
||||||
|
confirm_certificate,
|
||||||
|
confirm_metadata_hash,
|
||||||
confirm_sending,
|
confirm_sending,
|
||||||
confirm_transaction,
|
confirm_transaction,
|
||||||
|
confirm_withdrawal,
|
||||||
show_warning_tx_different_staking_account,
|
show_warning_tx_different_staking_account,
|
||||||
show_warning_tx_no_staking_info,
|
show_warning_tx_no_staking_info,
|
||||||
show_warning_tx_pointer_address,
|
show_warning_tx_pointer_address,
|
||||||
@ -36,6 +48,8 @@ if False:
|
|||||||
from trezor.messages.CardanoSignTx import CardanoSignTx
|
from trezor.messages.CardanoSignTx import CardanoSignTx
|
||||||
from trezor.messages.CardanoTxInputType import CardanoTxInputType
|
from trezor.messages.CardanoTxInputType import CardanoTxInputType
|
||||||
from trezor.messages.CardanoTxOutputType import CardanoTxOutputType
|
from trezor.messages.CardanoTxOutputType import CardanoTxOutputType
|
||||||
|
from trezor.messages.CardanoTxCertificateType import CardanoTxCertificateType
|
||||||
|
from trezor.messages.CardanoTxWithdrawalType import CardanoTxWithdrawalType
|
||||||
|
|
||||||
# the maximum allowed change address. this should be large enough for normal
|
# the maximum allowed change address. this should be large enough for normal
|
||||||
# use and still allow to quickly brute-force the correct bip32 path
|
# use and still allow to quickly brute-force the correct bip32 path
|
||||||
@ -45,6 +59,9 @@ BIP_PATH_LENGTH = const(5)
|
|||||||
|
|
||||||
LOVELACE_MAX_SUPPLY = 45_000_000_000 * 1_000_000
|
LOVELACE_MAX_SUPPLY = 45_000_000_000 * 1_000_000
|
||||||
|
|
||||||
|
POOL_HASH_SIZE = 28
|
||||||
|
METADATA_HASH_SIZE = 32
|
||||||
|
|
||||||
|
|
||||||
@seed.with_keychain
|
@seed.with_keychain
|
||||||
async def sign_tx(
|
async def sign_tx(
|
||||||
@ -60,6 +77,11 @@ async def sign_tx(
|
|||||||
await validate_path(ctx, validate_full_path, keychain, i.address_n, CURVE)
|
await validate_path(ctx, validate_full_path, keychain, i.address_n, CURVE)
|
||||||
|
|
||||||
_validate_outputs(keychain, msg.outputs, msg.protocol_magic, msg.network_id)
|
_validate_outputs(keychain, msg.outputs, msg.protocol_magic, msg.network_id)
|
||||||
|
_validate_certificates(msg.certificates)
|
||||||
|
_validate_withdrawals(msg.withdrawals)
|
||||||
|
|
||||||
|
if msg.metadata_hash and len(msg.metadata_hash) != METADATA_HASH_SIZE:
|
||||||
|
raise wire.ProcessError("Invalid metadata hash")
|
||||||
|
|
||||||
# display the transaction in UI
|
# display the transaction in UI
|
||||||
await _show_tx(ctx, keychain, msg)
|
await _show_tx(ctx, keychain, msg)
|
||||||
@ -117,12 +139,41 @@ def _validate_outputs(
|
|||||||
raise wire.ProcessError("Total transaction amount is out of range!")
|
raise wire.ProcessError("Total transaction amount is out of range!")
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_certificates(certificates: List[CardanoTxCertificateType]) -> None:
|
||||||
|
for certificate in certificates:
|
||||||
|
if not is_staking_path(certificate.path):
|
||||||
|
raise INVALID_CERTIFICATE
|
||||||
|
|
||||||
|
if certificate.type == CardanoCertificateType.STAKE_DELEGATION:
|
||||||
|
if certificate.pool is None or len(certificate.pool) != POOL_HASH_SIZE:
|
||||||
|
raise INVALID_CERTIFICATE
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_withdrawals(withdrawals: List[CardanoTxWithdrawalType]) -> None:
|
||||||
|
for withdrawal in withdrawals:
|
||||||
|
if not is_staking_path(withdrawal.path):
|
||||||
|
raise INVALID_WITHDRAWAL
|
||||||
|
|
||||||
|
if not 0 <= withdrawal.amount < LOVELACE_MAX_SUPPLY:
|
||||||
|
raise INVALID_WITHDRAWAL
|
||||||
|
|
||||||
|
|
||||||
def _serialize_tx(keychain: seed.Keychain, msg: CardanoSignTx) -> Tuple[bytes, bytes]:
|
def _serialize_tx(keychain: seed.Keychain, msg: CardanoSignTx) -> Tuple[bytes, bytes]:
|
||||||
tx_body = _build_tx_body(keychain, msg)
|
tx_body = _build_tx_body(keychain, msg)
|
||||||
tx_hash = _hash_tx_body(tx_body)
|
tx_hash = _hash_tx_body(tx_body)
|
||||||
|
|
||||||
witnesses = _build_witnesses(keychain, msg.inputs, tx_hash, msg.protocol_magic)
|
witnesses = _build_witnesses(
|
||||||
|
keychain,
|
||||||
|
msg.inputs,
|
||||||
|
msg.certificates,
|
||||||
|
msg.withdrawals,
|
||||||
|
tx_hash,
|
||||||
|
msg.protocol_magic,
|
||||||
|
)
|
||||||
|
|
||||||
|
# We always set transaction metadata to None, even if metadata
|
||||||
|
# hash is set. Metadata aren't sent to Trezor and the None
|
||||||
|
# should be replaced by the SW wallet if metadata exist.
|
||||||
serialized_tx = cbor.encode([tx_body, witnesses, None])
|
serialized_tx = cbor.encode([tx_body, witnesses, None])
|
||||||
|
|
||||||
return serialized_tx, tx_hash
|
return serialized_tx, tx_hash
|
||||||
@ -141,6 +192,21 @@ def _build_tx_body(keychain: seed.Keychain, msg: CardanoSignTx) -> Dict:
|
|||||||
3: msg.ttl,
|
3: msg.ttl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if msg.certificates:
|
||||||
|
certificates_for_cbor = _build_certificates(keychain, msg.certificates)
|
||||||
|
tx_body[4] = certificates_for_cbor
|
||||||
|
|
||||||
|
if msg.withdrawals:
|
||||||
|
withdrawals_for_cbor = _build_withdrawals(
|
||||||
|
keychain, msg.withdrawals, msg.protocol_magic, msg.network_id
|
||||||
|
)
|
||||||
|
tx_body[5] = withdrawals_for_cbor
|
||||||
|
|
||||||
|
# tx_body[6] is for protocol updates, which we don't support
|
||||||
|
|
||||||
|
if msg.metadata_hash:
|
||||||
|
tx_body[7] = msg.metadata_hash
|
||||||
|
|
||||||
return tx_body
|
return tx_body
|
||||||
|
|
||||||
|
|
||||||
@ -170,6 +236,50 @@ def _build_outputs(
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _build_certificates(
|
||||||
|
keychain: seed.Keychain, certificates: List[CardanoTxCertificateType]
|
||||||
|
) -> List[Tuple]:
|
||||||
|
result = []
|
||||||
|
for certificate in certificates:
|
||||||
|
public_key_hash = get_public_key_hash(keychain, certificate.path)
|
||||||
|
|
||||||
|
stake_credential = [0, public_key_hash]
|
||||||
|
if certificate.type == CardanoCertificateType.STAKE_DELEGATION:
|
||||||
|
certificate_for_cbor = (
|
||||||
|
certificate.type,
|
||||||
|
stake_credential,
|
||||||
|
certificate.pool,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
certificate_for_cbor = (certificate.type, stake_credential)
|
||||||
|
|
||||||
|
result.append(certificate_for_cbor)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _build_withdrawals(
|
||||||
|
keychain: seed.Keychain,
|
||||||
|
withdrawals: List[CardanoTxWithdrawalType],
|
||||||
|
protocol_magic: int,
|
||||||
|
network_id: int,
|
||||||
|
) -> Dict[bytes, int]:
|
||||||
|
result = {}
|
||||||
|
for withdrawal in withdrawals:
|
||||||
|
reward_address = derive_address_bytes(
|
||||||
|
keychain,
|
||||||
|
CardanoAddressParametersType(
|
||||||
|
address_type=CardanoAddressType.REWARD, address_n=withdrawal.path,
|
||||||
|
),
|
||||||
|
protocol_magic,
|
||||||
|
network_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
result[reward_address] = withdrawal.amount
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def _hash_tx_body(tx_body: Dict) -> bytes:
|
def _hash_tx_body(tx_body: Dict) -> bytes:
|
||||||
tx_body_cbor = cbor.encode(tx_body)
|
tx_body_cbor = cbor.encode(tx_body)
|
||||||
return hashlib.blake2b(data=tx_body_cbor, outlen=32).digest()
|
return hashlib.blake2b(data=tx_body_cbor, outlen=32).digest()
|
||||||
@ -178,10 +288,14 @@ def _hash_tx_body(tx_body: Dict) -> bytes:
|
|||||||
def _build_witnesses(
|
def _build_witnesses(
|
||||||
keychain: seed.Keychain,
|
keychain: seed.Keychain,
|
||||||
inputs: List[CardanoTxInputType],
|
inputs: List[CardanoTxInputType],
|
||||||
|
certificates: List[CardanoTxCertificateType],
|
||||||
|
withdrawals: List[CardanoTxWithdrawalType],
|
||||||
tx_body_hash: bytes,
|
tx_body_hash: bytes,
|
||||||
protocol_magic: int,
|
protocol_magic: int,
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
shelley_witnesses = _build_shelley_witnesses(keychain, inputs, tx_body_hash)
|
shelley_witnesses = _build_shelley_witnesses(
|
||||||
|
keychain, inputs, certificates, withdrawals, tx_body_hash
|
||||||
|
)
|
||||||
byron_witnesses = _build_byron_witnesses(
|
byron_witnesses = _build_byron_witnesses(
|
||||||
keychain, inputs, tx_body_hash, protocol_magic
|
keychain, inputs, tx_body_hash, protocol_magic
|
||||||
)
|
)
|
||||||
@ -189,33 +303,59 @@ def _build_witnesses(
|
|||||||
# use key 0 for shelley witnesses and key 2 for byron witnesses
|
# use key 0 for shelley witnesses and key 2 for byron witnesses
|
||||||
# according to the spec in shelley.cddl in cardano-ledger-specs
|
# according to the spec in shelley.cddl in cardano-ledger-specs
|
||||||
witnesses = {}
|
witnesses = {}
|
||||||
if len(shelley_witnesses) > 0:
|
if shelley_witnesses:
|
||||||
witnesses[0] = shelley_witnesses
|
witnesses[0] = shelley_witnesses
|
||||||
if len(byron_witnesses) > 0:
|
if byron_witnesses:
|
||||||
witnesses[2] = byron_witnesses
|
witnesses[2] = byron_witnesses
|
||||||
|
|
||||||
return witnesses
|
return witnesses
|
||||||
|
|
||||||
|
|
||||||
def _build_shelley_witnesses(
|
def _build_shelley_witnesses(
|
||||||
keychain: seed.Keychain, inputs: List[CardanoTxInputType], tx_body_hash: bytes,
|
keychain: seed.Keychain,
|
||||||
|
inputs: List[CardanoTxInputType],
|
||||||
|
certificates: List[CardanoTxCertificateType],
|
||||||
|
withdrawals: List[CardanoTxWithdrawalType],
|
||||||
|
tx_body_hash: bytes,
|
||||||
) -> List[Tuple[bytes, bytes]]:
|
) -> List[Tuple[bytes, bytes]]:
|
||||||
shelley_witnesses = []
|
shelley_witnesses = []
|
||||||
|
|
||||||
|
paths = set()
|
||||||
for input in inputs:
|
for input in inputs:
|
||||||
if not is_shelley_path(input.address_n):
|
if not is_shelley_path(input.address_n):
|
||||||
continue
|
continue
|
||||||
|
paths.add(tuple(input.address_n))
|
||||||
|
for certificate in certificates:
|
||||||
|
if not _is_certificate_witness_required(certificate.type):
|
||||||
|
continue
|
||||||
|
paths.add(tuple(certificate.path))
|
||||||
|
for withdrawal in withdrawals:
|
||||||
|
paths.add(tuple(withdrawal.path))
|
||||||
|
|
||||||
node = keychain.derive(input.address_n)
|
for path in paths:
|
||||||
|
witness = _build_shelley_witness(keychain, tx_body_hash, list(path))
|
||||||
public_key = remove_ed25519_prefix(node.public_key())
|
shelley_witnesses.append(witness)
|
||||||
signature = ed25519.sign_ext(
|
|
||||||
node.private_key(), node.private_key_ext(), tx_body_hash
|
|
||||||
)
|
|
||||||
shelley_witnesses.append((public_key, signature))
|
|
||||||
|
|
||||||
return shelley_witnesses
|
return shelley_witnesses
|
||||||
|
|
||||||
|
|
||||||
|
def _build_shelley_witness(
|
||||||
|
keychain: seed.Keychain, tx_body_hash: bytes, path: List[int]
|
||||||
|
) -> List[Tuple[bytes, bytes]]:
|
||||||
|
node = keychain.derive(path)
|
||||||
|
|
||||||
|
signature = ed25519.sign_ext(
|
||||||
|
node.private_key(), node.private_key_ext(), tx_body_hash
|
||||||
|
)
|
||||||
|
public_key = remove_ed25519_prefix(node.public_key())
|
||||||
|
|
||||||
|
return public_key, signature
|
||||||
|
|
||||||
|
|
||||||
|
def _is_certificate_witness_required(certificate_type: int) -> bool:
|
||||||
|
return certificate_type != CardanoCertificateType.STAKE_REGISTRATION
|
||||||
|
|
||||||
|
|
||||||
def _build_byron_witnesses(
|
def _build_byron_witnesses(
|
||||||
keychain: seed.Keychain,
|
keychain: seed.Keychain,
|
||||||
inputs: List[CardanoTxInputType],
|
inputs: List[CardanoTxInputType],
|
||||||
@ -245,6 +385,16 @@ async def _show_tx(
|
|||||||
ctx: wire.Context, keychain: seed.Keychain, msg: CardanoSignTx
|
ctx: wire.Context, keychain: seed.Keychain, msg: CardanoSignTx
|
||||||
) -> None:
|
) -> None:
|
||||||
total_amount = await _show_outputs(ctx, keychain, msg)
|
total_amount = await _show_outputs(ctx, keychain, msg)
|
||||||
|
|
||||||
|
for certificate in msg.certificates:
|
||||||
|
await confirm_certificate(ctx, certificate)
|
||||||
|
|
||||||
|
for withdrawal in msg.withdrawals:
|
||||||
|
await confirm_withdrawal(ctx, withdrawal)
|
||||||
|
|
||||||
|
if msg.metadata_hash:
|
||||||
|
await confirm_metadata_hash(ctx, msg.metadata_hash)
|
||||||
|
|
||||||
await confirm_transaction(ctx, total_amount, msg.fee, msg.protocol_magic)
|
await confirm_transaction(ctx, total_amount, msg.fee, msg.protocol_magic)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user