diff --git a/basicswap/bin/prepare.py b/basicswap/bin/prepare.py index f5fccaf..662f4f0 100755 --- a/basicswap/bin/prepare.py +++ b/basicswap/bin/prepare.py @@ -1899,6 +1899,9 @@ def initialise_wallets( if c == Coins.PART and "particl" not in with_coins: # Running addcoin with an existing particl wallet swap_client.waitForDaemonRPC(c, with_wallet=True) + # Particl wallet must be unlocked to call getWalletKey + if WALLET_ENCRYPTION_PWD != "": + swap_client.ci(c).unlockWallet(WALLET_ENCRYPTION_PWD) continue if c == Coins.DCR: if coin_settings["manage_wallet_daemon"] is False: @@ -1930,11 +1933,28 @@ def initialise_wallets( logger.info( f'Creating wallet "{wallet_name}" for {getCoinName(c)}.' ) - - if c in (Coins.BTC, Coins.LTC, Coins.NMC, Coins.DOGE, Coins.DASH): + use_descriptors = coin_settings.get("use_descriptors", False) + if c in (Coins.DASH,): + # TODO: Remove when fixed + if WALLET_ENCRYPTION_PWD != "": + logger.warning( + "Workaround for Dash sethdseed error if wallet is encrypted." + ) # Errors with "AddHDChainSingle failed" + assert use_descriptors is False + swap_client.callcoinrpc( + c, + "createwallet", + [ + wallet_name, + False, + True, + "", + False, + use_descriptors, + ], + ) + elif c in (Coins.BTC, Coins.LTC, Coins.NMC, Coins.DOGE): # wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors - - use_descriptors = coin_settings.get("use_descriptors", False) swap_client.callcoinrpc( c, "createwallet", @@ -1964,7 +1984,9 @@ def initialise_wallets( use_descriptors, ], ) - swap_client.ci(c).unlockWallet(WALLET_ENCRYPTION_PWD) + swap_client.ci(c).unlockWallet( + WALLET_ENCRYPTION_PWD, check_seed=False + ) else: swap_client.callcoinrpc( c, @@ -1995,9 +2017,6 @@ def initialise_wallets( swap_client.callcoinrpc( Coins.PART, "extkeyimportmaster", [particl_wallet_mnemonic] ) - # Particl wallet must be unlocked to call getWalletKey - if WALLET_ENCRYPTION_PWD != "": - swap_client.ci(c).unlockWallet(WALLET_ENCRYPTION_PWD) for coin_name in with_coins: c = swap_client.getCoinIdFromName(coin_name) @@ -2010,7 +2029,9 @@ def initialise_wallets( swap_client.initialiseWallet(c, raise_errors=True) except Exception as e: coins_failed_to_initialise.append((c, e)) - if WALLET_ENCRYPTION_PWD != "" and c not in coins_to_create_wallets_for: + if WALLET_ENCRYPTION_PWD != "" and ( + c not in coins_to_create_wallets_for or c in (Coins.DASH,) + ): # TODO: Remove DASH workaround try: swap_client.ci(c).changeWalletPassword("", WALLET_ENCRYPTION_PWD) except Exception as e: # noqa: F841 @@ -2026,12 +2047,12 @@ def initialise_wallets( print("") for pair in coins_failed_to_initialise: c, e = pair - if c in (Coins.PIVX,): + if c in (Coins.PIVX, Coins.BCH): print( f"NOTE - Unable to initialise wallet for {getCoinName(c)}. To complete setup click 'Reseed Wallet' from the ui page once chain is synced." ) else: - print(f"WARNING - Failed to initialise wallet for {getCoinName(c)}: {e}") + raise ValueError(f"Failed to initialise wallet for {getCoinName(c)}: {e}") if "decred" in with_coins and WALLET_ENCRYPTION_PWD != "": print( diff --git a/basicswap/interface/btc.py b/basicswap/interface/btc.py index b8656c8..d65702b 100644 --- a/basicswap/interface/btc.py +++ b/basicswap/interface/btc.py @@ -1986,7 +1986,7 @@ class BTCInterface(Secp256k1Interface): return self.rpc_wallet("encryptwallet", [new_password]) self.rpc_wallet("walletpassphrasechange", [old_password, new_password]) - def unlockWallet(self, password: str): + def unlockWallet(self, password: str, check_seed: bool = True) -> None: if password == "": return self._log.info(f"unlockWallet - {self.ticker()}") @@ -2007,7 +2007,8 @@ class BTCInterface(Secp256k1Interface): # Max timeout value, ~3 years self.rpc_wallet("walletpassphrase", [password, 100000000]) - self._sc.checkWalletSeed(self.coin_type()) + if check_seed: + self._sc.checkWalletSeed(self.coin_type()) def lockWallet(self): self._log.info(f"lockWallet - {self.ticker()}") diff --git a/basicswap/interface/dash.py b/basicswap/interface/dash.py index 7215763..5904c17 100644 --- a/basicswap/interface/dash.py +++ b/basicswap/interface/dash.py @@ -111,17 +111,11 @@ class DASHInterface(BTCInterface): return None - def unlockWallet(self, password: str): - super().unlockWallet(password) + def unlockWallet(self, password: str, check_seed: bool = True) -> None: + super().unlockWallet(password, check_seed) if self._wallet_v20_compatible: # Store password for initialiseWallet self._wallet_passphrase = password - if not self._have_checked_seed: - try: - self._sc.checkWalletSeed(self.coin_type()) - except Exception as ex: - # dumphdinfo can fail if the wallet is not initialised - self._log.debug(f"DASH checkWalletSeed failed: {ex}.") def lockWallet(self): super().lockWallet() diff --git a/basicswap/interface/dcr/dcr.py b/basicswap/interface/dcr/dcr.py index 83a7306..c59c547 100644 --- a/basicswap/interface/dcr/dcr.py +++ b/basicswap/interface/dcr/dcr.py @@ -368,14 +368,15 @@ class DCRInterface(Secp256k1Interface): # Clear initial password self._sc.editSettings(self.coin_name().lower(), {"wallet_pwd": ""}) - def unlockWallet(self, password: str): + def unlockWallet(self, password: str, check_seed: bool = True) -> None: if password == "": return self._log.info("unlockWallet - {}".format(self.ticker())) # Max timeout value, ~3 years self.rpc_wallet("walletpassphrase", [password, 100000000]) - self._sc.checkWalletSeed(self.coin_type()) + if check_seed: + self._sc.checkWalletSeed(self.coin_type()) def lockWallet(self): self._log.info("lockWallet - {}".format(self.ticker())) diff --git a/basicswap/interface/ltc.py b/basicswap/interface/ltc.py index b5e6eee..aa640b4 100644 --- a/basicswap/interface/ltc.py +++ b/basicswap/interface/ltc.py @@ -146,7 +146,7 @@ class LTCInterfaceMWEB(LTCInterface): self.rpc_wallet("walletpassphrase", [password, 100000000]) self.rpc_wallet("keypoolrefill") - def unlockWallet(self, password: str): + def unlockWallet(self, password: str, check_seed: bool = True) -> None: if password == "": return self._log.info("unlockWallet - {}".format(self.ticker())) @@ -156,5 +156,5 @@ class LTCInterfaceMWEB(LTCInterface): else: # Max timeout value, ~3 years self.rpc_wallet("walletpassphrase", [password, 100000000]) - - self._sc.checkWalletSeed(self.coin_type()) + if check_seed: + self._sc.checkWalletSeed(self.coin_type()) diff --git a/basicswap/interface/xmr.py b/basicswap/interface/xmr.py index e60ef3b..32bb01b 100644 --- a/basicswap/interface/xmr.py +++ b/basicswap/interface/xmr.py @@ -744,11 +744,11 @@ class XMRInterface(CoinInterface): self._wallet_password = orig_password raise e - def unlockWallet(self, password: str) -> None: + def unlockWallet(self, password: str, check_seed: bool = True) -> None: self._log.info("unlockWallet - {}".format(self.ticker())) self._wallet_password = password - if not self._have_checked_seed: + if check_seed and not self._have_checked_seed: self._sc.checkWalletSeed(self.coin_type()) def lockWallet(self) -> None: diff --git a/tests/basicswap/extended/test_dash.py b/tests/basicswap/extended/test_dash.py index 9db754b..cb90523 100644 --- a/tests/basicswap/extended/test_dash.py +++ b/tests/basicswap/extended/test_dash.py @@ -758,20 +758,39 @@ class Test(unittest.TestCase): def test_09_initialise_wallet(self): logging.info("---------- Test DASH initialiseWallet") - self.swap_clients[0].initialiseWallet(Coins.DASH, raise_errors=True) - assert self.swap_clients[0].checkWalletSeed(Coins.DASH) is True + test_seed = "8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b" + ci = self.swap_clients[0].ci(Coins.DASH) + test_wif: str = ci.encodeKey(bytes.fromhex(test_seed)) + new_wallet_name: str = random.randbytes(10).hex() + # wallet_name, wallet_name, blank, passphrase, avoid_reuse, descriptors + ci.rpc("createwallet", [new_wallet_name, False, True, "", False, False]) + ci.rpc("sethdseed", [True, test_wif], wallet_override=new_wallet_name) - addr = dashRpc('getnewaddress "hd wallet test"') - assert addr == "ybzWYJbZEhZai8kiKkTtPFKTuDNwhpiwac" + test_pwd: str = "test_pwd" + ci.rpc( + "encryptwallet", + [ + test_pwd, + ], + wallet_override=new_wallet_name, + ) - logging.info("Test that getcoinseed returns a mnemonic for Dash") - mnemonic = read_json_api(1800, "getcoinseed", {"coin": "DASH"})["mnemonic"] - new_wallet_name = random.randbytes(10).hex() - dashRpc(f'createwallet "{new_wallet_name}"') - dashRpc(f'upgradetohd "{mnemonic}"', wallet=new_wallet_name) - addr_test = dashRpc("getnewaddress", wallet=new_wallet_name) - dashRpc("unloadwallet", wallet=new_wallet_name) - assert addr_test == addr + addr = ci.rpc("getnewaddress", wallet_override=new_wallet_name) + # sethdseed keys are not == upgradetohd, was "ybzWYJbZEhZai8kiKkTtPFKTuDNwhpiwac" + assert addr == "yb8DSec26MLqtuj48iELnhnDCSBBbpWJ9p" + + new_wallet_name += "_encrypted" + ci.rpc("createwallet", [new_wallet_name, False, True, test_pwd, False, False]) + ci.rpc("walletpassphrase", [test_pwd, 1000], wallet_override=new_wallet_name) + # sethdseed fails on encrypted wallets! + try: + ci.rpc("sethdseed", [True, test_wif], wallet_override=new_wallet_name) + except Exception as e: + assert "AddHDChainSingle failed" in str(e) + else: + raise ValueError( + "sethdseed on encrypted wallets is fixed! Remove workaround in prepare.py." + ) def test_10_prefunded_itx(self): logging.info("---------- Test prefunded itx offer") diff --git a/tests/basicswap/test_btc_xmr.py b/tests/basicswap/test_btc_xmr.py index a79c5a8..c314f56 100644 --- a/tests/basicswap/test_btc_xmr.py +++ b/tests/basicswap/test_btc_xmr.py @@ -1187,12 +1187,12 @@ class BasicSwapTest(TestFunctions): logging.warning("Skipping test") return - test_wif = ( + test_wif: str = ( self.swap_clients[0] .ci(self.test_coin_from) .encodeKey(bytes.fromhex(test_seed)) ) - new_wallet_name = random.randbytes(10).hex() + new_wallet_name: str = random.randbytes(10).hex() # wallet_name, wallet_name, blank, passphrase, avoid_reuse, descriptors self.callnoderpc( "createwallet", [new_wallet_name, False, True, "", False, False]