1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-21 13:58:08 +00:00

feat(core): Show path for internal outputs in BTC signing.

This commit is contained in:
Andrew Kozlik 2023-01-11 12:40:18 +01:00 committed by Martin Milata
parent 4622aec0f1
commit d4ddc78dbb
5 changed files with 128 additions and 5 deletions

View File

@ -0,0 +1 @@
Show path for internal outputs in BTC signing.

View File

@ -1,9 +1,10 @@
from micropython import const
from typing import TYPE_CHECKING
from trezor.enums import InputScriptType
from trezor.messages import AuthorizeCoinJoin, SignMessage
from apps.common.paths import PATTERN_BIP44, PATTERN_CASA, PathSchema
from apps.common.paths import PATTERN_BIP44, PATTERN_CASA, PathSchema, unharden
from . import authorization
from .common import BITCOIN_NAMES
@ -15,7 +16,6 @@ if TYPE_CHECKING:
from trezor.protobuf import MessageType
from trezor.wire import Context
from trezor.enums import InputScriptType
from trezor.messages import (
GetAddress,
GetOwnershipId,
@ -333,3 +333,109 @@ def with_keychain(func: HandlerWithCoinInfo[MsgOut]) -> Handler[MsgIn, MsgOut]:
return await func(ctx, msg, keychain, coin)
return wrapper
class AccountType:
def __init__(
self,
account_name: str,
pattern: str,
script_type: InputScriptType,
require_segwit: bool,
require_bech32: bool,
require_taproot: bool,
):
self.account_name = account_name
self.pattern = pattern
self.script_type = script_type
self.require_segwit = require_segwit
self.require_bech32 = require_bech32
self.require_taproot = require_taproot
def get_name(
self,
coin: coininfo.CoinInfo,
address_n: Bip32Path,
script_type: InputScriptType | None,
) -> str | None:
if (
(script_type is not None and script_type != self.script_type)
or not PathSchema.parse(self.pattern, coin.slip44).match(address_n)
or (not coin.segwit and self.require_segwit)
or (not coin.bech32_prefix and self.require_bech32)
or (not coin.taproot and self.require_taproot)
):
return None
name = self.account_name
account_pos = self.pattern.find("/account'")
if account_pos >= 0:
i = self.pattern.count("/", 0, account_pos)
account_number = unharden(address_n[i]) + 1
name += f" #{account_number}"
return name
def address_n_to_name(
coin: coininfo.CoinInfo,
address_n: Bip32Path,
script_type: InputScriptType | None = None,
) -> str | None:
ACCOUNT_TYPES = (
AccountType(
"Legacy account",
PATTERN_BIP44,
InputScriptType.SPENDADDRESS,
require_segwit=True,
require_bech32=False,
require_taproot=False,
),
AccountType(
"Account",
PATTERN_BIP44,
InputScriptType.SPENDADDRESS,
require_segwit=False,
require_bech32=False,
require_taproot=False,
),
AccountType(
"Legacy SegWit account",
PATTERN_BIP49,
InputScriptType.SPENDP2SHWITNESS,
require_segwit=True,
require_bech32=False,
require_taproot=False,
),
AccountType(
"SegWit account",
PATTERN_BIP84,
InputScriptType.SPENDWITNESS,
require_segwit=True,
require_bech32=True,
require_taproot=False,
),
AccountType(
"Taproot account",
PATTERN_BIP86,
InputScriptType.SPENDTAPROOT,
require_segwit=False,
require_bech32=True,
require_taproot=True,
),
AccountType(
"Coinjoin account",
PATTERN_SLIP25_TAPROOT,
InputScriptType.SPENDTAPROOT,
require_segwit=False,
require_bech32=True,
require_taproot=True,
),
)
for account in ACCOUNT_TYPES:
name = account.get_name(coin, address_n, script_type)
if name:
return name
return None

View File

@ -6,8 +6,11 @@ from trezor.strings import format_amount
from trezor.ui import layouts
from trezor.ui.layouts import confirm_metadata
from apps.common.paths import address_n_to_str
from .. import addresses
from ..common import format_fee_rate
from ..common import CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES, format_fee_rate
from ..keychain import address_n_to_name
if TYPE_CHECKING:
from typing import Any
@ -76,11 +79,20 @@ async def confirm_output(
else:
title = "Confirm sending"
address_label = None
if output.address_n and not output.multisig:
script_type = CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES[output.script_type]
address_label = (
address_n_to_name(coin, output.address_n, script_type)
or f"address path {address_n_to_str(output.address_n)}"
)
layout = layouts.confirm_output(
ctx,
address_short,
format_coin_amount(output.amount, coin, amount_unit),
title=title,
address_label=address_label,
)
await layout

View File

@ -189,13 +189,15 @@ async def confirm_output(
amount: str,
title: str = "Confirm sending",
br_code: ButtonRequestType = ButtonRequestType.ConfirmOutput,
address_label: str | None = None,
) -> None:
label = f" ({address_label})" if address_label else ""
result = await interact(
ctx,
RustLayout(
trezorui2.confirm_text(
title=title,
data=f"Send {amount} to {address}?",
data=f"Send {amount} to {address}{label}?",
description="Confirm Output",
)
),

View File

@ -532,16 +532,18 @@ async def confirm_output(
title: str = "SENDING",
hold: bool = False,
br_code: ButtonRequestType = ButtonRequestType.ConfirmOutput,
address_label: str | None = None,
) -> None:
title = title.upper()
if title.startswith("CONFIRM "):
title = title[len("CONFIRM ") :]
description = f"To your {address_label}:" if address_label else "To:"
await confirm_value(
ctx,
title,
address,
"To:",
description,
"confirm_output",
br_code,
verb="NEXT",