From deb38abd37de1f86d8bd87ef8f4e458c49af04b5 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 Co-authored-by: Kristaps Kaupe --- jmclient/jmclient/__init__.py | 2 +- jmclient/jmclient/configure.py | 9 +++++++++ jmclient/jmclient/cryptoengine.py | 18 +++++++++++++++++- scripts/joinmarket-qt.py | 7 ++++--- 4 files changed, 31 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..64e1b3125 100644 --- a/jmclient/jmclient/configure.py +++ b/jmclient/jmclient/configure.py @@ -262,6 +262,12 @@ def jm_single(): # 2. You cannot change the type of a pre-existing wallet. native = true +# In joinmarket-qt, 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. +qt_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 +992,9 @@ def is_native_segwit_mode(): return False return jm_single().config.get('POLICY', 'native') != 'false' +def qt_display_ypub_zpub(): + return jm_single().config.get('POLICY', 'qt_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..a085f414e 100644 --- a/jmclient/jmclient/cryptoengine.py +++ b/jmclient/jmclient/cryptoengine.py @@ -4,7 +4,7 @@ import jmbitcoin as btc from jmbase import bintohex -from .configure import get_network, jm_single +from .configure import get_network, jm_single, qt_display_ypub_zpub #NOTE: before fidelity bonds and watchonly wallet, each of these types corresponded @@ -25,7 +25,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 +63,20 @@ 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, current_wallet_type): + if not xpub.startswith(BIP32_PUB_PREFIX) or not qt_display_ypub_zpub(): + return xpub + + # Convert xpub to ypub or zpub for display + if current_wallet_type in (TYPE_P2WPKH, TYPE_SEGWIT_WALLET_FIDELITY_BONDS): + # BIP84 format + xpub = btc.base58.encode(BIP84_PUB_PREFIX_BYTES + btc.base58.decode(xpub)[4:]) + elif current_wallet_type == TYPE_P2SH_P2WPKH: + # BIP49 format + xpub = btc.base58.encode(BIP49_PUB_PREFIX_BYTES + btc.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..9d5692e2a 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,8 @@ 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], + mainWindow.wallet_service.wallet.TYPE) elif address_type == BaseWallet.ADDRESS_TYPE_INTERNAL: heading = "INTERNAL" elif address_type == FidelityBondMixin.BIP32_TIMELOCK_ID: @@ -2339,7 +2340,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, wallet_service.wallet.TYPE)) # 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