async def require_confirm_transfer(ctx, msg: BinanceTransferMsg): def make_input_output_pages(msg: BinanceInputOutput, direction): pages = [] for coin in msg.coins: coin_page = Text("Confirm " + direction, ui.ICON_SEND, icon_color=ui.GREEN) coin_page.bold( format_amount(coin.amount, helpers.DECIMALS) + " " + coin.denom) coin_page.normal("to") coin_page.mono(*split_address(msg.address)) pages.append(coin_page) return pages pages = [] for txinput in msg.inputs: pages.extend(make_input_output_pages(txinput, "input")) for txoutput in msg.outputs: pages.extend(make_input_output_pages(txoutput, "output")) return await require_hold_to_confirm(ctx, Paginated(pages), ButtonRequestType.ConfirmOutput)
async def confirm_transaction( ctx: wire.Context, amount: int, fee: int, protocol_magic: int, ttl: int | None, validity_interval_start: int | None, is_network_id_verifiable: bool, ) -> None: pages: list[ui.Component] = [] page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.normal("Transaction amount:") page1.bold(format_coin_amount(amount)) page1.normal("Transaction fee:") page1.bold(format_coin_amount(fee)) pages.append(page1) page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) if is_network_id_verifiable: page2.normal("Network:") page2.bold(protocol_magics.to_ui_string(protocol_magic)) page2.normal("Valid since: %s" % format_optional_int(validity_interval_start)) page2.normal("TTL: %s" % format_optional_int(ttl)) pages.append(page2) await require_hold_to_confirm(ctx, Paginated(pages))
async def confirm_stake_pool_owners( ctx: wire.Context, keychain: seed.Keychain, owners: list[CardanoPoolOwnerType], network_id: int, ) -> None: pages: list[ui.Component] = [] for index, owner in enumerate(owners, 1): page = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page.normal("Pool owner #%d:" % (index)) if owner.staking_key_path: page.bold(address_n_to_str(owner.staking_key_path)) page.normal( encode_human_readable_address( pack_reward_address_bytes( get_public_key_hash(keychain, owner.staking_key_path), network_id, ))) else: assert owner.staking_key_hash is not None # validate_pool_owners page.bold( encode_human_readable_address( pack_reward_address_bytes(owner.staking_key_hash, network_id))) pages.append(page) await require_confirm(ctx, Paginated(pages))
async def confirm_stake_pool_parameters( ctx: wire.Context, pool_parameters: CardanoPoolParametersType, network_id: int, protocol_magic: int, ) -> None: page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.bold("Stake pool registration") page1.normal("Pool ID:") page1.bold(format_stake_pool_id(pool_parameters.pool_id)) page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page2.normal("Pool reward account:") page2.bold(pool_parameters.reward_account) page3 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page3.normal("Pledge: " + format_coin_amount(pool_parameters.pledge)) page3.normal("Cost: " + format_coin_amount(pool_parameters.cost)) margin_percentage = ( 100.0 * pool_parameters.margin_numerator / pool_parameters.margin_denominator ) percentage_formatted = ("%f" % margin_percentage).rstrip("0").rstrip(".") page3.normal("Margin: %s%%" % percentage_formatted) await require_confirm(ctx, Paginated([page1, page2, page3]))
async def show_warning_address_foreign_staking_key( ctx: wire.Context, account_path: list[int], staking_account_path: list[int], staking_key_hash: bytes | None, ) -> None: page1 = Text("Warning", ui.ICON_WRONG, ui.RED) page1.normal("Stake rights associated") page1.normal("with this address do") page1.normal("not match your") page1.normal("account %s:" % format_account_number(account_path)) page1.bold(address_n_to_str(account_path)) page2 = Text("Warning", ui.ICON_WRONG, ui.RED) if staking_account_path: page2.normal("Stake account %s:" % format_account_number(staking_account_path)) page2.bold(address_n_to_str(staking_account_path)) page2.br_half() else: assert staking_key_hash is not None # _validate_base_address_staking_info page2.normal("Staking key:") page2.bold(hexlify(staking_key_hash).decode()) page2.normal("Continue?") await require_confirm(ctx, Paginated([page1, page2]))
async def show_remaining_shares( ctx: wire.GenericContext, groups: Iterable[tuple[int, tuple[str, ...]]], # remaining + list 3 words shares_remaining: list[int], group_threshold: int, ) -> None: pages: list[ui.Component] = [] for remaining, group in groups: if 0 < remaining < MAX_SHARE_COUNT: text = Text("Remaining Shares") text.bold( strings.format_plural("{count} more {plural} starting", remaining, "share")) for word in group: text.normal(word) pages.append(text) elif (remaining == MAX_SHARE_COUNT and shares_remaining.count(0) < group_threshold): text = Text("Remaining Shares") groups_remaining = group_threshold - shares_remaining.count(0) text.bold( strings.format_plural("{count} more {plural} starting", groups_remaining, "group")) for word in group: text.normal(word) pages.append(text) await confirm(ctx, Paginated(pages), cancel=None)
async def confirm_sending_token_hex(ctx: wire.Context, token: CardanoTokenType, token_number: int) -> None: page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.bold("Asset #%s name (hex):" % (token_number)) page1.mono(hexlify(token.asset_name_bytes).decode()) page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page2.normal("Amount sent:") page2.bold(format_amount(token.amount, 0)) await require_confirm(ctx, Paginated([page1, page2]))
async def show_address( ctx: wire.Context, address: str, address_type: EnumTypeCardanoAddressType, path: List[int], network: str = None, ) -> bool: """ Custom show_address function is needed because cardano addresses don't fit on a single screen. """ address_type_label = "%s address" % ADDRESS_TYPE_NAMES[address_type] page1 = Text(address_type_label, ui.ICON_RECEIVE, ui.GREEN) lines_per_page = 5 lines_used_on_first_page = 0 # assemble first page to be displayed (path + network + whatever part of the address fits) if network is not None: page1.normal("%s network" % network) lines_used_on_first_page += 1 path_str = address_n_to_str(path) page1.mono(path_str) lines_used_on_first_page = min( lines_used_on_first_page + math.ceil(len(path_str) / _MAX_MONO_LINE), lines_per_page, ) address_lines = list(chunks(address, 17)) for address_line in address_lines[: lines_per_page - lines_used_on_first_page]: page1.bold(address_line) pages: List[ui.Component] = [] pages.append(page1) # append remaining pages containing the rest of the address pages.extend( _paginate_lines( address_lines, lines_per_page - lines_used_on_first_page, address_type_label, ui.ICON_RECEIVE, lines_per_page, ) ) return await confirm( ctx, Paginated(pages), code=ButtonRequestType.Address, cancel="QR", cancel_style=ButtonDefault, )
async def _require_confirm_paginated(ctx: wire.Context, header: str, fields: List[str], per_page: int) -> None: pages = [] for page in chunks(fields, per_page): if header == "Arbitrary data": text = Text(header, ui.ICON_WIPE, ui.RED) else: text = Text(header, ui.ICON_CONFIRM, ui.GREEN) text.mono(*page) pages.append(text) await require_confirm(ctx, Paginated(pages), ButtonRequestType.ConfirmOutput)
async def require_confirm_cancel(ctx, msg: BinanceCancelMsg): page1 = Text("Confirm cancel 1/2", ui.ICON_SEND, icon_color=ui.GREEN) page1.normal("Sender address:") page1.bold(msg.sender) page1.normal("Pair:") page1.bold(msg.symbol) page2 = Text("Confirm cancel 2/2", ui.ICON_SEND, icon_color=ui.GREEN) page2.normal("Order ID:") page2.bold(msg.refid) return await require_hold_to_confirm(ctx, Paginated([page1, page2]), ButtonRequestType.SignTx)
async def confirm_sending_token_bundle( ctx: wire.Context, token_bundle: list[CardanoAssetGroupType]) -> None: for token_group in token_bundle: for token in token_group.tokens: page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.normal("Asset fingerprint:") page1.bold( format_asset_fingerprint( policy_id=token_group.policy_id, asset_name_bytes=token.asset_name_bytes, )) page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page2.normal("Amount sent:") page2.bold(format_amount(token.amount, 0)) await require_confirm(ctx, Paginated([page1, page2]))
async def require_confirm_proposals(ctx, proposals): if len(proposals) > 1: title = "Submit proposals" else: title = "Submit proposal" pages = [] for page, proposal in enumerate(proposals): text = Text(title, ui.ICON_SEND, icon_color=ui.PURPLE) text.bold("Proposal {}: ".format(page + 1)) text.mono(*split_proposal(proposal)) pages.append(text) paginated = Paginated(pages) await require_confirm(ctx, paginated, ButtonRequestType.SignTx)
async def show_warning_tx_different_staking_account( ctx: wire.Context, staking_account_path: List[int], amount: int, ) -> None: page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.normal("Change address staking") page1.normal("rights do not match") page1.normal("the current account.") page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page2.normal("Staking account %s:" % format_account_number(staking_account_path)) page2.bold(address_n_to_str(staking_account_path)) page2.normal("Change amount:") page2.bold(format_coin_amount(amount)) await require_confirm(ctx, Paginated([page1, page2]))
async def show_address( ctx: wire.Context, address: str, address_type: CardanoAddressType, path: list[int], network: str | None = None, ) -> bool: """ Custom show_address function is needed because cardano addresses don't fit on a single screen. """ address_type_label = "%s address" % ADDRESS_TYPE_NAMES[address_type] page1 = Text(address_type_label, ui.ICON_RECEIVE, ui.GREEN) lines_per_page = 5 lines_used_on_first_page = 0 # assemble first page to be displayed (path + network + whatever part of the address fits) if network is not None: page1.normal("%s network" % network) lines_used_on_first_page += 1 path_str = address_n_to_str(path) page1.mono(path_str) lines_used_on_first_page = min( lines_used_on_first_page + math.ceil(len(path_str) / _MAX_MONO_LINE), lines_per_page, ) pages = _paginate_text( page1, address_type_label, ui.ICON_RECEIVE, address, lines_per_page=lines_per_page, lines_used_on_first_page=lines_used_on_first_page, ) return await confirm( ctx, Paginated(pages), code=ButtonRequestType.Address, cancel="QR", cancel_style=ButtonDefault, )
async def show_warning_tx_staking_key_hash( ctx: wire.Context, staking_key_hash: bytes, amount: int, ) -> None: page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.normal("Change address staking") page1.normal("rights do not match") page1.normal("the current account.") page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page2.normal("Staking key hash:") page2.mono(*chunks(hexlify(staking_key_hash).decode(), 17)) page3 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page3.normal("Change amount:") page3.bold(format_coin_amount(amount)) await require_confirm(ctx, Paginated([page1, page2, page3]))
def paginate_text( text: str, header: str, font: int = ui.NORMAL, header_icon: str = ui.ICON_DEFAULT, icon_color: int = ui.ORANGE_ICON, break_words: bool = False, ) -> Union[Text, Paginated]: span = Span(text, 0, font, break_words=break_words) if span.count_lines() <= TEXT_MAX_LINES: result = Text( header, header_icon=header_icon, icon_color=icon_color, new_lines=False, ) result.content = [font, text] return result else: pages: List[ui.Component] = [] span.reset(text, 0, font, break_words=break_words, line_width=204) while span.has_more_content(): # advance to first line of the page span.next_line() page = Text( header, header_icon=header_icon, icon_color=icon_color, new_lines=False, content_offset=0, char_offset=span.start, line_width=204, render_page_overflow=False, ) page.content = [font, text] pages.append(page) # roll over the remaining lines on the page for _ in range(TEXT_MAX_LINES - 1): span.next_line() return Paginated(pages)
async def show_warning_tx_pointer_address( ctx: wire.Context, pointer: CardanoBlockchainPointerType, amount: int, ) -> None: page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.normal("Change address has a") page1.normal("pointer with staking") page1.normal("rights.") page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page2.normal("Pointer:") page2.bold( "%s, %s, %s" % (pointer.block_index, pointer.tx_index, pointer.certificate_index)) page2.normal("Change amount:") page2.bold(format_coin_amount(amount)) await require_confirm(ctx, Paginated([page1, page2]))
async def confirm_sending( ctx: wire.Context, ada_amount: int, token_bundle: List[CardanoAssetGroupType], to: str, ) -> None: await confirm_sending_token_bundle(ctx, token_bundle) page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.normal("Confirm sending:") page1.bold(format_coin_amount(ada_amount)) page1.normal("to") to_lines = list(chunks(to, 17)) page1.bold(to_lines[0]) comp: ui.Component = page1 # otherwise `[page1]` is of the wrong type pages = [comp] + _paginate_lines(to_lines, 1, "Confirm transaction", ui.ICON_SEND) await require_confirm(ctx, Paginated(pages))
async def confirm_stake_pool_metadata( ctx: wire.Context, metadata: CardanoPoolMetadataType | None, ) -> None: if metadata is None: page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.normal("Pool has no metadata") page1.normal("(anonymous pool)") await require_confirm(ctx, page1) return page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.normal("Pool metadata url:") page1.bold(metadata.url) page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page2.normal("Pool metadata hash:") page2.bold(hexlify(metadata.hash).decode()) await require_confirm(ctx, Paginated([page1, page2]))
async def require_confirm_order(ctx, msg: BinanceOrderMsg): page1 = Text("Confirm order 1/3", ui.ICON_SEND, icon_color=ui.GREEN) page1.normal("Sender address:") page1.bold(msg.sender) page2 = Text("Confirm order 2/3", ui.ICON_SEND, icon_color=ui.GREEN) page2.normal("Pair:") page2.bold(msg.symbol) page2.normal("Side:") if msg.side == BinanceOrderSide.BUY: page2.bold("Buy") elif msg.side == BinanceOrderSide.SELL: page2.bold("Sell") page3 = Text("Confirm order 3/3", ui.ICON_SEND, icon_color=ui.GREEN) page3.normal("Quantity:") page3.bold(format_amount(msg.quantity, helpers.DECIMALS)) page3.normal("Price:") page3.bold(format_amount(msg.price, helpers.DECIMALS)) return await require_hold_to_confirm(ctx, Paginated([page1, page2, page3]), ButtonRequestType.SignTx)
async def show_address( ctx, address: str, desc: str = "Confirm address", network: str = None ): from apps.common.confirm import confirm from trezor.messages import ButtonRequestType from trezor.ui.components.tt.button import ButtonDefault from trezor.ui.components.tt.scroll import Paginated pages = [] for lines in common.paginate_lines(common.split_address(address), 5): text = Text(desc, ui.ICON_RECEIVE, ui.GREEN) if network is not None: text.normal("%s network" % network) text.mono(*lines) pages.append(text) return await confirm( ctx, Paginated(pages), code=ButtonRequestType.Address, cancel="QR", cancel_style=ButtonDefault, )
async def confirm_certificate(ctx: wire.Context, certificate: CardanoTxCertificateType) -> None: # stake pool registration requires custom confirmation logic not covered # in this call assert certificate.type != CardanoCertificateType.STAKE_POOL_REGISTRATION pages: list[ui.Component] = [] page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.normal("Confirm:") page1.bold(CERTIFICATE_TYPE_NAMES[certificate.type]) page1.normal("for account %s:" % format_account_number(certificate.path)) page1.bold(address_n_to_str(to_account_path(certificate.path))) pages.append(page1) if certificate.type == CardanoCertificateType.STAKE_DELEGATION: assert certificate.pool is not None # validate_certificate page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page2.normal("to pool:") page2.bold(format_stake_pool_id(certificate.pool)) pages.append(page2) await require_confirm(ctx, Paginated(pages))
async def confirm_sending( ctx: wire.Context, ada_amount: int, token_bundle: list[CardanoAssetGroupType], to: str, ) -> None: await confirm_sending_token_bundle(ctx, token_bundle) page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.normal("Confirm sending:") page1.bold(format_coin_amount(ada_amount)) page1.normal("to") pages = _paginate_text( page1, "Confirm transaction", ui.ICON_SEND, to, lines_per_page=4, lines_used_on_first_page=3, ) await require_confirm(ctx, Paginated(pages))
async def confirm_catalyst_registration( ctx: wire.Context, public_key: str, staking_path: list[int], reward_address: str, nonce: int, ) -> None: pages: list[ui.Component] = [] page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page1.bold("Catalyst voting key") page1.bold("registration") pages.append(page1) page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page2.normal("Voting public key:") page2.bold(*chunks(public_key, 17)) pages.append(page2) page3 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page3.normal("Staking key for") page3.normal("account %s:" % format_account_number(staking_path)) page3.bold(address_n_to_str(staking_path)) pages.append(page3) page4 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) page4.normal("Rewards go to:") pages.extend( _paginate_text(page4, "Confirm transaction", ui.ICON_SEND, reward_address)) last_page = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) last_page.normal("Nonce: %s" % nonce) pages.append(last_page) await require_confirm(ctx, Paginated(pages))
async def _show_share_words(ctx, share_words, share_index=None, group_index=None): first, chunks, last = _split_share_into_pages(share_words) if share_index is None: header_title = "Recovery seed" elif group_index is None: header_title = "Recovery share #%s" % (share_index + 1) else: header_title = "Group %s - Share %s" % ((group_index + 1), (share_index + 1)) header_icon = ui.ICON_RESET pages = [] # ui page components shares_words_check = [] # check we display correct data # first page text = Text(header_title, header_icon) text.bold("Write down these") text.bold("%s words:" % len(share_words)) text.br_half() for index, word in first: text.mono("%s. %s" % (index + 1, word)) shares_words_check.append(word) pages.append(text) # middle pages for chunk in chunks: text = Text(header_title, header_icon) for index, word in chunk: text.mono("%s. %s" % (index + 1, word)) shares_words_check.append(word) pages.append(text) # last page text = Text(header_title, header_icon) for index, word in last: text.mono("%s. %s" % (index + 1, word)) shares_words_check.append(word) text.br_half() text.bold("I wrote down all %s" % len(share_words)) text.bold("words in order.") pages.append(text) # pagination paginated = Paginated(pages) if __debug__: word_pages = [first] + chunks + [last] def export_displayed_words(): # export currently displayed mnemonic words into debuglink words = [w for _, w in word_pages[paginated.page]] debug.reset_current_words.publish(words) paginated.on_change = export_displayed_words export_displayed_words() # make sure we display correct data utils.ensure(share_words == shares_words_check) # confirm the share await require_hold_to_confirm(ctx, paginated, ButtonRequestType.ResetDevice, cancel=False)
async def require_confirm_properties(ctx, definition: NEMMosaicDefinition): properties = [] # 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) # 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) # mutable_supply if definition.mutable_supply: imm = "mutable" else: imm = "immutable" if definition.supply: t = Text("Confirm properties", ui.ICON_SEND) t.bold("Initial supply:") t.normal(str(definition.supply), imm) else: t = Text("Confirm properties", ui.ICON_SEND) t.bold("Initial supply:") t.normal(imm) properties.append(t) # levy if definition.levy: 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) 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)