ui: auto set blank amount from using amount to and rate.

Fix btc get unspents, 'solvable'.
2024-05-20_merge
tecnovert 8 months ago
parent f64b2c1030
commit 47f7b4545e
No known key found for this signature in database
GPG Key ID: 8ED6D8750C4E3F93
  1. 28
      basicswap/basicswap.py
  2. 3
      basicswap/interface/btc.py
  3. 25
      basicswap/interface/ltc.py
  4. 9
      basicswap/templates/offer_new_1.html
  5. 1
      doc/release-notes.md
  6. 37
      tests/basicswap/selenium/test_offer.py
  7. 1
      tests/basicswap/test_ltc_xmr.py

@ -444,10 +444,10 @@ class BasicSwap(BaseApp):
if connection_type == 'rpc':
if 'rpcauth' in chain_client_settings:
rpcauth = chain_client_settings['rpcauth']
self.log.debug('Read %s rpc credentials from json settings', coin)
self.log.debug(f'Read {Coins(coin).name} rpc credentials from json settings')
elif 'rpcpassword' in chain_client_settings:
rpcauth = chain_client_settings['rpcuser'] + ':' + chain_client_settings['rpcpassword']
self.log.debug('Read %s rpc credentials from json settings', coin)
self.log.debug(f'Read {Coins(coin).name} rpc credentials from json settings')
session = scoped_session(self.session_factory)
try:
@ -698,7 +698,7 @@ class BasicSwap(BaseApp):
pidfilename += 'd'
pidfilepath = os.path.join(self.getChainDatadirPath(coin), pidfilename + '.pid')
self.log.debug('Reading %s rpc credentials from auth cookie %s', coin, authcookiepath)
self.log.debug('Reading %s rpc credentials from auth cookie %s', Coins(coin).name, authcookiepath)
# Wait for daemon to start
# Test pids to ensure authcookie is read for the correct process
datadir_pid = -1
@ -1948,7 +1948,7 @@ class BasicSwap(BaseApp):
return txid
def cacheNewAddressForCoin(self, coin_type):
self.log.debug('cacheNewAddressForCoin %s', coin_type)
self.log.debug('cacheNewAddressForCoin %s', Coins(coin_type).name)
key_str = 'receive_addr_' + self.ci(coin_type).coin_name().lower()
addr = self.getReceiveAddressForCoin(coin_type)
self.setStringKV(key_str, addr)
@ -2012,7 +2012,7 @@ class BasicSwap(BaseApp):
raise ValueError('Wallet seed doesn\'t match expected.')
def getCachedAddressForCoin(self, coin_type):
self.log.debug('getCachedAddressForCoin %s', coin_type)
self.log.debug('getCachedAddressForCoin %s', Coins(coin_type).name)
# TODO: auto refresh after used
ci = self.ci(coin_type)
@ -2032,7 +2032,7 @@ class BasicSwap(BaseApp):
return addr
def cacheNewStealthAddressForCoin(self, coin_type):
self.log.debug('cacheNewStealthAddressForCoin %s', coin_type)
self.log.debug('cacheNewStealthAddressForCoin %s', Coins(coin_type).name)
if coin_type == Coins.LTC_MWEB:
coin_type = Coins.LTC
@ -2043,7 +2043,7 @@ class BasicSwap(BaseApp):
return addr
def getCachedStealthAddressForCoin(self, coin_type):
self.log.debug('getCachedStealthAddressForCoin %s', coin_type)
self.log.debug('getCachedStealthAddressForCoin %s', Coins(coin_type).name)
if coin_type == Coins.LTC_MWEB:
coin_type = Coins.LTC
@ -2546,7 +2546,7 @@ class BasicSwap(BaseApp):
lock_value = self.callcoinrpc(coin_from, 'getblockcount') + offer.lock_value
else:
lock_value = self.getTime() + offer.lock_value
self.log.debug('Initiate %s lock_value %d %d', coin_from, offer.lock_value, lock_value)
self.log.debug('Initiate %s lock_value %d %d', ci_from.coin_name(), offer.lock_value, lock_value)
script = atomic_swap_1.buildContractScript(lock_value, secret_hash, bid.pkhash_buyer, pkhash_refund, OpCodes.OP_CHECKLOCKTIMEVERIFY)
p2sh = self.callcoinrpc(Coins.PART, 'decodescript', [script.hex()])['p2sh']
@ -3161,12 +3161,12 @@ class BasicSwap(BaseApp):
cblock_hash = block_header_at['hash']
cblock_height = block_header_at['height']
self.log.debug('Setting lock value from height of block %s %s', coin_to, cblock_hash)
self.log.debug('Setting lock value from height of block %s %s', Coins(coin_to).name, cblock_hash)
contract_lock_value = cblock_height + lock_value
else:
self.log.debug('Setting lock value from time of block %s %s', coin_from, initiate_tx_block_hash)
self.log.debug('Setting lock value from time of block %s %s', Coins(coin_from).name, initiate_tx_block_hash)
contract_lock_value = initiate_tx_block_time + lock_value
self.log.debug('participate %s lock_value %d %d', coin_to, lock_value, contract_lock_value)
self.log.debug('participate %s lock_value %d %d', Coins(coin_to).name, lock_value, contract_lock_value)
participate_script = atomic_swap_1.buildContractScript(contract_lock_value, secret_hash, pkhash_seller, pkhash_buyer_refund, OpCodes.OP_CHECKLOCKTIMEVERIFY)
return participate_script
@ -3965,7 +3965,7 @@ class BasicSwap(BaseApp):
bid.participate_tx.conf = found['depth']
index = found['index']
if bid.participate_tx is None or bid.participate_tx.txid is None:
self.log.debug('Found bid %s participate txn %s in chain %s', bid_id.hex(), found['txid'], coin_to)
self.log.debug('Found bid %s participate txn %s in chain %s', bid_id.hex(), found['txid'], Coins(coin_to).name)
self.addParticipateTxn(bid_id, bid, coin_to, found['txid'], found['index'], found['height'])
bid.setPTxState(TxStates.TX_SENT)
save_bid = True
@ -4265,7 +4265,7 @@ class BasicSwap(BaseApp):
def checkForSpends(self, coin_type, c):
# assert (self.mxDB.locked())
self.log.debug('checkForSpends %s', coin_type)
self.log.debug('checkForSpends %s', Coins(coin_type).name)
# TODO: Check for spends on watchonly txns where possible
@ -7375,7 +7375,7 @@ class BasicSwap(BaseApp):
return self._is_encrypted, self._is_locked
def lookupRates(self, coin_from, coin_to, output_array=False):
self.log.debug('lookupRates {}, {}'.format(coin_from, coin_to))
self.log.debug('lookupRates {}, {}'.format(coin_from, Coins(coin_to).name))
rate_sources = self.settings.get('rate_sources', {})
ci_from = self.ci(int(coin_from))

