mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-10 23:40:58 +00:00
refactor(core): convert rest of apps.bitcoin to layouts
This commit is contained in:
parent
b1e38fe382
commit
2b6ea25712
@ -4,10 +4,9 @@ from trezor import ui
|
||||
from trezor.messages.AuthorizeCoinJoin import AuthorizeCoinJoin
|
||||
from trezor.messages.Success import Success
|
||||
from trezor.strings import format_amount
|
||||
from trezor.ui.components.tt.text import Text
|
||||
from trezor.ui.layouts import confirm_action, confirm_coinjoin, require
|
||||
|
||||
from apps.base import set_authorization
|
||||
from apps.common.confirm import require_confirm, require_hold_to_confirm
|
||||
from apps.common.paths import validate_path
|
||||
|
||||
from .authorization import FEE_PER_ANONYMITY_DECIMALS, CoinJoinAuthorization
|
||||
@ -46,30 +45,30 @@ async def authorize_coinjoin(ctx: wire.Context, msg: AuthorizeCoinJoin) -> Succe
|
||||
),
|
||||
)
|
||||
|
||||
text = Text("Authorize CoinJoin", ui.ICON_RECOVERY)
|
||||
text.normal("Do you really want to")
|
||||
text.normal("take part in a CoinJoin")
|
||||
text.normal("transaction at:")
|
||||
text.mono(msg.coordinator)
|
||||
await require_confirm(ctx, text)
|
||||
|
||||
text = Text("Authorize CoinJoin", ui.ICON_RECOVERY)
|
||||
if msg.fee_per_anonymity is not None:
|
||||
text.normal("Fee per anonymity set:")
|
||||
text.bold(
|
||||
"{} %".format(
|
||||
format_amount(msg.fee_per_anonymity, FEE_PER_ANONYMITY_DECIMALS)
|
||||
)
|
||||
)
|
||||
text.normal("Maximum total fees:")
|
||||
text.bold(
|
||||
format_coin_amount(
|
||||
msg.max_total_fee,
|
||||
coin,
|
||||
msg.amount_unit,
|
||||
await require(
|
||||
confirm_action(
|
||||
ctx,
|
||||
"coinjoin_coordinator",
|
||||
title="Authorize CoinJoin",
|
||||
description="Do you really want to take part in a CoinJoin transaction at:\n{}",
|
||||
description_param=msg.coordinator,
|
||||
description_param_font=ui.MONO,
|
||||
icon=ui.ICON_RECOVERY,
|
||||
)
|
||||
)
|
||||
|
||||
fee_per_anonymity = None
|
||||
if msg.fee_per_anonymity is not None:
|
||||
fee_per_anonymity = format_amount(
|
||||
msg.fee_per_anonymity, FEE_PER_ANONYMITY_DECIMALS
|
||||
)
|
||||
await require(
|
||||
confirm_coinjoin(
|
||||
ctx,
|
||||
fee_per_anonymity,
|
||||
format_coin_amount(msg.max_total_fee, coin, msg.amount_unit),
|
||||
)
|
||||
)
|
||||
await require_hold_to_confirm(ctx, text)
|
||||
|
||||
set_authorization(CoinJoinAuthorization(msg, keychain, coin))
|
||||
|
||||
|
@ -3,9 +3,8 @@ from ubinascii import hexlify
|
||||
from trezor import ui, wire
|
||||
from trezor.messages.GetOwnershipProof import GetOwnershipProof
|
||||
from trezor.messages.OwnershipProof import OwnershipProof
|
||||
from trezor.ui.components.tt.text import Text
|
||||
from trezor.ui.layouts import confirm_action, confirm_hex, require
|
||||
|
||||
from apps.common.confirm import require_confirm
|
||||
from apps.common.paths import validate_path
|
||||
|
||||
from . import addresses, common, scripts
|
||||
@ -65,25 +64,28 @@ async def get_ownership_proof(
|
||||
|
||||
# In order to set the "user confirmation" bit in the proof, the user must actually confirm.
|
||||
if msg.user_confirmation and not authorization:
|
||||
text = Text("Proof of ownership", ui.ICON_CONFIG)
|
||||
text.normal("Do you want to create a")
|
||||
if not msg.commitment_data:
|
||||
text.normal("proof of ownership?")
|
||||
else:
|
||||
hex_data = hexlify(msg.commitment_data).decode()
|
||||
text.normal("proof of ownership for:")
|
||||
if len(hex_data) > 3 * _MAX_MONO_LINE:
|
||||
text.mono(hex_data[0:_MAX_MONO_LINE])
|
||||
text.mono(
|
||||
hex_data[_MAX_MONO_LINE : 3 * _MAX_MONO_LINE // 2 - 1]
|
||||
+ "..."
|
||||
+ hex_data[-3 * _MAX_MONO_LINE // 2 + 2 : -_MAX_MONO_LINE]
|
||||
await require(
|
||||
confirm_action(
|
||||
ctx,
|
||||
"confirm_ownership_proof",
|
||||
title="Proof of ownership",
|
||||
description="Do you want to create a proof of ownership?",
|
||||
)
|
||||
text.mono(hex_data[-_MAX_MONO_LINE:])
|
||||
else:
|
||||
text.mono(hex_data)
|
||||
|
||||
await require_confirm(ctx, text)
|
||||
)
|
||||
else:
|
||||
await require(
|
||||
confirm_hex(
|
||||
ctx,
|
||||
"confirm_ownership_proof",
|
||||
title="Proof of ownership",
|
||||
description="Do you want to create a proof of ownership for:",
|
||||
data=hexlify(msg.commitment_data).decode(),
|
||||
icon=ui.ICON_CONFIG,
|
||||
icon_color=ui.ORANGE_ICON,
|
||||
truncate_middle=True,
|
||||
)
|
||||
)
|
||||
|
||||
ownership_proof, signature = generate_proof(
|
||||
node,
|
||||
|
@ -2,9 +2,10 @@ from trezor import wire
|
||||
from trezor.crypto.curve import secp256k1
|
||||
from trezor.messages.InputScriptType import SPENDADDRESS, SPENDP2SHWITNESS, SPENDWITNESS
|
||||
from trezor.messages.MessageSignature import MessageSignature
|
||||
from trezor.ui.layouts import confirm_signverify, require
|
||||
|
||||
from apps.common.paths import validate_path
|
||||
from apps.common.signverify import message_digest, require_confirm_sign_message
|
||||
from apps.common.signverify import decode_message, message_digest
|
||||
|
||||
from .addresses import get_address
|
||||
from .keychain import with_keychain
|
||||
@ -25,7 +26,7 @@ async def sign_message(
|
||||
script_type = msg.script_type or 0
|
||||
|
||||
await validate_path(ctx, keychain, address_n)
|
||||
await require_confirm_sign_message(ctx, coin.coin_shortcut, message)
|
||||
await require(confirm_signverify(ctx, coin.coin_shortcut, decode_message(message)))
|
||||
|
||||
node = keychain.derive(address_n)
|
||||
seckey = node.private_key()
|
||||
|
@ -59,9 +59,9 @@ async def confirm_output(
|
||||
layout = layouts.confirm_hex(
|
||||
ctx,
|
||||
"op_return",
|
||||
"OP_RETURN",
|
||||
hexlify(data).decode(),
|
||||
ButtonRequestType.ConfirmOutput,
|
||||
title="OP_RETURN",
|
||||
data=hexlify(data).decode(),
|
||||
br_code=ButtonRequestType.ConfirmOutput,
|
||||
)
|
||||
else:
|
||||
assert output.address is not None
|
||||
|
@ -2,9 +2,10 @@ from trezor import wire
|
||||
from trezor.crypto.curve import secp256k1
|
||||
from trezor.messages.InputScriptType import SPENDADDRESS, SPENDP2SHWITNESS, SPENDWITNESS
|
||||
from trezor.messages.Success import Success
|
||||
from trezor.ui.layouts import confirm_signverify, require
|
||||
|
||||
from apps.common import coins
|
||||
from apps.common.signverify import message_digest, require_confirm_verify_message
|
||||
from apps.common.signverify import decode_message, message_digest
|
||||
|
||||
from .addresses import (
|
||||
address_p2wpkh,
|
||||
@ -62,8 +63,13 @@ async def verify_message(ctx: wire.Context, msg: VerifyMessage) -> Success:
|
||||
if addr != address:
|
||||
raise wire.ProcessError("Invalid signature")
|
||||
|
||||
await require_confirm_verify_message(
|
||||
ctx, address_short(coin, address), coin.coin_shortcut, message
|
||||
await require(
|
||||
confirm_signverify(
|
||||
ctx,
|
||||
coin.coin_shortcut,
|
||||
decode_message(message),
|
||||
address=address_short(coin, address),
|
||||
)
|
||||
)
|
||||
|
||||
return Success(message="Message verified")
|
||||
|
@ -3,8 +3,7 @@ from micropython import const
|
||||
from trezor import ui
|
||||
from trezor.messages import ButtonRequestType
|
||||
from trezor.ui.components.tt.button import ButtonDefault
|
||||
from trezor.ui.components.tt.scroll import Paginated
|
||||
from trezor.ui.components.tt.text import TEXT_MAX_LINES, Span, Text
|
||||
from trezor.ui.components.tt.text import Text
|
||||
from trezor.ui.container import Container
|
||||
from trezor.ui.qr import Qr
|
||||
from trezor.utils import chunks
|
||||
@ -13,7 +12,7 @@ from apps.common import HARDENED
|
||||
from apps.common.confirm import confirm
|
||||
|
||||
if False:
|
||||
from typing import Iterable, Iterator, List, Union
|
||||
from typing import Iterable, Iterator
|
||||
from trezor import wire
|
||||
|
||||
|
||||
@ -55,48 +54,3 @@ def address_n_to_str(address_n: Iterable[int]) -> str:
|
||||
return "m"
|
||||
|
||||
return "m/" + "/".join([path_item(i) for i in address_n])
|
||||
|
||||
|
||||
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)
|
||||
|
@ -1,11 +1,8 @@
|
||||
from ubinascii import hexlify
|
||||
|
||||
from trezor import ui, utils, wire
|
||||
from trezor import utils, wire
|
||||
from trezor.crypto.hashlib import blake256, sha256
|
||||
from trezor.ui.components.tt.text import Text
|
||||
|
||||
from apps.common.confirm import require_confirm
|
||||
from apps.common.layout import paginate_text, split_address
|
||||
from apps.common.writers import write_bitcoin_varint
|
||||
|
||||
if False:
|
||||
@ -34,25 +31,3 @@ def decode_message(message: bytes) -> str:
|
||||
return bytes(message).decode()
|
||||
except UnicodeError:
|
||||
return "hex(%s)" % hexlify(message).decode()
|
||||
|
||||
|
||||
async def require_confirm_sign_message(
|
||||
ctx: wire.Context, coin: str, message: bytes
|
||||
) -> None:
|
||||
header = "Sign {} message".format(coin)
|
||||
await require_confirm(ctx, paginate_text(decode_message(message), header))
|
||||
|
||||
|
||||
async def require_confirm_verify_message(
|
||||
ctx: wire.Context, address: str, coin: str, message: bytes
|
||||
) -> None:
|
||||
header = "Verify {} message".format(coin)
|
||||
text = Text(header)
|
||||
text.bold("Confirm address:")
|
||||
text.mono(*split_address(address))
|
||||
await require_confirm(ctx, text)
|
||||
|
||||
await require_confirm(
|
||||
ctx,
|
||||
paginate_text(decode_message(message), header, font=ui.MONO),
|
||||
)
|
||||
|
@ -1,10 +1,11 @@
|
||||
from trezor.crypto.curve import secp256k1
|
||||
from trezor.crypto.hashlib import sha3_256
|
||||
from trezor.messages.EthereumMessageSignature import EthereumMessageSignature
|
||||
from trezor.ui.layouts import confirm_signverify, require
|
||||
from trezor.utils import HashWriter
|
||||
|
||||
from apps.common import paths
|
||||
from apps.common.signverify import require_confirm_sign_message
|
||||
from apps.common.signverify import decode_message
|
||||
|
||||
from . import address
|
||||
from .keychain import PATTERNS_ADDRESS, with_keychain_from_path
|
||||
@ -22,7 +23,7 @@ def message_digest(message):
|
||||
@with_keychain_from_path(*PATTERNS_ADDRESS)
|
||||
async def sign_message(ctx, msg, keychain):
|
||||
await paths.validate_path(ctx, keychain, msg.address_n)
|
||||
await require_confirm_sign_message(ctx, "ETH", msg.message)
|
||||
await require(confirm_signverify(ctx, "ETH", decode_message(msg.message)))
|
||||
|
||||
node = keychain.derive(msg.address_n)
|
||||
signature = secp256k1.sign(
|
||||
|
@ -2,8 +2,9 @@ from trezor import wire
|
||||
from trezor.crypto.curve import secp256k1
|
||||
from trezor.crypto.hashlib import sha3_256
|
||||
from trezor.messages.Success import Success
|
||||
from trezor.ui.layouts import confirm_signverify, require
|
||||
|
||||
from apps.common.signverify import require_confirm_verify_message
|
||||
from apps.common.signverify import decode_message
|
||||
|
||||
from .address import address_from_bytes, bytes_from_address
|
||||
from .sign_message import message_digest
|
||||
@ -28,6 +29,8 @@ async def verify_message(ctx, msg):
|
||||
|
||||
address = address_from_bytes(address_bytes)
|
||||
|
||||
await require_confirm_verify_message(ctx, address, "ETH", msg.message)
|
||||
await require(
|
||||
confirm_signverify(ctx, "ETH", decode_message(msg.message), address=address)
|
||||
)
|
||||
|
||||
return Success(message="Message verified")
|
||||
|
@ -1,11 +1,12 @@
|
||||
from trezor.crypto.curve import ed25519
|
||||
from trezor.crypto.hashlib import sha256
|
||||
from trezor.messages.LiskMessageSignature import LiskMessageSignature
|
||||
from trezor.ui.layouts import confirm_signverify, require
|
||||
from trezor.utils import HashWriter
|
||||
|
||||
from apps.common import paths
|
||||
from apps.common.keychain import auto_keychain
|
||||
from apps.common.signverify import require_confirm_sign_message
|
||||
from apps.common.signverify import decode_message
|
||||
from apps.common.writers import write_bitcoin_varint
|
||||
|
||||
|
||||
@ -22,7 +23,7 @@ def message_digest(message):
|
||||
@auto_keychain(__name__)
|
||||
async def sign_message(ctx, msg, keychain):
|
||||
await paths.validate_path(ctx, keychain, msg.address_n)
|
||||
await require_confirm_sign_message(ctx, "Lisk", msg.message)
|
||||
await require(confirm_signverify(ctx, "Lisk", decode_message(msg.message)))
|
||||
|
||||
node = keychain.derive(msg.address_n)
|
||||
seckey = node.private_key()
|
||||
|
@ -1,8 +1,9 @@
|
||||
from trezor import wire
|
||||
from trezor.crypto.curve import ed25519
|
||||
from trezor.messages.Success import Success
|
||||
from trezor.ui.layouts import confirm_signverify, require
|
||||
|
||||
from apps.common.signverify import require_confirm_verify_message
|
||||
from apps.common.signverify import decode_message
|
||||
|
||||
from .helpers import get_address_from_public_key
|
||||
from .sign_message import message_digest
|
||||
@ -15,6 +16,8 @@ async def verify_message(ctx, msg):
|
||||
raise wire.ProcessError("Invalid signature")
|
||||
|
||||
address = get_address_from_public_key(msg.public_key)
|
||||
await require_confirm_verify_message(ctx, address, "Lisk", msg.message)
|
||||
await require(
|
||||
confirm_signverify(ctx, "Lisk", decode_message(msg.message), address=address)
|
||||
)
|
||||
|
||||
return Success(message="Message verified")
|
||||
|
@ -3,14 +3,18 @@ from micropython import const
|
||||
from trezor import loop, res, ui, utils
|
||||
|
||||
from .button import Button, ButtonCancel, ButtonConfirm, ButtonDefault
|
||||
from .confirm import CANCELLED, CONFIRMED
|
||||
from .confirm import CANCELLED, CONFIRMED, Confirm
|
||||
from .swipe import SWIPE_DOWN, SWIPE_UP, SWIPE_VERTICAL, Swipe
|
||||
from .text import TEXT_MAX_LINES, Span, Text
|
||||
|
||||
if __debug__:
|
||||
from apps.debug import confirm_signal, swipe_signal, notify_layout_change
|
||||
|
||||
if False:
|
||||
from typing import List, Tuple
|
||||
from typing import List, Tuple, Union
|
||||
|
||||
|
||||
_PAGINATED_LINE_WIDTH = const(204)
|
||||
|
||||
|
||||
def render_scrollbar(pages: int, page: int) -> None:
|
||||
@ -231,3 +235,53 @@ class PaginatedWithButtons(ui.Layout):
|
||||
|
||||
def create_tasks(self) -> Tuple[loop.Task, ...]:
|
||||
return super().create_tasks() + (confirm_signal(),)
|
||||
|
||||
|
||||
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[Confirm, 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,
|
||||
break_words=break_words,
|
||||
)
|
||||
result.content = [font, text]
|
||||
return Confirm(result)
|
||||
|
||||
else:
|
||||
pages: List[ui.Component] = []
|
||||
span.reset(
|
||||
text, 0, font, break_words=break_words, line_width=_PAGINATED_LINE_WIDTH
|
||||
)
|
||||
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=_PAGINATED_LINE_WIDTH,
|
||||
break_words=break_words,
|
||||
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()
|
||||
|
||||
pages[-1] = Confirm(pages[-1])
|
||||
return Paginated(pages)
|
||||
|
@ -11,8 +11,8 @@ from ..components.common import break_path_to_lines
|
||||
from ..components.common.confirm import is_confirmed
|
||||
from ..components.tt.button import ButtonCancel, ButtonDefault
|
||||
from ..components.tt.confirm import Confirm, HoldToConfirm
|
||||
from ..components.tt.scroll import Paginated
|
||||
from ..components.tt.text import Text
|
||||
from ..components.tt.scroll import Paginated, paginate_text
|
||||
from ..components.tt.text import Span, Text
|
||||
from ..constants.tt import (
|
||||
MONO_CHARS_PER_LINE,
|
||||
MONO_HEX_PER_LINE,
|
||||
@ -38,6 +38,7 @@ __all__ = (
|
||||
"confirm_backup",
|
||||
"confirm_path_warning",
|
||||
"confirm_sign_identity",
|
||||
"confirm_signverify",
|
||||
"show_address",
|
||||
"show_error",
|
||||
"show_pubkey",
|
||||
@ -53,6 +54,7 @@ __all__ = (
|
||||
"confirm_replacement",
|
||||
"confirm_modify_output",
|
||||
"confirm_modify_fee",
|
||||
"confirm_coinjoin",
|
||||
)
|
||||
|
||||
|
||||
@ -63,6 +65,7 @@ async def confirm_action(
|
||||
action: str = None,
|
||||
description: str = None,
|
||||
description_param: str = None,
|
||||
description_param_font: int = ui.BOLD,
|
||||
verb: Union[str, bytes, None] = Confirm.DEFAULT_CONFIRM,
|
||||
verb_cancel: Union[str, bytes, None] = Confirm.DEFAULT_CANCEL,
|
||||
hold: bool = False,
|
||||
@ -82,7 +85,9 @@ async def confirm_action(
|
||||
|
||||
if reverse and description is not None:
|
||||
text.format_parametrized(
|
||||
description, description_param if description_param is not None else ""
|
||||
description,
|
||||
description_param if description_param is not None else "",
|
||||
param_font=description_param_font,
|
||||
)
|
||||
elif action is not None:
|
||||
text.bold(action)
|
||||
@ -96,7 +101,9 @@ async def confirm_action(
|
||||
text.bold(action)
|
||||
elif description is not None:
|
||||
text.format_parametrized(
|
||||
description, description_param if description_param is not None else ""
|
||||
description,
|
||||
description_param if description_param is not None else "",
|
||||
param_font=description_param_font,
|
||||
)
|
||||
|
||||
cls = HoldToConfirm if hold else Confirm
|
||||
@ -208,11 +215,21 @@ def _split_address(address: str) -> Iterator[str]:
|
||||
return chunks(address, MONO_CHARS_PER_LINE)
|
||||
|
||||
|
||||
def _hex_lines(
|
||||
hex_data: str, lines: int = TEXT_MAX_LINES, width: int = MONO_HEX_PER_LINE
|
||||
def _truncate_hex(
|
||||
hex_data: str,
|
||||
lines: int = TEXT_MAX_LINES,
|
||||
width: int = MONO_HEX_PER_LINE,
|
||||
middle: bool = False,
|
||||
) -> Iterator[str]:
|
||||
if len(hex_data) >= width * lines:
|
||||
hex_data = hex_data[: (width * lines - 3)] + "..."
|
||||
if middle:
|
||||
hex_data = (
|
||||
hex_data[: lines * width // 2 - 1]
|
||||
+ "..."
|
||||
+ hex_data[-lines * width // 2 + 2 :]
|
||||
)
|
||||
else:
|
||||
hex_data = hex_data[: (width * lines - 3)] + "..."
|
||||
return chunks(hex_data, width)
|
||||
|
||||
|
||||
@ -457,14 +474,29 @@ async def confirm_hex(
|
||||
br_type: str,
|
||||
title: str,
|
||||
data: str,
|
||||
description: str = None,
|
||||
br_code: EnumTypeButtonRequestType = ButtonRequestType.Other,
|
||||
icon: str = ui.ICON_SEND, # TODO cleanup @ redesign
|
||||
icon_color: int = ui.GREEN, # TODO cleanup @ redesign
|
||||
width: int = MONO_HEX_PER_LINE,
|
||||
truncate_middle: bool = False,
|
||||
) -> bool:
|
||||
text = Text(title, icon, icon_color)
|
||||
text.mono(*_hex_lines(data, width=width))
|
||||
return is_confirmed(await interact(ctx, Confirm(text), br_type, br_code))
|
||||
text = Text(title, icon, icon_color, new_lines=False)
|
||||
description_lines = 0
|
||||
if description is not None:
|
||||
description_lines = Span(description, 0, ui.NORMAL).count_lines()
|
||||
text.normal(description)
|
||||
text.br()
|
||||
text.mono(
|
||||
*_truncate_hex(
|
||||
data,
|
||||
lines=TEXT_MAX_LINES - description_lines,
|
||||
width=width,
|
||||
middle=truncate_middle,
|
||||
)
|
||||
)
|
||||
content: ui.Layout = Confirm(text)
|
||||
return is_confirmed(await interact(ctx, content, br_type, br_code))
|
||||
|
||||
|
||||
async def confirm_total(
|
||||
@ -519,7 +551,7 @@ async def confirm_replacement(
|
||||
) -> bool:
|
||||
text = Text(description, ui.ICON_SEND, ui.GREEN)
|
||||
text.normal("Confirm transaction ID:")
|
||||
text.mono(*_hex_lines(txid, TEXT_MAX_LINES - 1))
|
||||
text.mono(*_truncate_hex(txid, TEXT_MAX_LINES - 1))
|
||||
return is_confirmed(
|
||||
await interact(
|
||||
ctx, Confirm(text), "confirm_replacement", ButtonRequestType.SignTx
|
||||
@ -582,6 +614,22 @@ async def confirm_modify_fee(
|
||||
)
|
||||
|
||||
|
||||
async def confirm_coinjoin(
|
||||
ctx: wire.GenericContext, fee_per_anonymity: Optional[str], total_fee: str
|
||||
) -> bool:
|
||||
text = Text("Authorize CoinJoin", ui.ICON_RECOVERY, new_lines=False)
|
||||
if fee_per_anonymity is not None:
|
||||
text.normal("Fee per anonymity set:\n")
|
||||
text.bold("{} %\n".format(fee_per_anonymity))
|
||||
text.normal("Maximum total fees:\n")
|
||||
text.bold(total_fee)
|
||||
return is_confirmed(
|
||||
await interact(
|
||||
ctx, HoldToConfirm(text), "coinjoin_final", ButtonRequestType.Other
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# TODO cleanup @ redesign
|
||||
async def confirm_sign_identity(
|
||||
ctx: wire.GenericContext, proto: str, identity: str, challenge_visual: Optional[str]
|
||||
@ -598,3 +646,33 @@ async def confirm_sign_identity(
|
||||
return is_confirmed(
|
||||
await interact(ctx, Confirm(text), "sign_identity", ButtonRequestType.Other)
|
||||
)
|
||||
|
||||
|
||||
async def confirm_signverify(
|
||||
ctx: wire.GenericContext, coin: str, message: str, address: str = None
|
||||
) -> bool:
|
||||
if address:
|
||||
header = "Verify {} message".format(coin)
|
||||
font = ui.MONO
|
||||
br_type = "verify_message"
|
||||
|
||||
text = Text(header)
|
||||
text.bold("Confirm address:")
|
||||
text.mono(*_split_address(address))
|
||||
if not is_confirmed(
|
||||
await interact(ctx, Confirm(text), br_type, ButtonRequestType.Other)
|
||||
):
|
||||
return False
|
||||
else:
|
||||
header = "Sign {} message".format(coin)
|
||||
font = ui.NORMAL
|
||||
br_type = "sign_message"
|
||||
|
||||
return is_confirmed(
|
||||
await interact(
|
||||
ctx,
|
||||
paginate_text(message, header, font=font),
|
||||
br_type,
|
||||
ButtonRequestType.Other,
|
||||
)
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user