You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/src/apps/stellar/operations/layout.py

345 lines
10 KiB

from typing import TYPE_CHECKING
from ubinascii import hexlify
from trezor import TR
from trezor.ui.layouts import (
confirm_address,
confirm_amount,
confirm_metadata,
confirm_output,
confirm_properties,
)
from trezor.wire import DataError, ProcessError
from ..layout import format_amount
if TYPE_CHECKING:
from trezor.messages import (
StellarAccountMergeOp,
StellarAllowTrustOp,
StellarAsset,
StellarBumpSequenceOp,
StellarChangeTrustOp,
StellarClaimClaimableBalanceOp,
StellarCreateAccountOp,
StellarCreatePassiveSellOfferOp,
StellarManageBuyOfferOp,
StellarManageDataOp,
StellarManageSellOfferOp,
StellarPathPaymentStrictReceiveOp,
StellarPathPaymentStrictSendOp,
StellarPaymentOp,
StellarSetOptionsOp,
)
async def confirm_source_account(source_account: str) -> None:
await confirm_address(
TR.stellar__confirm_operation,
source_account,
TR.stellar__source_account,
"op_source_account",
)
async def confirm_allow_trust_op(op: StellarAllowTrustOp) -> None:
await confirm_properties(
"op_allow_trust",
TR.stellar__allow_trust if op.is_authorized else TR.stellar__revoke_trust,
(
(TR.stellar__asset, op.asset_code),
(TR.stellar__trusted_account, op.trusted_account),
),
)
async def confirm_account_merge_op(op: StellarAccountMergeOp) -> None:
await confirm_address(
TR.stellar__account_merge,
op.destination_account,
TR.stellar__all_will_be_sent_to,
"op_account_merge",
)
async def confirm_bump_sequence_op(op: StellarBumpSequenceOp) -> None:
await confirm_metadata(
"op_bump",
TR.stellar__bump_sequence,
TR.stellar__set_sequence_to_template,
str(op.bump_to),
)
async def confirm_change_trust_op(op: StellarChangeTrustOp) -> None:
await confirm_amount(
TR.stellar__delete_trust if op.limit == 0 else TR.stellar__add_trust,
format_amount(op.limit, op.asset),
TR.stellar__limit,
"op_change_trust",
)
await confirm_asset_issuer(op.asset)
async def confirm_create_account_op(op: StellarCreateAccountOp) -> None:
await confirm_properties(
"op_create_account",
TR.stellar__create_account,
(
(TR.words__account, op.new_account),
(TR.stellar__initial_balance, format_amount(op.starting_balance)),
),
)
async def confirm_create_passive_sell_offer_op(
op: StellarCreatePassiveSellOfferOp,
) -> None:
text = (
TR.stellar__delete_passive_offer
if op.amount == 0
else TR.stellar__new_passive_offer
)
await _confirm_offer(text, op)
async def confirm_manage_buy_offer_op(op: StellarManageBuyOfferOp) -> None:
await _confirm_manage_offer_op_common(op)
async def confirm_manage_sell_offer_op(op: StellarManageSellOfferOp) -> None:
await _confirm_manage_offer_op_common(op)
async def _confirm_manage_offer_op_common(
op: StellarManageBuyOfferOp | StellarManageSellOfferOp,
) -> None:
if op.offer_id == 0:
text = TR.stellar__new_offer
else:
text = f"{TR.stellar__delete if op.amount == 0 else TR.stellar__update} #{op.offer_id}"
await _confirm_offer(text, op)
async def _confirm_offer(
title: str,
op: (
StellarCreatePassiveSellOfferOp
| StellarManageSellOfferOp
| StellarManageBuyOfferOp
),
) -> None:
from trezor.messages import StellarManageBuyOfferOp
from ..layout import format_asset
buying_asset = op.buying_asset # local_cache_attribute
selling_asset = op.selling_asset # local_cache_attribute
if StellarManageBuyOfferOp.is_type_of(op):
buying = (TR.stellar__buying, format_amount(op.amount, buying_asset))
selling = (TR.stellar__selling, format_asset(selling_asset))
price = (
TR.stellar__price_per_template.format(format_asset(selling_asset)),
str(op.price_n / op.price_d),
)
await confirm_properties(
"op_offer",
title,
(buying, selling, price),
)
else:
selling = (TR.stellar__selling, format_amount(op.amount, selling_asset))
buying = (TR.stellar__buying, format_asset(buying_asset))
price = (
TR.stellar__price_per_template.format(format_asset(buying_asset)),
str(op.price_n / op.price_d),
)
await confirm_properties(
"op_offer",
title,
(selling, buying, price),
)
await confirm_asset_issuer(selling_asset)
await confirm_asset_issuer(buying_asset)
async def confirm_manage_data_op(op: StellarManageDataOp) -> None:
from trezor.crypto.hashlib import sha256
if op.value:
digest = sha256(op.value).digest()
await confirm_properties(
"op_data",
TR.stellar__set_data,
((TR.stellar__key, op.key), (TR.stellar__value_sha256, digest)),
)
else:
await confirm_metadata(
"op_data",
TR.stellar__clear_data,
TR.stellar__wanna_clean_value_key_template,
op.key,
)
async def confirm_path_payment_strict_receive_op(
op: StellarPathPaymentStrictReceiveOp,
) -> None:
await confirm_output(
op.destination_account,
format_amount(op.destination_amount, op.destination_asset),
title=TR.stellar__path_pay,
)
await confirm_asset_issuer(op.destination_asset)
# confirm what the sender is using to pay
await confirm_amount(
TR.stellar__debited_amount,
format_amount(op.send_max, op.send_asset),
TR.stellar__pay_at_most,
"op_path_payment_strict_receive",
)
await confirm_asset_issuer(op.send_asset)
async def confirm_path_payment_strict_send_op(
op: StellarPathPaymentStrictSendOp,
) -> None:
await confirm_output(
op.destination_account,
format_amount(op.destination_min, op.destination_asset),
title=TR.stellar__path_pay_at_least,
)
await confirm_asset_issuer(op.destination_asset)
# confirm what the sender is using to pay
await confirm_amount(
TR.stellar__debited_amount,
format_amount(op.send_amount, op.send_asset),
TR.stellar__pay,
"op_path_payment_strict_send",
)
await confirm_asset_issuer(op.send_asset)
async def confirm_payment_op(op: StellarPaymentOp) -> None:
await confirm_output(
op.destination_account,
format_amount(op.amount, op.asset),
)
await confirm_asset_issuer(op.asset)
async def confirm_set_options_op(op: StellarSetOptionsOp) -> None:
from trezor.enums import StellarSignerType
from trezor.ui.layouts import confirm_blob, confirm_text
from .. import helpers
if op.inflation_destination_account:
await confirm_address(
TR.stellar__inflation,
op.inflation_destination_account,
TR.stellar__destination,
"op_inflation",
)
if op.clear_flags:
t = _format_flags(op.clear_flags)
await confirm_text("op_set_options", TR.stellar__clear_flags, data=t)
if op.set_flags:
t = _format_flags(op.set_flags)
await confirm_text("op_set_options", TR.stellar__set_flags, data=t)
thresholds: list[tuple[str, str]] = []
append = thresholds.append # local_cache_attribute
if op.master_weight is not None:
append((TR.stellar__master_weight, str(op.master_weight)))
if op.low_threshold is not None:
append((TR.stellar__low, str(op.low_threshold)))
if op.medium_threshold is not None:
append((TR.stellar__medium, str(op.medium_threshold)))
if op.high_threshold is not None:
append((TR.stellar__high, str(op.high_threshold)))
if thresholds:
await confirm_properties(
"op_thresholds", TR.stellar__account_thresholds, thresholds
)
if op.home_domain:
await confirm_text("op_home_domain", TR.stellar__home_domain, op.home_domain)
signer_type = op.signer_type # local_cache_attribute
signer_key = op.signer_key # local_cache_attribute
if signer_type is not None:
if signer_key is None or op.signer_weight is None:
raise DataError("Stellar: invalid signer option data.")
if op.signer_weight > 0:
title = TR.stellar__add_signer
else:
title = TR.stellar__remove_signer
data: str | bytes = ""
if signer_type == StellarSignerType.ACCOUNT:
description = f"{TR.words__account}:"
data = helpers.address_from_public_key(signer_key)
elif signer_type == StellarSignerType.PRE_AUTH:
description = TR.stellar__preauth_transaction
data = signer_key
elif signer_type == StellarSignerType.HASH:
description = TR.stellar__hash
data = signer_key
else:
raise ProcessError("Stellar: invalid signer type")
await confirm_blob(
"op_signer",
title=title,
description=description,
data=data,
)
async def confirm_claim_claimable_balance_op(
op: StellarClaimClaimableBalanceOp,
) -> None:
balance_id = hexlify(op.balance_id).decode()
await confirm_metadata(
"op_claim_claimable_balance",
TR.stellar__claim_claimable_balance,
TR.stellar__balance_id + ": {}",
balance_id,
)
def _format_flags(flags: int) -> str:
from .. import consts
if flags > consts.FLAGS_MAX_SIZE:
raise ProcessError("Stellar: invalid flags")
flags_set: list[str] = []
if flags & consts.FLAG_AUTH_REQUIRED:
flags_set.append("AUTH_REQUIRED\n")
if flags & consts.FLAG_AUTH_REVOCABLE:
flags_set.append("AUTH_REVOCABLE\n")
if flags & consts.FLAG_AUTH_IMMUTABLE:
flags_set.append("AUTH_IMMUTABLE\n")
return "".join(flags_set)
async def confirm_asset_issuer(asset: StellarAsset) -> None:
from trezor.enums import StellarAssetType
if asset.type == StellarAssetType.NATIVE:
return
if asset.issuer is None or asset.code is None:
raise DataError("Stellar: invalid asset definition")
await confirm_address(
TR.stellar__confirm_issuer,
asset.issuer,
TR.stellar__issuer_template.format(asset.code),
"confirm_asset_issuer",
)