from trezor import ui from trezor.messages import ( ButtonRequestType, NEMImportanceTransfer, NEMImportanceTransferMode, NEMMosaic, NEMMosaicLevy, NEMTransactionCommon, NEMTransfer, ) from trezor.strings import format_amount from trezor.ui.text import Text from apps.common.confirm import require_confirm from apps.common.layout import split_address from ..helpers import ( NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE, NEM_MAX_DIVISIBILITY, NEM_MOSAIC_AMOUNT_DIVISOR, ) from ..layout import require_confirm_final, require_confirm_text from ..mosaic.helpers import get_mosaic_definition, is_nem_xem_mosaic async def ask_transfer( ctx, common: NEMTransactionCommon, transfer: NEMTransfer, payload: bytes, encrypted: bool, ): if payload: await _require_confirm_payload(ctx, transfer.payload, encrypted) for mosaic in transfer.mosaics: await ask_transfer_mosaic(ctx, common, transfer, mosaic) await _require_confirm_transfer(ctx, transfer.recipient, _get_xem_amount(transfer)) await require_confirm_final(ctx, common.fee) async def ask_transfer_mosaic( ctx, common: NEMTransactionCommon, transfer: NEMTransfer, mosaic: NEMMosaic ): if is_nem_xem_mosaic(mosaic.namespace, mosaic.mosaic): return definition = get_mosaic_definition(mosaic.namespace, mosaic.mosaic, common.network) 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"] ) 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) 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) 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) def _get_xem_amount(transfer: NEMTransfer): # if mosaics are empty the transfer.amount denotes the xem amount if not transfer.mosaics: return transfer.amount # otherwise xem amount is taken from the nem xem mosaic if present for mosaic in transfer.mosaics: if is_nem_xem_mosaic(mosaic.namespace, mosaic.mosaic): return mosaic.quantity * transfer.amount / NEM_MOSAIC_AMOUNT_DIVISOR # if there are mosaics but do not include xem, 0 xem is sent return 0 def _get_levy_msg(mosaic_definition, quantity: int, network: int) -> str: levy_definition = get_mosaic_definition( mosaic_definition["levy_namespace"], mosaic_definition["levy_mosaic"], network ) if mosaic_definition["levy"] == NEMMosaicLevy.MosaicLevy_Absolute: levy_fee = mosaic_definition["fee"] else: levy_fee = ( quantity * mosaic_definition["fee"] / NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE ) return ( format_amount(levy_fee, levy_definition["divisibility"]) + levy_definition["ticker"] ) async def ask_importance_transfer( ctx, common: NEMTransactionCommon, imp: NEMImportanceTransfer ): if imp.mode == NEMImportanceTransferMode.ImportanceTransfer_Activate: m = "Activate" else: m = "Deactivate" await require_confirm_text(ctx, m + " remote harvesting?") await require_confirm_final(ctx, common.fee) 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) 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)