From 9ee6669179c7eb5620086fb6e8f5ebed53b69b7e Mon Sep 17 00:00:00 2001 From: tecnovert <tecnovert@tecnovert.net> Date: Sun, 28 Jan 2024 20:16:30 +0200 Subject: [PATCH] ui: Display count of locked UTXOs on wallet page. --- basicswap/basicswap.py | 3 ++ basicswap/interface/btc.py | 1 + basicswap/interface/ltc.py | 4 +- basicswap/js_server.py | 2 +- basicswap/templates/rpc.html | 4 +- basicswap/templates/wallet.html | 8 +++- basicswap/ui/page_wallet.py | 2 + tests/basicswap/selenium/test_wallets.py | 48 +++++++++++++++++++++++- tests/basicswap/test_run.py | 3 ++ tests/basicswap/test_xmr.py | 6 ++- 10 files changed, 72 insertions(+), 9 deletions(-) diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index 1a421ad..1714c96 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -6522,6 +6522,9 @@ class BasicSwap(BaseApp): 'locked': walletinfo['locked'], } + if 'locked_utxos' in walletinfo: + rv['locked_utxos'] = walletinfo['locked_utxos'] + if coin == Coins.PART: rv['stealth_address'] = self.getCachedStealthAddressForCoin(Coins.PART) rv['anon_balance'] = walletinfo['anon_balance'] diff --git a/basicswap/interface/btc.py b/basicswap/interface/btc.py index 2b213c2..1faa1dd 100644 --- a/basicswap/interface/btc.py +++ b/basicswap/interface/btc.py @@ -300,6 +300,7 @@ class BTCInterface(CoinInterface): rv = self.rpc_wallet('getwalletinfo') rv['encrypted'] = 'unlocked_until' in rv rv['locked'] = rv.get('unlocked_until', 1) <= 0 + rv['locked_utxos'] = len(self.rpc_wallet('listlockunspent')) return rv def walletRestoreHeight(self) -> int: diff --git a/basicswap/interface/ltc.py b/basicswap/interface/ltc.py index 4576208..6dc1ddf 100644 --- a/basicswap/interface/ltc.py +++ b/basicswap/interface/ltc.py @@ -33,9 +33,7 @@ class LTCInterface(BTCInterface): return self.rpc_wallet('sendtoaddress', params) def getWalletInfo(self): - rv = self.rpc_wallet('getwalletinfo') - rv['encrypted'] = 'unlocked_until' in rv - rv['locked'] = rv.get('unlocked_until', 1) <= 0 + rv = super(LTCInterface, self).getWalletInfo() mweb_info = self.rpc_wallet_mweb('getwalletinfo') rv['mweb_balance'] = mweb_info['balance'] diff --git a/basicswap/js_server.py b/basicswap/js_server.py index eb9ed5d..6ae75eb 100644 --- a/basicswap/js_server.py +++ b/basicswap/js_server.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2023 tecnovert +# Copyright (c) 2020-2024 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. diff --git a/basicswap/templates/rpc.html b/basicswap/templates/rpc.html index 2d5c861..ead82e3 100644 --- a/basicswap/templates/rpc.html +++ b/basicswap/templates/rpc.html @@ -121,7 +121,7 @@ <div class="px-6"> <div class="flex flex-wrap justify-end"> <div class="w-full md:w-auto p-1.5 ml-2"> - <button name="" value="Apply" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none"> + <button name="apply" value="Apply" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none"> <svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"> <g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="round"> <polyline points=" 6,12 10,16 18,8 " stroke="#ffffff"></polyline> @@ -160,7 +160,7 @@ </thead> <tr class="opacity-100 text-gray-500 dark:text-gray-100"> <td class="py-3 px-6"> - <textarea class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-gray-50 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" rows="20">{{ result }}</textarea> + <textarea name="result" class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-gray-50 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" rows="20">{{ result }}</textarea> </td> </tr> </table> diff --git a/basicswap/templates/wallet.html b/basicswap/templates/wallet.html index d389d9b..b23042e 100644 --- a/basicswap/templates/wallet.html +++ b/basicswap/templates/wallet.html @@ -172,6 +172,12 @@ <td class="py-3 px-6 bold coinname-value" data-coinname="{{ w.name }}">{{ w.mweb_balance }} {{ w.ticker }} (<span class="usd-value"></span>) {% if w.mweb_pending %} <span class="inline-block py-1 px-2 rounded-full bg-green-100 text-green-500 dark:bg-gray-500 dark:text-green-500">Pending: +{{ w.mweb_pending }} {{ w.ticker }}</span>{% endif %}</td> </tr> {% endif %} {# / LTC #} + {% if w.locked_utxos %} + <tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600"> + <td class="py-3 px-6 bold">Locked Outputs:</td> + <td id='locked_utxos' class="py-3 px-6">{{ w.locked_utxos }}</td> + </tr> + {% endif %} {# / locked_utxos #} <tr class="opacity-100 text-gray-500 dark:text-gray-100 hover:bg-coolGray-200 dark:hover:bg-gray-600"> <td class="py-3 px-6 bold">Blocks:</td> <td class="py-3 px-6">{{ w.blocks }} {% if w.known_block_count %} / {{ w.known_block_count }} {% endif %}</td> @@ -637,4 +643,4 @@ document.addEventListener('DOMContentLoaded', () => { </script> </body> -</html> \ No newline at end of file +</html> diff --git a/basicswap/ui/page_wallet.py b/basicswap/ui/page_wallet.py index cfaf04e..b8f2cf3 100644 --- a/basicswap/ui/page_wallet.py +++ b/basicswap/ui/page_wallet.py @@ -41,6 +41,8 @@ def format_wallet_data(swap_client, ci, w): wf['bootstrapping'] = True if 'known_block_count' in w: wf['known_block_count'] = w['known_block_count'] + if 'locked_utxos' in w: + wf['locked_utxos'] = w['locked_utxos'] if 'balance' in w and 'unconfirmed' in w: wf['balance_all'] = float(w['balance']) + float(w['unconfirmed']) diff --git a/tests/basicswap/selenium/test_wallets.py b/tests/basicswap/selenium/test_wallets.py index 8f76e69..c113295 100644 --- a/tests/basicswap/selenium/test_wallets.py +++ b/tests/basicswap/selenium/test_wallets.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2022-2023 tecnovert +# Copyright (c) 2022-2024 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -10,7 +10,9 @@ import time from urllib.request import urlopen from selenium.webdriver.common.by import By +from selenium.webdriver.support.select import Select from util import get_driver +from basicswap.util import dumpje def test_wallets(driver): @@ -72,6 +74,50 @@ def test_wallets(driver): e = elements[0] assert ('Withdrew 10 rtPART (plain to plain) to address' in e.text) + print('Locking UTXO') + driver.get(base_url + '/rpc') + el = driver.find_element(By.NAME, 'coin_type') + for option in el.find_elements(By.TAG_NAME, 'option'): + if option.text == 'Particl': + option.click() + break + driver.find_element(By.NAME, 'cmd').send_keys('listunspent') + driver.find_element(By.NAME, 'apply').click() + time.sleep(1) + + text_value = driver.find_element(By.NAME, 'result').text + utxos = json.loads(text_value.split('\n', 1)[1]) + + lock_utxos = [{'txid': utxos[0]['txid'], 'vout': utxos[0]['vout']}] + driver.find_element(By.NAME, 'cmd').send_keys('lockunspent false "{}"'.format(dumpje(lock_utxos))) + driver.find_element(By.NAME, 'apply').click() + + print('Check for locked UTXO count') + driver.get(base_url + '/wallet/PART') + found = False + for i in range(5): + try: + el = driver.find_element(By.ID, 'locked_utxos') + found = True + break + except Exception: + continue + driver.find_element(By.ID, 'refresh').click() + time.sleep(2) + found = True + assert (found) + driver.refresh() + + print('Unlocking UTXO') + driver.get(base_url + '/rpc') + el = driver.find_element(By.NAME, 'coin_type') + for option in el.find_elements(By.TAG_NAME, 'option'): + if option.text == 'Particl': + option.click() + break + driver.find_element(By.NAME, 'cmd').send_keys('lockunspent true "{}"'.format(dumpje(lock_utxos))) + driver.find_element(By.NAME, 'apply').click() + print('Test Passed!') diff --git a/tests/basicswap/test_run.py b/tests/basicswap/test_run.py index 1557dbb..57c0a99 100644 --- a/tests/basicswap/test_run.py +++ b/tests/basicswap/test_run.py @@ -182,6 +182,9 @@ class Test(BaseTest): sx_addr = read_json_api(1800, 'wallets/part/newstealthaddress') assert (callnoderpc(0, 'getaddressinfo', [sx_addr, ])['isstealthaddress'] is True) + rv = read_json_api(1800, 'wallets/part') + assert ('locked_utxos' in rv) + def test_004_validateSwapType(self): logging.info('---------- Test validateSwapType') diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index 5a1024c..2417847 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2020-2023 tecnovert +# Copyright (c) 2020-2024 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -107,6 +107,7 @@ XMR_BASE_RPC_PORT = 21792 XMR_BASE_ZMQ_PORT = 22792 XMR_BASE_WALLET_RPC_PORT = 23792 +signal_event = threading.Event() # Set if test was cancelled test_delay_event = threading.Event() RESET_TEST = make_boolean(os.getenv('RESET_TEST', 'true')) @@ -255,6 +256,7 @@ def ltcCli(cmd, node_id=0): def signal_handler(sig, frame): logging.info('signal {} detected.'.format(sig)) + signal_event.set() test_delay_event.set() @@ -336,6 +338,8 @@ class BaseTest(unittest.TestCase): @classmethod def setUpClass(cls): + if signal_event.is_set(): + raise ValueError('Test has been cancelled.') test_delay_event.clear() random.seed(time.time())