diff --git a/core/src/apps/common/layout.py b/core/src/apps/common/layout.py index 1e16c5d97c..d3fe8b4785 100644 --- a/core/src/apps/common/layout.py +++ b/core/src/apps/common/layout.py @@ -6,6 +6,7 @@ from trezor.messages import ButtonRequestType from trezor.ui.button import ButtonDefault from trezor.ui.container import Container from trezor.ui.qr import Qr +from trezor.ui.scroll import Paginated from trezor.ui.text import Text from trezor.utils import chunks @@ -13,12 +14,16 @@ from apps.common import HARDENED from apps.common.confirm import confirm, require_confirm if False: - from typing import Iterable, Iterator + from typing import Iterable, Iterator, List from trezor import wire async def show_address( - ctx: wire.Context, address: str, desc: str = "Confirm address", network: str = None + ctx: wire.Context, + address: str, + desc: str = "Confirm address", + cancel: str = "QR", + network: str = None, ) -> bool: text = Text(desc, ui.ICON_RECEIVE, ui.GREEN) if network is not None: @@ -29,13 +34,16 @@ async def show_address( ctx, text, code=ButtonRequestType.Address, - cancel="QR", + cancel=cancel, cancel_style=ButtonDefault, ) async def show_qr( - ctx: wire.Context, address: str, desc: str = "Confirm address" + ctx: wire.Context, + address: str, + desc: str = "Confirm address", + cancel: str = "Address", ) -> bool: QR_X = const(120) QR_Y = const(115) @@ -48,7 +56,7 @@ async def show_qr( ctx, content, code=ButtonRequestType.Address, - cancel="Address", + cancel=cancel, cancel_style=ButtonDefault, ) @@ -60,6 +68,22 @@ async def show_pubkey(ctx: wire.Context, pubkey: bytes) -> None: await require_confirm(ctx, text, ButtonRequestType.PublicKey) +async def show_xpub(ctx: wire.Context, xpub: str, desc: str, cancel: str) -> bool: + pages = [] # type: List[ui.Component] + for lines in chunks(list(chunks(xpub, 16)), 5): + text = Text(desc, ui.ICON_RECEIVE, ui.GREEN) + text.mono(*lines) + pages.append(text) + + return await confirm( + ctx, + Paginated(pages), + code=ButtonRequestType.PublicKey, + cancel=cancel, + cancel_style=ButtonDefault, + ) + + def split_address(address: str) -> Iterator[str]: return chunks(address, 17) diff --git a/core/src/apps/wallet/get_address.py b/core/src/apps/wallet/get_address.py index f07d7b01bf..be07e6c16c 100644 --- a/core/src/apps/wallet/get_address.py +++ b/core/src/apps/wallet/get_address.py @@ -1,11 +1,37 @@ +from trezor.crypto import bip32 from trezor.messages import InputScriptType from trezor.messages.Address import Address from apps.common import coins -from apps.common.layout import address_n_to_str, show_address, show_qr +from apps.common.layout import address_n_to_str, show_address, show_qr, show_xpub from apps.common.paths import validate_path from apps.wallet.sign_tx import addresses +if False: + from typing import List + from trezor.messages import HDNodeType + from trezor import wire + from apps.common.coininfo import CoinInfo + + +async def show_xpubs( + ctx: wire.Context, coin: CoinInfo, pubnodes: List[HDNodeType] +) -> bool: + for i, x in enumerate(pubnodes): + cancel = "Next" if i < len(pubnodes) - 1 else "Address" + node = bip32.HDNode( + depth=x.depth, + fingerprint=x.fingerprint, + child_num=x.child_num, + chain_code=x.chain_code, + public_key=x.public_key, + curve_name=coin.curve_name, + ) + xpub = node.serialize_public(coin.xpub_magic) + if await show_xpub(ctx, xpub, desc="XPUB #%d" % (i + 1), cancel=cancel): + return True + return False + async def get_address(ctx, msg, keychain): coin_name = msg.coin_name or "Bitcoin" @@ -33,14 +59,24 @@ async def get_address(ctx, msg, keychain): if msg.show_display: if msg.multisig: - desc = "Multisig %d of %d" % (msg.multisig.m, len(msg.multisig.pubkeys)) + if msg.multisig.nodes: + pubnodes = msg.multisig.nodes + else: + pubnodes = [hd.node for hd in msg.multisig.pubkeys] + desc = "Multisig %d of %d" % (msg.multisig.m, len(pubnodes)) + while True: + if await show_address(ctx, address_short, desc=desc): + break + if await show_qr(ctx, address_qr, desc=desc, cancel="XPUBs"): + break + if await show_xpubs(ctx, coin, pubnodes): + break else: desc = address_n_to_str(msg.address_n) - - while True: - if await show_address(ctx, address_short, desc=desc): - break - if await show_qr(ctx, address_qr, desc=desc): - break + while True: + if await show_address(ctx, address_short, desc=desc): + break + if await show_qr(ctx, address_qr, desc=desc): + break return Address(address=address)