diff --git a/basicswap/chainparams.py b/basicswap/chainparams.py index 1e30cd6..8b9385c 100644 --- a/basicswap/chainparams.py +++ b/basicswap/chainparams.py @@ -552,16 +552,26 @@ chainparams = { name_map = {} ticker_map = {} +variant_ticker_map = {} for c, params in chainparams.items(): name_map[params["name"].lower()] = c ticker_map[params["ticker"].lower()] = c +# Add coin variants, eg: LTC_MWEB, PART_ANON +for c in Coins: + if c.name.lower() in ticker_map: + continue + variant_ticker_map[c.name.lower()] = c -def getCoinIdFromTicker(ticker: str) -> str: + +def getCoinIdFromTicker(ticker: str, inc_variant: bool = False) -> str: + lc_ticker: str = ticker.lower() try: - return ticker_map[ticker.lower()] + if inc_variant and lc_ticker in variant_ticker_map: + return variant_ticker_map[lc_ticker] + return ticker_map[lc_ticker] except Exception: raise ValueError(f"Unknown coin {ticker}") diff --git a/basicswap/interface/btc.py b/basicswap/interface/btc.py index c1cbd8a..2cc2bac 100644 --- a/basicswap/interface/btc.py +++ b/basicswap/interface/btc.py @@ -449,11 +449,11 @@ class BTCInterface(Secp256k1Interface): # Wallet name is "" for some LTC and PART installs on older cores if self._rpc_wallet not in wallets and len(wallets) > 0: if "" in wallets: + # Setting wallet= in the coin .conf file should also work self._log.warning( f"Nameless {self.ticker()} wallet found." + '\nPlease set the "wallet_name" coin setting to "" or recreate the wallet' ) - # backupwallet and restorewallet with name should work. if self._rpc_wallet not in wallets: raise RuntimeError( diff --git a/basicswap/interface/ltc.py b/basicswap/interface/ltc.py index 192ecba..6450198 100644 --- a/basicswap/interface/ltc.py +++ b/basicswap/interface/ltc.py @@ -26,87 +26,6 @@ class LTCInterface(BTCInterface): wallet=self._rpc_wallet_mweb, ) - def checkWallets(self) -> int: - if self._connection_type == "electrum": - wm = self.getWalletManager() - if wm and wm.isInitialized(self.coin_type()): - return 1 - return 0 - - wallets = self.rpc("listwallets") - - if self._rpc_wallet not in wallets: - self._log.debug( - f"Wallet: {self._rpc_wallet} not active, attempting to load." - ) - try: - self.rpc( - "loadwallet", - [ - self._rpc_wallet, - ], - ) - wallets = self.rpc("listwallets") - except Exception as e: - self._log.debug(f'Error loading wallet "{self._rpc_wallet}": {e}.') - if "does not exist" in str(e) or "Path does not exist" in str(e): - try: - wallet_dirs = self.rpc("listwalletdir") - existing = [w["name"] for w in wallet_dirs.get("wallets", [])] - except Exception: - existing = [] - if len(existing) == 0: - self._log.info( - f'Creating wallet "{self._rpc_wallet}" for {self.coin_name()}.' - ) - try: - # wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors - self.rpc( - "createwallet", - [ - self._rpc_wallet, - False, - True, - "", - False, - self._use_descriptors, - ], - ) - wallets = self.rpc("listwallets") - if self.getWalletSeedID() == "Not found": - self._log.info( - f"Initializing HD seed for {self.coin_name()}." - ) - self._sc.initialiseWallet(self.coin_type()) - except Exception as create_e: - self._log.error(f"Error creating wallet: {create_e}") - - if self._rpc_wallet not in wallets and len(wallets) > 0: - self._log.warning(f"Changing {self.ticker()} wallet name.") - for wallet_name in wallets: - if wallet_name in ("mweb",): - continue - - change_watchonly_wallet: bool = ( - self._rpc_wallet_watch == self._rpc_wallet - ) - - self._rpc_wallet = wallet_name - self._log.info( - f"Switched {self.ticker()} wallet name to {self._rpc_wallet}." - ) - self.rpc_wallet = make_rpc_func( - self._rpcport, - self._rpcauth, - host=self._rpc_host, - wallet=self._rpc_wallet, - ) - if change_watchonly_wallet: - self.rpc_wallet_watch = self.rpc_wallet - break - - return len(wallets) - def getNewMwebAddress(self, use_segwit=False, label="swap_receive") -> str: if self.useBackend(): raise ValueError("MWEB addresses not supported in electrum mode") @@ -172,6 +91,9 @@ class LTCInterface(BTCInterface): continue if "address" not in u: continue + utxo_address: str = u["address"] + if any(utxo_address.startswith(prefix) for prefix in ("mweb1", "tmweb1")): + continue if "desc" in u: desc = u["desc"] if self.using_segwit: @@ -184,8 +106,8 @@ class LTCInterface(BTCInterface): else: if not desc.startswith("pkh"): continue - unspent_addr[u["address"]] = unspent_addr.get( - u["address"], 0 + unspent_addr[utxo_address] = unspent_addr.get( + utxo_address, 0 ) + self.make_int(u["amount"], r=1) return unspent_addr @@ -306,23 +228,24 @@ class LTCInterfaceMWEB(LTCInterface): def init_wallet(self, password=None): # If system is encrypted mweb wallet will be created at first unlock - self._log.info("init_wallet - {}".format(self.ticker())) + wallet_name: str = self._rpc_wallet + self._log.info(f"init_wallet - {self.ticker()}") wallets = self.rpc("listwallets") - if self._rpc_wallet not in wallets: + if wallet_name not in wallets: try: - self.rpc("loadwallet", [self._rpc_wallet]) - self._log.debug(f'Loaded existing wallet "{self._rpc_wallet}".') + self.rpc("loadwallet", [wallet_name]) + self._log.debug(f'Loaded existing wallet "{wallet_name}".') except Exception as e: if "does not exist" in str(e) or "Path does not exist" in str(e): self._log.info( - f'Creating wallet "{self._rpc_wallet}" for {self.coin_name()}.' + f'Creating wallet "{wallet_name}" for {self.coin_name()}.' ) # wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors self.rpc( "createwallet", [ - self._rpc_wallet, + wallet_name, False, True, password, @@ -333,22 +256,6 @@ class LTCInterfaceMWEB(LTCInterface): else: raise - wallets = self.rpc("listwallets") - if "mweb" not in wallets: - try: - self.rpc("loadwallet", ["mweb"]) - self._log.debug("Loaded existing MWEB wallet.") - except Exception as e: - if "does not exist" in str(e) or "Path does not exist" in str(e): - self._log.info(f"Creating MWEB wallet for {self.coin_name()}.") - # wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors, load_on_startup - self.rpc( - "createwallet", - ["mweb", False, True, password, False, False, True], - ) - else: - raise - if password is not None: # Max timeout value, ~3 years self.rpc_wallet("walletpassphrase", [password, 100000000], timeout=120) @@ -357,8 +264,8 @@ class LTCInterfaceMWEB(LTCInterface): self._sc.initialiseWallet(self.interface_type()) # Workaround to trigger mweb_spk_man->LoadMWEBKeychain() - self.rpc("unloadwallet", ["mweb"]) - self.rpc("loadwallet", ["mweb"]) + self.rpc("unloadwallet", [wallet_name]) + self.rpc("loadwallet", [wallet_name]) if password is not None: self.rpc_wallet("walletpassphrase", [password, 100000000], timeout=120) self.rpc_wallet("keypoolrefill") diff --git a/basicswap/js_server.py b/basicswap/js_server.py index b927a7f..fa83cae 100644 --- a/basicswap/js_server.py +++ b/basicswap/js_server.py @@ -290,7 +290,7 @@ def js_wallets(self, url_split, post_string, is_json): swap_client.checkSystemStatus() if len(url_split) > 3: ticker_str = url_split[3] - coin_type = getCoinIdFromTicker(ticker_str) + coin_type = getCoinIdFromTicker(ticker_str, inc_variant=True) if len(url_split) > 4: cmd = url_split[4] diff --git a/tests/basicswap/test_ltc_xmr.py b/tests/basicswap/test_ltc_xmr.py index 3bdb656..4fc38f9 100644 --- a/tests/basicswap/test_ltc_xmr.py +++ b/tests/basicswap/test_ltc_xmr.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # Copyright (c) 2021-2024 tecnovert -# Copyright (c) 2024 The Basicswap developers +# Copyright (c) 2024-2026 The Basicswap developers # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -184,6 +184,15 @@ class TestLTC(BasicSwapTest): ci0 = swap_clients[0].ci(self.test_coin_from) ci1 = swap_clients[1].ci(self.test_coin_from) + # mweb utxos before sending to mweb + num_mweb: int = 0 + utxos_0 = ci0.rpc_wallet("listunspent") + for utxo in utxos_0: + addr_info = ci0.rpc_wallet("getaddressinfo", [utxo["address"]]) + if addr_info["ismweb"] is True: + num_mweb += 1 + assert num_mweb == 1 + mweb_addr_0 = ci0.rpc_wallet("getnewaddress", ["mweb addr test 0", "mweb"]) mweb_addr_1 = ci1.rpc_wallet("getnewaddress", ["mweb addr test 1", "mweb"]) @@ -210,6 +219,19 @@ class TestLTC(BasicSwapTest): < 0.1 ) + num_mweb: int = 0 + utxos_0 = ci0.rpc_wallet( + "listunspent", + [ + 0, + ], + ) + for utxo in utxos_0: + addr_info = ci0.rpc_wallet("getaddressinfo", [utxo["address"]]) + if addr_info["ismweb"] is True: + num_mweb += 1 + assert num_mweb > 1 + try: pause_event.clear() # Stop mining ci0.rpc_wallet("sendtoaddress", [mweb_addr_1, 10.0]) @@ -237,6 +259,7 @@ class TestLTC(BasicSwapTest): for utxo in utxos: if utxo.get("address", "") == mweb_addr_1: mweb_tx = utxo + break assert mweb_tx is not None unspent_addr = ci1.getUnspentsByAddr() @@ -265,7 +288,9 @@ class TestLTC(BasicSwapTest): ltc_mweb_addr = read_json_api( TEST_HTTP_PORT + 0, "wallets/ltc_mweb/nextdepositaddr" ) + assert ltc_mweb_addr.startswith("tmweb1") ltc_mweb_addr2 = read_json_api(TEST_HTTP_PORT + 0, "wallets/ltc/newmwebaddress") + assert ltc_mweb_addr2.startswith("tmweb1") assert ( ci_mweb.rpc_wallet( diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index b79e8ba..92d5525 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -222,6 +222,7 @@ def prepare_swapclient_dir( "datadir": os.path.join(datadir, "ltc_" + str(node_id)), "bindir": cfg.LITECOIN_BINDIR, "use_segwit": True, + "wallet_name": "bsx_wallet", } if cls: