diff --git a/core/src/apps/nem/layout.py b/core/src/apps/nem/layout.py index 6dad04c88..7d4ae5eff 100644 --- a/core/src/apps/nem/layout.py +++ b/core/src/apps/nem/layout.py @@ -1,39 +1,50 @@ -from trezor import ui from trezor.enums import ButtonRequestType from trezor.strings import format_amount -from trezor.ui.components.tt.text import Text - -from apps.common.confirm import require_confirm, require_hold_to_confirm +from trezor.ui.layouts import confirm_metadata, confirm_properties from .helpers import NEM_MAX_DIVISIBILITY async def require_confirm_text(ctx, action: str): - text = Text("Confirm action", ui.ICON_SEND, ui.GREEN, new_lines=False) - text.normal(action) - await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput) + await confirm_metadata( + ctx, + "confirm_nem", + title="Confirm action", + content=action, + hide_continue=True, + br_code=ButtonRequestType.ConfirmOutput, + ) async def require_confirm_fee(ctx, action: str, fee: int): - content = ( - ui.NORMAL, - action, - ui.BOLD, - "%s XEM" % format_amount(fee, NEM_MAX_DIVISIBILITY), + await confirm_metadata( + ctx, + "confirm_fee", + title="Confirm fee", + content=action + "\n{}", + param="{} XEM".format(format_amount(fee, NEM_MAX_DIVISIBILITY)), + hide_continue=True, + br_code=ButtonRequestType.ConfirmOutput, ) - await require_confirm_content(ctx, "Confirm fee", content) async def require_confirm_content(ctx, headline: str, content: list): - text = Text(headline, ui.ICON_SEND, ui.GREEN) - text.normal(*content) - await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput) + await confirm_properties( + ctx, + "confirm_content", + title=headline, + props=content, + ) async def require_confirm_final(ctx, fee: int): - text = Text("Final confirm", ui.ICON_SEND, ui.GREEN) - text.normal("Sign this transaction") - text.bold("and pay %s XEM" % format_amount(fee, NEM_MAX_DIVISIBILITY)) - text.normal("for network fee?") # we use SignTx, not ConfirmOutput, for compatibility with T1 - await require_hold_to_confirm(ctx, text, ButtonRequestType.SignTx) + await confirm_metadata( + ctx, + "confirm_final", + title="Final confirm", + content="Sign this transaction\n{}\nfor network fee?", + param="and pay {} XEM".format(format_amount(fee, NEM_MAX_DIVISIBILITY)), + hide_continue=True, + hold=True, + ) diff --git a/core/src/apps/nem/mosaic/layout.py b/core/src/apps/nem/mosaic/layout.py index 9d207ee8d..f535f887f 100644 --- a/core/src/apps/nem/mosaic/layout.py +++ b/core/src/apps/nem/mosaic/layout.py @@ -1,16 +1,12 @@ from trezor import ui -from trezor.enums import ButtonRequestType, NEMMosaicLevy, NEMSupplyChangeType +from trezor.enums import NEMMosaicLevy, NEMSupplyChangeType from trezor.messages import ( NEMMosaicCreation, NEMMosaicDefinition, NEMMosaicSupplyChange, NEMTransactionCommon, ) -from trezor.ui.components.tt.scroll import Paginated -from trezor.ui.components.tt.text import Text - -from apps.common.confirm import require_confirm -from apps.common.layout import split_address +from trezor.ui.layouts import confirm_properties from ..layout import ( require_confirm_content, @@ -47,27 +43,15 @@ async def ask_supply_change( def _creation_message(mosaic_creation): return [ - ui.NORMAL, - "Create mosaic", - ui.BOLD, - mosaic_creation.definition.mosaic, - ui.NORMAL, - "under namespace", - ui.BOLD, - mosaic_creation.definition.namespace, + ("Create mosaic", mosaic_creation.definition.mosaic), + ("under namespace", mosaic_creation.definition.namespace), ] def _supply_message(supply_change): return [ - ui.NORMAL, - "Modify supply for", - ui.BOLD, - supply_change.mosaic, - ui.NORMAL, - "under namespace", - ui.BOLD, - supply_change.namespace, + ("Modify supply for", supply_change.mosaic), + ("under namespace", supply_change.namespace), ] @@ -76,21 +60,14 @@ async def require_confirm_properties(ctx, definition: NEMMosaicDefinition): # description if definition.description: - t = Text("Confirm properties", ui.ICON_SEND, new_lines=False) - t.bold("Description:") - t.br() - t.normal(*definition.description.split(" ")) - properties.append(t) + properties.append(("Description:", definition.description)) # transferable if definition.transferable: transferable = "Yes" else: transferable = "No" - t = Text("Confirm properties", ui.ICON_SEND) - t.bold("Transferable?") - t.normal(transferable) - properties.append(t) + properties.append(("Transferable?", transferable)) # mutable_supply if definition.mutable_supply: @@ -98,45 +75,30 @@ async def require_confirm_properties(ctx, definition: NEMMosaicDefinition): else: imm = "immutable" if definition.supply: - t = Text("Confirm properties", ui.ICON_SEND) - t.bold("Initial supply:") - t.normal(str(definition.supply), imm) + properties.append(("Initial supply:", str(definition.supply) + "\n" + imm)) else: - t = Text("Confirm properties", ui.ICON_SEND) - t.bold("Initial supply:") - t.normal(imm) - properties.append(t) + properties.append(("Initial supply:", imm)) # levy if definition.levy: + properties.append(("Levy recipient:", definition.levy_address)) + + properties.append(("Levy fee:", str(definition.fee))) + properties.append(("Levy divisibility:", str(definition.divisibility))) - t = Text("Confirm properties", ui.ICON_SEND) - t.bold("Levy recipient:") - t.mono(*split_address(definition.levy_address)) - properties.append(t) - - t = Text("Confirm properties", ui.ICON_SEND) - t.bold("Levy fee:") - t.normal(str(definition.fee)) - t.bold("Levy divisibility:") - t.normal(str(definition.divisibility)) - properties.append(t) - - t = Text("Confirm properties", ui.ICON_SEND) - t.bold("Levy namespace:") - t.normal(definition.levy_namespace) - t.bold("Levy mosaic:") - t.normal(definition.levy_mosaic) - properties.append(t) + properties.append(("Levy namespace:", definition.levy_namespace)) + properties.append(("Levy mosaic:", definition.levy_mosaic)) if definition.levy == NEMMosaicLevy.MosaicLevy_Absolute: levy_type = "absolute" else: levy_type = "percentile" - t = Text("Confirm properties", ui.ICON_SEND) - t.bold("Levy type:") - t.normal(levy_type) - properties.append(t) - - paginated = Paginated(properties) - await require_confirm(ctx, paginated, ButtonRequestType.ConfirmOutput) + properties.append(("Levy type:", levy_type)) + + await confirm_properties( + ctx, + "confirm_properties", + title="Confirm properties", + props=properties, + icon_color=ui.ORANGE_ICON, + ) diff --git a/core/src/apps/nem/multisig/layout.py b/core/src/apps/nem/multisig/layout.py index 108b011d3..bced5f386 100644 --- a/core/src/apps/nem/multisig/layout.py +++ b/core/src/apps/nem/multisig/layout.py @@ -2,16 +2,10 @@ from trezor import ui from trezor.crypto import nem from trezor.enums import ButtonRequestType, NEMModificationType from trezor.messages import NEMAggregateModification, NEMSignTx, NEMTransactionCommon -from trezor.ui.components.tt.text import Text +from trezor.ui.constants import MONO_ADDR_PER_LINE +from trezor.ui.layouts import confirm_hex -from apps.common.layout import split_address - -from ..layout import ( - require_confirm, - require_confirm_fee, - require_confirm_final, - require_confirm_text, -) +from ..layout import require_confirm_fee, require_confirm_final, require_confirm_text async def ask_multisig(ctx, msg: NEMSignTx): @@ -48,7 +42,14 @@ async def ask_aggregate_modification( async def _require_confirm_address(ctx, action: str, address: str): - text = Text("Confirm address", ui.ICON_SEND, ui.GREEN) - text.normal(action) - text.mono(*split_address(address)) - await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput) + await confirm_hex( + ctx, + br_type="confirm_multisig", + title="Confirm address", + description=action, + data=address, + br_code=ButtonRequestType.ConfirmOutput, + icon=ui.ICON_SEND, + width=MONO_ADDR_PER_LINE, + truncate=True, + ) diff --git a/core/src/apps/nem/namespace/layout.py b/core/src/apps/nem/namespace/layout.py index bc94360bc..5c87aab3f 100644 --- a/core/src/apps/nem/namespace/layout.py +++ b/core/src/apps/nem/namespace/layout.py @@ -1,4 +1,3 @@ -from trezor import ui from trezor.messages import NEMProvisionNamespace, NEMTransactionCommon from ..layout import require_confirm_content, require_confirm_fee, require_confirm_final @@ -8,19 +7,13 @@ async def ask_provision_namespace( ctx, common: NEMTransactionCommon, namespace: NEMProvisionNamespace ): if namespace.parent: - content = ( - ui.NORMAL, - "Create namespace", - ui.BOLD, - namespace.namespace, - ui.NORMAL, - "under namespace", - ui.BOLD, - namespace.parent, - ) + content = [ + ("Create namespace", namespace.namespace), + ("under namespace", namespace.parent), + ] await require_confirm_content(ctx, "Confirm namespace", content) else: - content = (ui.NORMAL, "Create namespace", ui.BOLD, namespace.namespace) + content = [("Create namespace", namespace.namespace)] await require_confirm_content(ctx, "Confirm namespace", content) await require_confirm_fee(ctx, "Confirm rental fee", namespace.fee) diff --git a/core/src/apps/nem/transfer/layout.py b/core/src/apps/nem/transfer/layout.py index 7ffa9d344..5faa37fae 100644 --- a/core/src/apps/nem/transfer/layout.py +++ b/core/src/apps/nem/transfer/layout.py @@ -7,10 +7,7 @@ from trezor.messages import ( NEMTransfer, ) from trezor.strings import format_amount -from trezor.ui.components.tt.text import Text - -from apps.common.confirm import require_confirm -from apps.common.layout import split_address +from trezor.ui.layouts import confirm_action, confirm_output, confirm_properties from ..helpers import ( NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE, @@ -46,37 +43,52 @@ async def ask_transfer_mosaic( mosaic_quantity = mosaic.quantity * transfer.amount / NEM_MOSAIC_AMOUNT_DIVISOR if definition: - msg = Text("Confirm mosaic", ui.ICON_SEND, ui.GREEN) - msg.normal("Confirm transfer of") - msg.bold( - format_amount(mosaic_quantity, definition["divisibility"]) - + definition["ticker"] + await confirm_properties( + ctx, + "confirm_mosaic", + title="Confirm mosaic", + props=[ + ( + "Confirm transfer of", + format_amount(mosaic_quantity, definition["divisibility"]) + + definition["ticker"], + ), + ("of", definition["name"]), + ], ) - msg.normal("of") - msg.bold(definition["name"]) - await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) if "levy" in definition and "fee" in definition: levy_msg = _get_levy_msg(definition, mosaic_quantity, common.network) - msg = Text("Confirm mosaic", ui.ICON_SEND, ui.GREEN) - msg.normal("Confirm mosaic", "levy fee of") - msg.bold(levy_msg) - await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) + await confirm_properties( + ctx, + "confirm_mosaic_levy", + title="Confirm mosaic", + props=[ + ("Confirm mosaic\nlevy fee of", levy_msg), + ], + ) else: - msg = Text("Confirm mosaic", ui.ICON_SEND, ui.RED) - msg.bold("Unknown mosaic!") - msg.normal("Divisibility and levy") - msg.normal("cannot be shown for") - msg.normal("unknown mosaics") - await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) + await confirm_action( + ctx, + "confirm_mosaic_unknown", + title="Confirm mosaic", + action="Unknown mosaic!", + description="Divisibility and levy cannot be shown for unknown mosaics", + icon=ui.ICON_SEND, + icon_color=ui.RED, + br_code=ButtonRequestType.ConfirmOutput, + ) - msg = Text("Confirm mosaic", ui.ICON_SEND, ui.GREEN) - msg.normal("Confirm transfer of") - msg.bold("%s raw units" % mosaic_quantity) - msg.normal("of") - msg.bold("%s.%s" % (mosaic.namespace, mosaic.mosaic)) - await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) + await confirm_properties( + ctx, + "confirm_mosaic_transfer", + title="Confirm mosaic", + props=[ + ("Confirm transfer of", "%s raw units" % mosaic_quantity), + ("of", "%s.%s" % (mosaic.namespace, mosaic.mosaic)), + ], + ) def _get_xem_amount(transfer: NEMTransfer): @@ -119,22 +131,27 @@ async def ask_importance_transfer( async def _require_confirm_transfer(ctx, recipient, value): - text = Text("Confirm transfer", ui.ICON_SEND, ui.GREEN) - text.bold("Send %s XEM" % format_amount(value, NEM_MAX_DIVISIBILITY)) - text.normal("to") - text.mono(*split_address(recipient)) - await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput) + await confirm_output( + ctx, + recipient, + amount="Send {} XEM".format(format_amount(value, NEM_MAX_DIVISIBILITY)), + font_amount=ui.BOLD, + title="Confirm transfer", + to_str="\nto\n", + ) async def _require_confirm_payload(ctx, payload: bytearray, encrypt=False): payload = bytes(payload).decode() - - if encrypt: - text = Text("Confirm payload", ui.ICON_SEND, ui.GREEN) - text.bold("Encrypted:") - text.normal(payload) - else: - text = Text("Confirm payload", ui.ICON_SEND, ui.RED) - text.bold("Unencrypted:") - text.normal(payload) - await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput) + subtitle = "Encrypted:" if encrypt else "Unencrypted:" + + await confirm_properties( + ctx, + "confirm_payload", + title="Confirm payload", + props=[ + (None, subtitle), + (payload, None), + ], + icon_color=ui.GREEN if encrypt else ui.RED, + ) diff --git a/core/src/trezor/ui/layouts/tt.py b/core/src/trezor/ui/layouts/tt.py index 463ad0ea1..5049bb369 100644 --- a/core/src/trezor/ui/layouts/tt.py +++ b/core/src/trezor/ui/layouts/tt.py @@ -36,7 +36,7 @@ if False: ) ExceptionType = Union[BaseException, Type[BaseException]] - PropertyType = Tuple[str, Optional[str]] + PropertyType = Tuple[Optional[str], Optional[str]] __all__ = ( @@ -590,7 +590,8 @@ async def confirm_properties( ) -> None: para = [] for p in props: - para.append((ui.NORMAL, p[0])) + if p[0] is not None: + para.append((ui.NORMAL, p[0])) if p[1] is not None: para.append((ui.BOLD, p[1])) content = paginate_paragraphs( diff --git a/tests/device_tests/test_msg_nem_getaddress.py b/tests/device_tests/test_msg_nem_getaddress.py index 2316b688e..883ac363c 100644 --- a/tests/device_tests/test_msg_nem_getaddress.py +++ b/tests/device_tests/test_msg_nem_getaddress.py @@ -28,10 +28,14 @@ class TestMsgNEMGetaddress: @pytest.mark.setup_client(mnemonic=MNEMONIC12) def test_nem_getaddress(self, client): assert ( - nem.get_address(client, parse_path("m/44'/1'/0'/0'/0'"), 0x68) + nem.get_address( + client, parse_path("m/44'/1'/0'/0'/0'"), 0x68, show_display=True + ) == "NB3JCHVARQNGDS3UVGAJPTFE22UQFGMCQGHUBWQN" ) assert ( - nem.get_address(client, parse_path("m/44'/1'/0'/0'/0'"), 0x98) + nem.get_address( + client, parse_path("m/44'/1'/0'/0'/0'"), 0x98, show_display=True + ) == "TB3JCHVARQNGDS3UVGAJPTFE22UQFGMCQHSBNBMF" )