From 18be93533372da3558f664312612dd462b3cc27c Mon Sep 17 00:00:00 2001 From: Wukong Date: Tue, 10 May 2022 23:55:07 -0700 Subject: [PATCH] Enable importing joinmarket wallet as watch-only --- jmclient/jmclient/__init__.py | 2 +- jmclient/jmclient/configure.py | 8 ++++++++ jmclient/jmclient/cryptoengine.py | 22 +++++++++++++++++++++- scripts/joinmarket-qt.py | 6 +++--- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/jmclient/jmclient/__init__.py b/jmclient/jmclient/__init__.py index 3495c8d7d..2d862a4e1 100644 --- a/jmclient/jmclient/__init__.py +++ b/jmclient/jmclient/__init__.py @@ -22,7 +22,7 @@ StoragePasswordError, VolatileStorage) from .cryptoengine import (BTCEngine, BTC_P2PKH, BTC_P2SH_P2WPKH, BTC_P2WPKH, EngineError, TYPE_P2PKH, TYPE_P2SH_P2WPKH, TYPE_P2WPKH, detect_script_type, - is_extended_public_key) + is_extended_public_key, convert_xpub_if_needed) from .configure import (load_test_config, process_shutdown, load_program_config, jm_single, get_network, update_persist_config, validate_address, is_burn_destination, get_mchannels, diff --git a/jmclient/jmclient/configure.py b/jmclient/jmclient/configure.py index daef3b50a..676ce018b 100644 --- a/jmclient/jmclient/configure.py +++ b/jmclient/jmclient/configure.py @@ -262,6 +262,11 @@ def jm_single(): # 2. You cannot change the type of a pre-existing wallet. native = true +# Display zpub for native segwit wallet, and ypub for non-native segwit wallet. +# If set to false, the extended public key will always display in the xpub +# format. +display_ypub_zpub = true + # for dust sweeping, try merge_algorithm = gradual # for more rapid dust sweeping, try merge_algorithm = greedy # for most rapid dust sweeping, try merge_algorithm = greediest @@ -986,6 +991,9 @@ def is_native_segwit_mode(): return False return jm_single().config.get('POLICY', 'native') != 'false' +def display_ypub_zpub(): + return jm_single().config.get('POLICY', 'display_ypub_zpub') != 'false' + def process_shutdown(mode="command-line"): if mode=="command-line": from twisted.internet import reactor diff --git a/jmclient/jmclient/cryptoengine.py b/jmclient/jmclient/cryptoengine.py index 70f35f799..cc4afe70c 100644 --- a/jmclient/jmclient/cryptoengine.py +++ b/jmclient/jmclient/cryptoengine.py @@ -1,10 +1,11 @@ from collections import OrderedDict +from bitcointx import base58 import struct import jmbitcoin as btc from jmbase import bintohex -from .configure import get_network, jm_single +from .configure import get_network, jm_single, is_segwit_mode, is_native_segwit_mode, display_ypub_zpub #NOTE: before fidelity bonds and watchonly wallet, each of these types corresponded @@ -25,7 +26,9 @@ BIP32_PUB_PREFIX = "xpub" BIP49_PUB_PREFIX = "ypub" +BIP49_PUB_PREFIX_BYTES = b"\x04\x9d\x7c\xb2" BIP84_PUB_PREFIX = "zpub" +BIP84_PUB_PREFIX_BYTES = b"\x04\xb2\x47\x46" TESTNET_PUB_PREFIX = "tpub" def detect_script_type(script_str): @@ -61,6 +64,23 @@ def is_extended_public_key(key_str): BIP32_PUB_PREFIX, BIP49_PUB_PREFIX, BIP84_PUB_PREFIX, TESTNET_PUB_PREFIX]]) +def convert_xpub_if_needed(xpub): + if not xpub.startswith(BIP32_PUB_PREFIX): + return xpub + if not display_ypub_zpub(): + return xpub + + # Convert xpub to ypub or zpub for display + if is_segwit_mode(): + if is_native_segwit_mode(): + # BIP84 format + xpub = base58.encode(BIP84_PUB_PREFIX_BYTES + base58.decode(xpub)[4:]) + else: + # BIP49 format + xpub = base58.encode(BIP49_PUB_PREFIX_BYTES + base58.decode(xpub)[4:]) + return xpub + + class classproperty(object): """ from https://stackoverflow.com/a/5192374 diff --git a/scripts/joinmarket-qt.py b/scripts/joinmarket-qt.py index 416bce94d..8bc699182 100755 --- a/scripts/joinmarket-qt.py +++ b/scripts/joinmarket-qt.py @@ -73,7 +73,7 @@ parse_payjoin_setup, send_payjoin, JMBIP78ReceiverManager, \ detect_script_type, general_custom_change_warning, \ nonwallet_custom_change_warning, sweep_custom_change_warning, EngineError,\ - TYPE_P2WPKH, check_and_start_tor, is_extended_public_key + TYPE_P2WPKH, check_and_start_tor, is_extended_public_key, convert_xpub_if_needed from jmclient.wallet import BaseWallet from qtsupport import ScheduleWizard, TumbleRestartWizard, config_tips,\ @@ -1573,7 +1573,7 @@ def updateWalletInfo(self, walletinfo=None): continue if address_type == BaseWallet.ADDRESS_TYPE_EXTERNAL: - heading = "EXTERNAL " + xpubs[mixdepth][address_type] + heading = "EXTERNAL " + convert_xpub_if_needed(xpubs[mixdepth][address_type]) elif address_type == BaseWallet.ADDRESS_TYPE_INTERNAL: heading = "INTERNAL" elif address_type == FidelityBondMixin.BIP32_TIMELOCK_ID: @@ -2339,7 +2339,7 @@ def get_wallet_printout(wallet_service): account_xpub = acct.xpub if account_xpub.startswith(FBONDS_PUBKEY_PREFIX): account_xpub = account_xpub[len(FBONDS_PUBKEY_PREFIX):] - xpubs[j].append(account_xpub) + xpubs[j].append(convert_xpub_if_needed(account_xpub)) # in case the wallet is not yet synced, don't return an incorrect # 0 balance, but signal incompleteness: total_bal = walletview.get_fmt_balance() if wallet_service.synced else None