@ -1378,8 +1378,6 @@ class BTCInterface(CoinInterface):
for u in unspent:
if u.get('spendable', False) is False:
continue
if u.get('solveable', False) is False:
continue
if 'address' not in u:
continue
if 'desc' in u:
@ -1411,7 +1409,6 @@ class BTCInterface(CoinInterface):
def getProofOfFunds(self, amount_for, extra_commit_bytes):
# TODO: Lock unspent and use same output/s to fund bid
unspent_addr = self.getUnspentsByAddr()
sign_for_addr = None
for addr, value in unspent_addr.items():
if value >= amount_for:

@ -51,6 +51,31 @@ class LTCInterface(BTCInterface):
rv['mweb_immature'] = mweb_info['immature_balance']
return rv
def getUnspentsByAddr(self):
unspent_addr = dict()
unspent = self.rpc_wallet('listunspent')
for u in unspent:
if u.get('spendable', False) is False:
continue
if u.get('solvable', False) is False: # Filter out mweb outputs
continue
if 'address' not in u:
continue
if 'desc' in u:
desc = u['desc']
if self.using_segwit:
if self.use_p2shp2wsh():
if not desc.startswith('sh(wpkh'):
continue
else:
if not desc.startswith('wpkh'):
continue
else:
if not desc.startswith('pkh'):
continue
unspent_addr[u['address']] = unspent_addr.get(u['address'], 0) + self.make_int(u['amount'], r=1)
return unspent_addr
class LTCInterfaceMWEB(LTCInterface):
@staticmethod

@ -459,10 +459,17 @@
}
params = 'coin_from=' + coin_from + '&coin_to=' + coin_to;
if (value_changed == 'rate' || (lock_rate && value_changed == 'amt_from') || (amt_to == '' && value_changed == 'amt_from')) {
if (amt_from == '' || rate == '') {
if (rate == '' || (amt_from == '' && amt_to == '')) {
return;
} else
if (amt_from == '' && amt_to != '') {
if (value_changed == 'amt_from') { // Don't try and set a value just cleared
return;
}
params += '&rate=' + rate + '&amt_to=' + amt_to;
} else {
params += '&rate=' + rate + '&amt_from=' + amt_from;
}
} else
if (lock_rate && value_changed == 'amt_to') {
if (amt_to == '' || rate == '') {

@ -11,6 +11,7 @@
- All for all known coins.
- Comma separated list of coin tickers to show.
- basicswap-run will rewrite litecoin.conf file to add config required to run Litecoin 0.21.3 in pruned mode.
- On new offers page a blank amount-from is auto-filled from amount-to and rate.
0.12.7

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2023 tecnovert
# Copyright (c) 2023-2024 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
@ -29,8 +29,39 @@ def test_offer(driver):
select = Select(driver.find_element(By.ID, 'coin_to'))
select.select_by_visible_text('Monero')
driver.find_element(By.NAME, 'amt_from').send_keys('1')
driver.find_element(By.NAME, 'amt_to').send_keys('2')
amt_from = driver.find_element(By.NAME, 'amt_from')
amt_to = driver.find_element(By.NAME, 'amt_to')
rate = driver.find_element(By.ID, 'rate')
amt_from.send_keys('1')
amt_to.send_keys('2')
amt_from.click()
time.sleep(0.5)
rate_value = rate.get_attribute('value')
assert (float(rate_value) == 2.0)
rate.clear()
rate.send_keys('3')
amt_from.click()
time.sleep(0.5)
amt_to_value = amt_to.get_attribute('value')
assert (float(amt_to_value) == 3.0)
amt_from.clear()
amt_from.send_keys('2')
amt_to.click()
time.sleep(0.5)
amt_to_value = amt_to.get_attribute('value')
assert (float(amt_to_value) == 6.0)
amt_from.clear()
amt_to.clear()
rate.clear()
amt_to.send_keys('2')
rate.send_keys('2')
amt_to.click()
time.sleep(0.2)
amt_from_value = amt_from.get_attribute('value')
assert (float(amt_from_value) == 1.0)
driver.find_element(By.NAME, 'continue').click()
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.NAME, 'check_offer'))).click()

@ -182,6 +182,7 @@ class TestLTC(BasicSwapTest):
require_amount: int = ci1.make_int(1)
unspent_addr = ci1.getUnspentsByAddr()
assert (len(unspent_addr) > 0)
for addr, _ in unspent_addr.items():
if 'mweb1' in addr:
raise ValueError('getUnspentsByAddr should exclude mweb UTXOs.')

Loading…
Cancel
Save