diff --git a/core/src/apps/stellar/layout.py b/core/src/apps/stellar/layout.py index e7a8ab6255..331192c5e2 100644 --- a/core/src/apps/stellar/layout.py +++ b/core/src/apps/stellar/layout.py @@ -1,32 +1,33 @@ from trezor import strings, ui from trezor.enums import ButtonRequestType -from trezor.ui.constants import MONO_ADDR_PER_LINE from trezor.ui.layouts import ( confirm_action, - confirm_hex, + confirm_address, + confirm_blob, confirm_metadata, confirm_timebounds_stellar, ) from . import consts +if False: + from trezor.messages import StellarAssetType + async def require_confirm_init( ctx, address: str, network_passphrase: str, accounts_match: bool ): if accounts_match: - description = "Initialize signing with\nyour account" + description = "Initialize signing with your account" else: description = "Initialize signing with" - await require_confirm_op( + await confirm_address( ctx, - "confirm_init", title="Confirm Stellar", - subtitle=None, + address=address, + br_type="confirm_init", description=description, - data=address, icon=ui.ICON_SEND, - is_account=True, ) network = get_network_warning(network_passphrase) @@ -68,13 +69,12 @@ async def require_confirm_memo(ctx, memo_type: int, memo_text: str): br_code=ButtonRequestType.ConfirmOutput, ) - await require_confirm_op( + await confirm_blob( ctx, "confirm_memo", title="Confirm memo", - subtitle=description, + description=description, data=memo_text, - split=False, ) @@ -91,39 +91,21 @@ async def require_confirm_final(ctx, fee: int, num_operations: int): ) -async def require_confirm_op( - ctx, - br_type: str, - subtitle: str | None, - data: str, - title: str = "Confirm operation", - description: str = None, - icon=ui.ICON_CONFIRM, - split: bool = True, - is_account: bool = False, -): - await confirm_hex( - ctx, - br_type, - title=title, - subtitle=subtitle, - description=description, - data=data, - width=MONO_ADDR_PER_LINE if split else None, - icon=icon, - truncate=True, - truncate_ellipsis=".." if is_account else "", - br_code=ButtonRequestType.ConfirmOutput, +def format_asset(asset: StellarAssetType | None = None) -> str: + if asset is None or asset.type == consts.ASSET_TYPE_NATIVE: + return "XLM" + else: + return asset.code + + +def format_amount(amount: int, asset: StellarAssetType | None = None) -> str: + return ( + strings.format_amount(amount, consts.AMOUNT_DECIMALS) + + " " + + format_asset(asset) ) -def format_amount(amount: int, ticker=True) -> str: - t = "" - if ticker: - t = " XLM" - return strings.format_amount(amount, consts.AMOUNT_DECIMALS) + t - - def get_network_warning(network_passphrase: str): if network_passphrase == consts.NETWORK_PASSPHRASE_PUBLIC: return None diff --git a/core/src/apps/stellar/operations/layout.py b/core/src/apps/stellar/operations/layout.py index 74d3465960..9628738d88 100644 --- a/core/src/apps/stellar/operations/layout.py +++ b/core/src/apps/stellar/operations/layout.py @@ -1,6 +1,3 @@ -from ubinascii import hexlify - -from trezor.enums import ButtonRequestType from trezor.messages import ( StellarAccountMergeOp, StellarAllowTrustOp, @@ -15,71 +12,83 @@ from trezor.messages import ( StellarPaymentOp, StellarSetOptionsOp, ) -from trezor.ui.layouts import confirm_metadata +from trezor.ui.layouts import ( + confirm_address, + confirm_amount, + confirm_blob, + confirm_metadata, + confirm_output, + confirm_properties, + confirm_text, +) from trezor.wire import ProcessError from .. import consts, helpers -from ..layout import format_amount, require_confirm_op, ui +from ..layout import format_amount, format_asset async def confirm_source_account(ctx, source_account: str): - await require_confirm_op(ctx, "confirm_source", "Source account:", source_account) + await confirm_address( + ctx, + "Confirm operation", + source_account, + description="Source account:", + br_type="op_source_account", + ) async def confirm_allow_trust_op(ctx, op: StellarAllowTrustOp): - await require_confirm_op( + await confirm_properties( ctx, "op_allow_trust", - subtitle="Allow Trust" if op.is_authorized else "Revoke Trust", - description="of %s by:" % op.asset_code, - data=op.trusted_account, - is_account=True, + title="Allow trust" if op.is_authorized else "Revoke trust", + props=( + ("Asset", op.asset_code), + ("Trusted Account", op.trusted_account), + ), ) async def confirm_account_merge_op(ctx, op: StellarAccountMergeOp): - await require_confirm_op( + await confirm_address( ctx, - "op_merge", "Account Merge", + op.destination_account, description="All XLM will be sent to:", - data=op.destination_account, - is_account=True, + br_type="op_account_merge", ) async def confirm_bump_sequence_op(ctx, op: StellarBumpSequenceOp): - await require_confirm_op( + await confirm_metadata( ctx, "op_bump", "Bump Sequence", - description="Set sequence to", - data=str(op.bump_to), - split=False, + content="Set sequence to {}?", + param=str(op.bump_to), ) async def confirm_change_trust_op(ctx, op: StellarChangeTrustOp): - await require_confirm_op( + await confirm_amount( ctx, - "op_change_trust", - subtitle="Delete Trust" if op.limit == 0 else "Add Trust", - description="Asset: %s\nAmount: %s" - % (op.asset.code, format_amount(op.limit, ticker=False)), - data="", - split=False, + title="Delete trust" if op.limit == 0 else "Add trust", + amount=format_amount(op.limit, op.asset), + description="Limit:", + br_type="op_change_trust", ) await confirm_asset_issuer(ctx, op.asset) async def confirm_create_account_op(ctx, op: StellarCreateAccountOp): - await require_confirm_op( + await confirm_properties( ctx, - "op_account", - subtitle="Create Account", - description="with %s" % format_amount(op.starting_balance), - data=op.new_account, - is_account=True, + "op_create_account", + "Create Account", + props=( + ("Account", op.new_account), + ("Initial Balance", format_amount(op.starting_balance)), + ), ) @@ -104,19 +113,18 @@ async def confirm_manage_offer_op(ctx, op: StellarManageOfferOp): async def _confirm_offer(ctx, title, op): - await require_confirm_op( + await confirm_properties( ctx, "op_offer", - subtitle=title, - description="Sell %s %s\nFor %f\nPer %s" - % ( - format_amount(op.amount, ticker=False), - op.selling_asset.code, - op.price_n / op.price_d, - format_asset_code(op.buying_asset), + title=title, + props=( + ("Selling:", format_amount(op.amount, op.selling_asset)), + ("Buying:", format_asset(op.buying_asset)), + ( + "Price per {}:".format(format_asset(op.buying_asset)), + str(op.price_n / op.price_d), + ), ), - data="", - split=False, ) await confirm_asset_issuer(ctx, op.selling_asset) await confirm_asset_issuer(ctx, op.buying_asset) @@ -125,122 +133,117 @@ async def _confirm_offer(ctx, title, op): async def confirm_manage_data_op(ctx, op: StellarManageDataOp): from trezor.crypto.hashlib import sha256 - if op.value: - title = "Set" - else: - title = "Clear" - await require_confirm_op(ctx, "op_data", "%s data value key" % title, op.key) - if op.value: digest = sha256(op.value).digest() - digest_str = hexlify(digest).decode() - await require_confirm_op(ctx, "op_data_value", "Value (SHA-256):", digest_str) + await confirm_properties( + ctx, + "op_data", + "Set data", + props=(("Key:", op.key), ("Value (SHA-256):", digest)), + ) + else: + await confirm_metadata( + ctx, + "op_data", + "Clear data", + "Do you want to clear value key {}?", + param=op.key, + ) async def confirm_path_payment_op(ctx, op: StellarPathPaymentOp): - await require_confirm_op( + await confirm_output( ctx, - "op_path_payment", - subtitle="Path Pay %s\n%s to:" - % ( - format_amount(op.destination_amount, ticker=False), - format_asset_code(op.destination_asset), - ), - data=op.destination_account, - is_account=True, + address=op.destination_account, + amount=format_amount(op.destination_amount, op.destination_asset), + title="Path Pay", ) await confirm_asset_issuer(ctx, op.destination_asset) # confirm what the sender is using to pay - await confirm_metadata( + await confirm_amount( ctx, - "op_path_payment", - "Confirm operation", - content="Pay using\n{}\nThis amount is debited from your account.", - param="{}\n{}".format( - format_amount(op.send_max, ticker=False), - format_asset_code(op.send_asset), - ), - icon=ui.ICON_CONFIRM, - hide_continue=True, - br_code=ButtonRequestType.ConfirmOutput, + title="Debited amount", + amount=format_amount(op.send_max, op.send_asset), + description="Pay at most:", + br_type="op_path_payment", ) await confirm_asset_issuer(ctx, op.send_asset) async def confirm_payment_op(ctx, op: StellarPaymentOp): - description = "Pay {}\n{} to:".format( - format_amount(op.amount, ticker=False), format_asset_code(op.asset) + await confirm_output( + ctx, + address=op.destination_account, + amount=format_amount(op.amount, op.asset), ) - await require_confirm_op( - ctx, "op_payment", description, op.destination_account, is_account=True - ) - await confirm_asset_issuer(ctx, op.asset) async def confirm_set_options_op(ctx, op: StellarSetOptionsOp): if op.inflation_destination_account: - await require_confirm_op( + await confirm_address( ctx, - "op_inflation", - "Set Inflation Destination", + "Inflation", op.inflation_destination_account, + description="Destination:", + br_type="op_inflation", ) + if op.clear_flags: t = _format_flags(op.clear_flags) - await require_confirm_op(ctx, "op_clear_flags", "Clear Flags", t, split=False) + await confirm_text(ctx, "op_set_options", "Clear flags", data=t) + if op.set_flags: t = _format_flags(op.set_flags) - await require_confirm_op(ctx, "op_set_flags", "Set Flags", t, split=False) + await confirm_text(ctx, "op_set_options", "Set flags", data=t) + thresholds = _format_thresholds(op) if thresholds: - await require_confirm_op( - ctx, - "op_thresholds", - "Account Thresholds", - thresholds, - split=False, + await confirm_properties( + ctx, "op_thresholds", "Account Thresholds", props=thresholds ) + if op.home_domain: - await require_confirm_op(ctx, "op_home_domain", "Home Domain", op.home_domain) + await confirm_text(ctx, "op_home_domain", "Home Domain", op.home_domain) + if op.signer_type is not None: if op.signer_weight > 0: - t = "Add Signer (%s)" + title = "Add Signer" else: - t = "Remove Signer (%s)" + title = "Remove Signer" + data: str | bytes = "" if op.signer_type == consts.SIGN_TYPE_ACCOUNT: - await require_confirm_op( - ctx, - "op_signer", - t % "acc", - helpers.address_from_public_key(op.signer_key), - ) - elif op.signer_type in (consts.SIGN_TYPE_PRE_AUTH, consts.SIGN_TYPE_HASH): - if op.signer_type == consts.SIGN_TYPE_PRE_AUTH: - signer_type = "auth" - else: - signer_type = "hash" - await require_confirm_op( - ctx, - "op_signer", - t % signer_type, - hexlify(op.signer_key).decode(), - ) + description = "Account:" + data = helpers.address_from_public_key(op.signer_key) + elif op.signer_type == consts.SIGN_TYPE_PRE_AUTH: + description = "Pre-auth transaction:" + data = op.signer_key + elif op.signer_type == consts.SIGN_TYPE_HASH: + description = "Hash:" + data = op.signer_key else: raise ProcessError("Stellar: invalid signer type") + await confirm_blob( + ctx, + "op_signer", + title=title, + description=description, + data=data, + ) -def _format_thresholds(op: StellarSetOptionsOp) -> tuple: - text = "" + +def _format_thresholds(op: StellarSetOptionsOp) -> list[(str, str)]: + props = [] if op.master_weight is not None: - text += "Master Weight: %d\n" % op.master_weight + props.append(("Master Weight:", str(op.master_weight))) if op.low_threshold is not None: - text += "Low: %d\n" % op.low_threshold + props.append(("Low:", str(op.low_threshold))) if op.medium_threshold is not None: - text += "Medium: %d\n" % op.medium_threshold + props.append(("Medium:", str(op.medium_threshold))) if op.high_threshold is not None: - text += "High: %d\n" % op.high_threshold - return text + props.append(("High:", str(op.high_threshold))) + return props def _format_flags(flags: int) -> tuple: @@ -254,19 +257,13 @@ def _format_flags(flags: int) -> tuple: return text -def format_asset_code(asset: StellarAssetType) -> str: - if asset is None or asset.type == consts.ASSET_TYPE_NATIVE: - return "XLM (native)" - return asset.code - - async def confirm_asset_issuer(ctx, asset: StellarAssetType): if asset is None or asset.type == consts.ASSET_TYPE_NATIVE: return - await require_confirm_op( + await confirm_address( ctx, - "confirm_issuer", - title="Confirm issuer", - subtitle="%s issuer:" % asset.code, - data=asset.issuer, + "Confirm Issuer", + asset.issuer, + description="{} issuer:".format(asset.code), + br_type="confirm_asset_issuer", )