diff --git a/core/src/apps/zcash/get_address.py b/core/src/apps/zcash/get_address.py index 2e462d500f..869d10cf72 100644 --- a/core/src/apps/zcash/get_address.py +++ b/core/src/apps/zcash/get_address.py @@ -9,9 +9,9 @@ from trezor.ui.layouts import show_address from apps.bitcoin import keychain as t_keychain from apps.common import address_type from apps.common.coininfo import CoinInfo, by_name -from apps.common.paths import HARDENED, address_n_to_str +from apps.common.paths import HARDENED, PATTERN_BIP44, PathSchema, address_n_to_str -from .orchard.keychain import OrchardKeychain +from .orchard.keychain import PATTERN_ZIP32, OrchardKeychain from .unified import Typecode, encode_address if TYPE_CHECKING: @@ -19,44 +19,55 @@ if TYPE_CHECKING: from trezor.messages import ZcashGetAddress +ORCHARD = Typecode.ORCHARD +P2PKH = Typecode.P2PKH + + def encode_p2pkh(raw_address: bytes, coin: CoinInfo) -> str: return base58.encode_check(address_type.tobytes(coin.address_type) + raw_address) async def get_address(ctx: Context, msg: ZcashGetAddress) -> ZcashAddress: - if not (msg.t_address_n or msg.z_address_n): - raise wire.DataError("t-address or z-address path expected") - coin = by_name(msg.coin_name) - + address_extra = None + receivers = {} if msg.z_address_n: - receivers = {} - receivers[Typecode.ORCHARD] = await get_raw_orchard_address(ctx, coin, msg) - - if msg.t_address_n: - # this check only makes sense if paths match the respective patterns - # (i.e. t_address_n follows BIP-44 and z_address_n follows ZIP-32) - if msg.t_address_n[2] != msg.z_address_n[2]: - raise wire.DataError("Receivers use different account numbers.") - receivers[Typecode.P2PKH] = await get_raw_transparent_address( - ctx, coin, msg - ) + receivers[ORCHARD] = await get_raw_orchard_address(ctx, coin, msg) + if msg.t_address_n: + receivers[P2PKH] = await get_raw_transparent_address(ctx, coin, msg) + if tuple(receivers.keys()) == (): # no receivers + raise wire.DataError("t-address or z-address path expected") + elif tuple(receivers.keys()) == (P2PKH,): # only transparent receiver + title = address_n_to_str(msg.t_address_n) + address = encode_p2pkh(receivers[P2PKH], coin) + elif tuple(receivers.keys()) == (ORCHARD,): # only shielded receiver + title = address_n_to_str(msg.z_address_n) + address = encode_address(receivers, coin) + elif ( # transparent + shielded, unified path + PathSchema.parse(PATTERN_BIP44, coin.slip44).match(msg.t_address_n) and + PathSchema.parse(PATTERN_ZIP32, coin.slip44).match(msg.z_address_n) and + msg.t_address_n[2] == msg.z_address_n[2] + ): title = "u/{coin_type}/{account}/{receivers}".format( coin_type=msg.z_address_n[1] ^ HARDENED, account=msg.z_address_n[2] ^ HARDENED, receivers=",".join(map(str, receivers.keys())), ) - + address = encode_address(receivers, coin) + else: # transparent + shielded, incompatible paths + title = "Unified address" + address_extra = "\n".join(( + "Receivers:", + "- transparent", + address_n_to_str(msg.t_address_n), + "- Orchard", + address_n_to_str(msg.z_address_n), + )) address = encode_address(receivers, coin) - else: # has only t-address - title = address_n_to_str(msg.t_address_n) - raw_address = await get_raw_transparent_address(ctx, coin, msg) - address = encode_p2pkh(raw_address, coin) - if msg.show_display: - await show_address(ctx, address=address, address_qr=address, title=title) + await show_address(ctx, address=address, address_qr=address, title=title, address_extra=address_extra) return ZcashAddress(address=address)