diff --git a/ckcc/cli.py b/ckcc/cli.py index 224e63c..3596980 100755 --- a/ckcc/cli.py +++ b/ckcc/cli.py @@ -29,9 +29,7 @@ from ckcc.constants import STXN_FINALIZE, STXN_VISUALIZE, STXN_SIGNED from ckcc.client import ColdcardDevice, COINKITE_VID, CKCC_PID from ckcc.sigheader import FW_HEADER_SIZE, FW_HEADER_OFFSET, FW_HEADER_MAGIC from ckcc.utils import dfu_parse, calc_local_pincode, xfp2str, B2A -from ckcc.electrum import ( - cc_adjust_hww_keystore, filepath_append_cc, is_multisig_wallet, cc_adjust_multisig_hww_keystore -) +from ckcc.electrum import filepath_append_cc, convert2cc global force_serial force_serial = None @@ -1063,56 +1061,23 @@ def electrum_convert2cc(file, outfile, dry_run, key, val): try: # open file only for reading and close it immediately after it is loaded into memory with open(file, "r") as f: - wallet = json.loads(f.read()) + wallet_str = f.read() + new_wallet_str = convert2cc(wallet_str=wallet_str, dev=dev, key=key, val=val) + except json.JSONDecodeError as e: + click.echo("Failed to load wallet file {}".format(e)) + sys.exit(1) except Exception as e: - click.echo("Failed to load wallet file: {}".format(e)) + click.echo("convert2cc failed: {}".format(e)) sys.exit(1) - wallet_type = wallet["wallet_type"] - try: - if wallet_type == "standard": - new_keystore = cc_adjust_hww_keystore(wallet["keystore"], dev) - wallet["keystore"] = new_keystore - elif is_multisig_wallet(wallet): - if key is None and val is None and dev is None: - # dev is not defined, key val is not defined, we are in multisig - have to fail - click.echo("--key and --val have to be specified for multisig wallets") - sys.exit(1) - elif key is None and val is None and dev: - # user haven't provided arguments - try some automagic if coldcard is connected - # look for root fingerprint - cc_adjust_multisig_hww_keystore( - wallet, - key="root_fingerprint", - value=xfp2str(dev.master_fingerprint).lower(), - dev=dev - ) - # is it sufficient to just check xfp? - # shouldn't I try to re-create xpub (Vpub) or whatever I get as derivation path? - else: - # key val specified - cc_adjust_multisig_hww_keystore( - wallet, - key=key, - value=val, - dev=dev - ) - else: - click.echo("Unsupported wallet type: {}".format(wallet_type)) - sys.exit(1) - except RuntimeError as e: - click.echo("Failed to adjust keystore: {}".format(e)) - sys.exit(1) - - content_str = json.dumps(wallet, indent=4) if dry_run: - click.echo(content_str) + click.echo(new_wallet_str) else: if outfile is None: outfile = filepath_append_cc(file) try: with open(outfile, "w") as f: - f.write(content_str) + f.write(new_wallet_str) click.echo("New wallet file created: {}".format(outfile)) except Exception as e: click.echo("Failed to dump wallet file: {}".format(e)) diff --git a/ckcc/electrum.py b/ckcc/electrum.py index 728e814..609bfea 100644 --- a/ckcc/electrum.py +++ b/ckcc/electrum.py @@ -3,6 +3,7 @@ import re import os import copy +import json from ckcc.utils import xfp2str from ckcc.client import ColdcardDevice @@ -59,7 +60,7 @@ def multisig_find_target(keystores: dict, key: str, value: str) -> tuple: return result[0] -def filepath_append_cc(f_path): +def filepath_append_cc(f_path: str) -> str: """Append '_cc' suffix to file path. Do consider one file extension""" dirname = os.path.dirname(f_path) filename, file_ext = os.path.splitext(os.path.basename(f_path)) @@ -119,3 +120,37 @@ def cc_adjust_multisig_hww_keystore(wallet: dict, key: str, value: str, dev: Col # 3. update target keystore in wallet wallet[k] = new_keystore return wallet + + +def convert2cc(wallet_str: str, dev: ColdcardDevice = None, key: str = None, val: str = None): + wallet = json.loads(wallet_str) + wallet_type = wallet["wallet_type"] + if wallet_type == "standard": + new_keystore = cc_adjust_hww_keystore(wallet["keystore"], dev) + wallet["keystore"] = new_keystore + elif is_multisig_wallet(wallet): + if key is None and val is None and dev is None: + # dev is not defined, key val is not defined, we are in multisig - have to fail + raise RuntimeError("--key and --val have to be specified for multisig wallets") + elif key is None and val is None and dev: + # user haven't provided arguments - try some auto-magic if coldcard is connected + # look for root fingerprint + cc_adjust_multisig_hww_keystore( + wallet, + key="root_fingerprint", + value=xfp2str(dev.master_fingerprint).lower(), + dev=dev + ) + # is it sufficient to just check xfp? + # shouldn't I try to re-create xpub (Vpub) or whatever I get as derivation path? + else: + # key val specified + cc_adjust_multisig_hww_keystore( + wallet, + key=key, + value=val, + dev=dev + ) + else: + raise RuntimeError("Unsupported wallet type: {}".format(wallet_type)) + return json.dumps(wallet) diff --git a/tests/test_data/multi3of5.json b/tests/test_data/multi3of5.json index 5f1b670..3aeb7f6 100644 --- a/tests/test_data/multi3of5.json +++ b/tests/test_data/multi3of5.json @@ -67,14 +67,17 @@ "tb1qxsqg669ju7qqw653zya5a5aulcaxwq8wnfejk20xjv0sm9q9cstqky9pum" ] }, + "channels": {}, "fiat_value": {}, "frozen_coins": {}, "invoices": {}, "labels": {}, "payment_requests": {}, "prevouts_by_scripthash": {}, - "seed_version": 41, + "qt-console-history": [], + "seed_version": 43, "spent_outpoints": {}, + "stored_height": 2163195, "transactions": {}, "tx_fees": {}, "txi": {}, @@ -82,6 +85,12 @@ "use_encryption": false, "verified_tx3": {}, "wallet_type": "3of5", + "winpos-qt": [ + 167, + 152, + 840, + 400 + ], "x1/": { "derivation": "m/1'", "pw_hash_version": 1, diff --git a/tests/test_electrum_coldcardify.py b/tests/test_electrum_coldcardify.py index 1526ae9..475cf8c 100644 --- a/tests/test_electrum_coldcardify.py +++ b/tests/test_electrum_coldcardify.py @@ -123,7 +123,7 @@ def test_not_hww_wallet(): for pth in [bip32_path]: result = runner.invoke(electrum_convert2cc, [pth]) assert result.exit_code == 1 - assert result.output == "Failed to adjust keystore: Not a hardware wallet type\n" + assert result.output == "convert2cc failed: Not a hardware wallet type\n" def test_not_standard_wallet(): @@ -131,7 +131,7 @@ def test_not_standard_wallet(): for name, pth in [("2fa", a2fa_path), ("imported", import_path)]: result = runner.invoke(electrum_convert2cc, [pth]) assert result.exit_code == 1 - assert result.output == "Unsupported wallet type: {}\n".format(name) + assert result.output == "convert2cc failed: Unsupported wallet type: {}\n".format(name) def test_is_multisig_wallet():