ui: Change Subtract Fee to Sweep All for XMR.

2024-05-20_merge
tecnovert 11 months ago
parent e9986148d7
commit 9be4bd28fd
No known key found for this signature in database
GPG Key ID: 8ED6D8750C4E3F93
  1. 3
      basicswap/basicswap.py
  2. 15
      basicswap/interface/xmr.py
  3. 12
      basicswap/js_server.py
  4. 27
      basicswap/templates/wallet.html
  5. 20
      basicswap/ui/page_wallet.py
  6. 47
      tests/basicswap/test_xmr.py

@ -1910,6 +1910,9 @@ class BasicSwap(BaseApp):
def withdrawCoin(self, coin_type, value, addr_to, subfee: bool) -> str: def withdrawCoin(self, coin_type, value, addr_to, subfee: bool) -> str:
ci = self.ci(coin_type) ci = self.ci(coin_type)
if subfee and coin_type == Coins.XMR:
self.log.info('withdrawCoin sweep all {} to {}'.format(ci.ticker(), addr_to))
else:
self.log.info('withdrawCoin {} {} to {} {}'.format(value, ci.ticker(), addr_to, ' subfee' if subfee else '')) self.log.info('withdrawCoin {} {} to {} {}'.format(value, ci.ticker(), addr_to, ' subfee' if subfee else ''))
txid = ci.withdrawCoin(value, addr_to, subfee) txid = ci.withdrawCoin(value, addr_to, subfee)

@ -473,25 +473,24 @@ class XMRInterface(CoinInterface):
return bytes.fromhex(rv['tx_hash_list'][0]) return bytes.fromhex(rv['tx_hash_list'][0])
def withdrawCoin(self, value: int, addr_to: str, subfee: bool) -> str: def withdrawCoin(self, value: int, addr_to: str, sweepall: bool) -> str:
with self._mx_wallet: with self._mx_wallet:
value_sats = make_int(value, self.exp())
self.openWallet(self._wallet_filename) self.openWallet(self._wallet_filename)
self.rpc_wallet('refresh') self.rpc_wallet('refresh')
if subfee: if sweepall:
balance = self.rpc_wallet('get_balance') balance = self.rpc_wallet('get_balance')
diff = balance['unlocked_balance'] - value_sats if balance['balance'] != balance['unlocked_balance']:
if diff >= 0 and diff <= 10: raise ValueError('Balance must be fully confirmed to use sweep all.')
self._log.info('subfee enabled and value close to total, using sweep_all.') self._log.info('XMR withdraw sweep_all.')
self._log.debug('XMR balance: {}'.format(balance['balance']))
params = {'address': addr_to} params = {'address': addr_to}
if self._fee_priority > 0: if self._fee_priority > 0:
params['priority'] = self._fee_priority params['priority'] = self._fee_priority
rv = self.rpc_wallet('sweep_all', params) rv = self.rpc_wallet('sweep_all', params)
return rv['tx_hash_list'][0] return rv['tx_hash_list'][0]
raise ValueError('Withdraw value must be close to total to use subfee/sweep_all.')
value_sats: int = make_int(value, self.exp())
params = {'destinations': [{'amount': value_sats, 'address': addr_to}]} params = {'destinations': [{'amount': value_sats, 'address': addr_to}]}
if self._fee_priority > 0: if self._fee_priority > 0:
params['priority'] = self._fee_priority params['priority'] = self._fee_priority

@ -52,9 +52,17 @@ def getFormData(post_string: str, is_json: bool):
def withdraw_coin(swap_client, coin_type, post_string, is_json): def withdraw_coin(swap_client, coin_type, post_string, is_json):
post_data = getFormData(post_string, is_json) post_data = getFormData(post_string, is_json)
address = get_data_entry(post_data, 'address')
if coin_type == Coins.XMR:
value = None
sweepall = get_data_entry(post_data, 'sweepall')
if not isinstance(sweepall, bool):
sweepall = toBool(sweepall)
if not sweepall:
value = get_data_entry(post_data, 'value')
else:
value = get_data_entry(post_data, 'value') value = get_data_entry(post_data, 'value')
address = get_data_entry(post_data, 'address')
subfee = get_data_entry(post_data, 'subfee') subfee = get_data_entry(post_data, 'subfee')
if not isinstance(subfee, bool): if not isinstance(subfee, bool):
subfee = toBool(subfee) subfee = toBool(subfee)
@ -66,6 +74,8 @@ def withdraw_coin(swap_client, coin_type, post_string, is_json):
elif coin_type == Coins.LTC: elif coin_type == Coins.LTC:
type_from = get_data_entry_or(post_data, 'type_from', 'plain') type_from = get_data_entry_or(post_data, 'type_from', 'plain')
txid_hex = swap_client.withdrawLTC(type_from, value, address, subfee) txid_hex = swap_client.withdrawLTC(type_from, value, address, subfee)
elif coin_type == Coins.XMR:
txid_hex = swap_client.withdrawCoin(coin_type, value, address, sweepall)
else: else:
txid_hex = swap_client.withdrawCoin(coin_type, value, address, subfee) txid_hex = swap_client.withdrawCoin(coin_type, value, address, subfee)

@ -326,14 +326,21 @@
<input placeholder="{{ w.ticker }} Address" 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-400 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" type="text" name="to_{{ w.cid }}" value="{{ w.wd_address }}"> <input placeholder="{{ w.ticker }} Address" 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-400 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" type="text" name="to_{{ w.cid }}" value="{{ w.wd_address }}">
</td> </td>
<td class="py-3 px-6"> <td class="py-3 px-6">
<input placeholder="{{ w.ticker }} Amount" 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-400 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" type="text" name="amt_{{ w.cid }}" value="{{ w.wd_value }}"> <input placeholder="{{ w.ticker }} Amount" 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-400 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" type="text" id="amount" name="amt_{{ w.cid }}" value="{{ w.wd_value }}">
</td> </td>
</tr> </tr>
<tr class="opacity-100 text-gray-500 dark:text-gray-100"> <tr class="opacity-100 text-gray-500 dark:text-gray-100">
{% if w.cid == '6' %} {# XMR #}
<td class="py-3 px-6 bold">Sweep All:</td>
<td class="py-3 px-6">
<input class="hover:border-blue-500 w-5 h-5 form-check-input text-blue-600 bg-gray-50 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-1 dark:bg-gray-500 dark:border-gray-400" type="checkbox" id="sweepall" name="sweepall_{{ w.cid }}" {% if w.wd_sweepall==true %} checked=checked{% endif %}>
</td>
{% else %}
<td class="py-3 px-6 bold">Subtract Fee:</td> <td class="py-3 px-6 bold">Subtract Fee:</td>
<td class="py-3 px-6"> <td class="py-3 px-6">
<input class="hover:border-blue-500 w-5 h-5 form-check-input text-blue-600 bg-gray-50 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-1 dark:bg-gray-500 dark:border-gray-400" type="checkbox" name="subfee_{{ w.cid }}" {% if w.wd_subfee==true %} checked=checked{% endif %}> <input class="hover:border-blue-500 w-5 h-5 form-check-input text-blue-600 bg-gray-50 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-1 dark:bg-gray-500 dark:border-gray-400" type="checkbox" name="subfee_{{ w.cid }}" {% if w.wd_subfee==true %} checked=checked{% endif %}>
</td> </td>
{% endif %}
<td></td> <td></td>
</tr> </tr>
{% if w.cid == '1' %} {# PART #} {% if w.cid == '1' %} {# PART #}
@ -623,6 +630,24 @@ document.addEventListener('DOMContentLoaded', () => {
} }
calculateTotalUsdValue(); calculateTotalUsdValue();
function set_sweep_all(element) {
let input = document.getElementById('amount');
if (element.checked) {
input.disabled = true;
input.style.display = 'none';
} else {
input.disabled = false;
input.style.display = 'block';
}
}
let cb_sweepall = document.getElementById('sweepall');
if (cb_sweepall) {
set_sweep_all(cb_sweepall);
cb_sweepall.addEventListener('change', (event) => {
set_sweep_all(event.currentTarget);
})
}
}); });
</script> </script>

@ -150,6 +150,13 @@ def page_wallet(self, url_split, post_string):
err_messages.append('Reseed failed ' + str(ex)) err_messages.append('Reseed failed ' + str(ex))
swap_client.updateWalletsInfo(True, coin_id) swap_client.updateWalletsInfo(True, coin_id)
elif bytes('withdraw_' + cid, 'utf-8') in form_data: elif bytes('withdraw_' + cid, 'utf-8') in form_data:
subfee = True if bytes('subfee_' + cid, 'utf-8') in form_data else False
page_data['wd_subfee_' + cid] = subfee
sweepall = True if bytes('sweepall_' + cid, 'utf-8') in form_data else False
page_data['wd_sweepall_' + cid] = sweepall
value = None
if not sweepall:
try: try:
value = form_data[bytes('amt_' + cid, 'utf-8')][0].decode('utf-8') value = form_data[bytes('amt_' + cid, 'utf-8')][0].decode('utf-8')
page_data['wd_value_' + cid] = value page_data['wd_value_' + cid] = value
@ -161,9 +168,6 @@ def page_wallet(self, url_split, post_string):
except Exception as e: except Exception as e:
err_messages.append('Missing address') err_messages.append('Missing address')
subfee = True if bytes('subfee_' + cid, 'utf-8') in form_data else False
page_data['wd_subfee_' + cid] = subfee
if coin_id == Coins.PART: if coin_id == Coins.PART:
try: try:
type_from = form_data[bytes('withdraw_type_from_' + cid, 'utf-8')][0].decode('utf-8') type_from = form_data[bytes('withdraw_type_from_' + cid, 'utf-8')][0].decode('utf-8')
@ -179,7 +183,7 @@ def page_wallet(self, url_split, post_string):
except Exception as e: except Exception as e:
err_messages.append('Missing type') err_messages.append('Missing type')
if len(messages) == 0: if len(err_messages) == 0:
ci = swap_client.ci(coin_id) ci = swap_client.ci(coin_id)
ticker = ci.ticker() ticker = ci.ticker()
try: try:
@ -189,6 +193,12 @@ def page_wallet(self, url_split, post_string):
elif coin_id == Coins.LTC: elif coin_id == Coins.LTC:
txid = swap_client.withdrawLTC(type_from, value, address, subfee) txid = swap_client.withdrawLTC(type_from, value, address, subfee)
messages.append('Withdrew {} {} (from {}) to address {}<br/>In txid: {}'.format(value, ticker, type_from, address, txid)) messages.append('Withdrew {} {} (from {}) to address {}<br/>In txid: {}'.format(value, ticker, type_from, address, txid))
elif coin_id == Coins.XMR:
txid = swap_client.withdrawCoin(coin_id, value, address, sweepall)
if sweepall:
messages.append('Swept all {} to address {}<br/>In txid: {}'.format(ticker, address, txid))
else:
messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
else: else:
txid = swap_client.withdrawCoin(coin_id, value, address, subfee) txid = swap_client.withdrawCoin(coin_id, value, address, subfee)
messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid)) messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
@ -261,6 +271,8 @@ def page_wallet(self, url_split, post_string):
wallet_data['wd_address'] = page_data['wd_address_' + cid] wallet_data['wd_address'] = page_data['wd_address_' + cid]
if 'wd_subfee_' + cid in page_data: if 'wd_subfee_' + cid in page_data:
wallet_data['wd_subfee'] = page_data['wd_subfee_' + cid] wallet_data['wd_subfee'] = page_data['wd_subfee_' + cid]
if 'wd_sweepall_' + cid in page_data:
wallet_data['wd_sweepall'] = page_data['wd_sweepall_' + cid]
if 'utxo_value' in page_data: if 'utxo_value' in page_data:
wallet_data['utxo_value'] = page_data['utxo_value'] wallet_data['utxo_value'] = page_data['utxo_value']

@ -1151,21 +1151,10 @@ class Test(BaseTest):
js_1 = read_json_api(1801, 'wallets') js_1 = read_json_api(1801, 'wallets')
assert (float(js_1[Coins.XMR.name]['balance']) > 0.0) assert (float(js_1[Coins.XMR.name]['balance']) > 0.0)
post_json = {
'value': 0.001,
'address': address_to,
'subfee': True,
}
rv = read_json_api(1801, 'wallets/xmr/withdraw', post_json)
assert ('Withdraw value must be close to total to use subfee' in rv['error'])
post_json['value'] = 1000000000.0
rv = read_json_api(1801, 'wallets/xmr/withdraw', post_json)
assert ('Withdraw value must be close to total to use subfee' in rv['error'])
post_json = { post_json = {
'value': 1.1, 'value': 1.1,
'address': address_to, 'address': address_to,
'subfee': False, 'sweepall': False,
} }
rv = read_json_api(1801, 'wallets/xmr/withdraw', post_json) rv = read_json_api(1801, 'wallets/xmr/withdraw', post_json)
assert (len(rv['txid']) == 64) assert (len(rv['txid']) == 64)
@ -1552,28 +1541,44 @@ class Test(BaseTest):
def test_97_withdraw_all(self): def test_97_withdraw_all(self):
logging.info('---------- Test XMR withdrawal all') logging.info('---------- Test XMR withdrawal all')
wait_for_balance(test_delay_event, 'http://127.0.0.1:1800/json/wallets/xmr', 'unconfirmed', 0.0)
wallets0 = read_json_api(TEST_HTTP_PORT + 0, 'wallets')
xmr_total = float(wallets0[Coins.XMR.name]['balance'])
if xmr_total < 10.0:
address_to = read_json_api(1800, 'wallets')[Coins.XMR.name]['deposit_address']
post_json = {
'value': 10.0,
'address': address_to,
'sweepall': False,
}
json_rv = read_json_api(TEST_HTTP_PORT + 1, 'wallets/xmr/withdraw', post_json)
wait_for_balance(test_delay_event, 'http://127.0.0.1:1800/json/wallets/xmr', 'balance', 10.0)
post_json = {
'address': read_json_api(1801, 'wallets')[Coins.XMR.name]['deposit_address'],
'sweepall': True,
}
json_rv = json.loads(post_json_req('http://127.0.0.1:{}/json/wallets/xmr/withdraw'.format(TEST_HTTP_PORT + 0), post_json))
assert (len(json_rv['txid']) == 64)
try: try:
logging.info('Disabling XMR mining') logging.info('Disabling XMR mining')
pause_event.clear() pause_event.clear()
js_0 = read_json_api(1800, 'wallets') address_to = read_json_api(1800, 'wallets')[Coins.XMR.name]['deposit_address']
address_to = js_0[Coins.XMR.name]['deposit_address']
wallets1 = read_json_api(TEST_HTTP_PORT + 1, 'wallets') wallets1 = read_json_api(TEST_HTTP_PORT + 1, 'wallets')
xmr_total = float(wallets1[Coins.XMR.name]['balance']) xmr_total = float(wallets1[Coins.XMR.name]['balance'])
assert (xmr_total > 10) assert (xmr_total > 10)
post_json = { post_json = {
'value': 10,
'address': address_to, 'address': address_to,
'subfee': True, 'sweepall': True,
} }
json_rv = json.loads(post_json_req('http://127.0.0.1:{}/json/wallets/xmr/withdraw'.format(TEST_HTTP_PORT + 1), post_json)) json_rv = json.loads(post_json_req('http://127.0.0.1:{}/json/wallets/xmr/withdraw'.format(TEST_HTTP_PORT + 1), post_json))
assert (json_rv['error'] == 'Withdraw value must be close to total to use subfee/sweep_all.') assert ('Balance must be fully confirmed to use sweep all' in json_rv['error'])
post_json['value'] = xmr_total
json_rv = json.loads(post_json_req('http://127.0.0.1:{}/json/wallets/xmr/withdraw'.format(TEST_HTTP_PORT + 1), post_json))
assert (len(json_rv['txid']) == 64)
finally: finally:
logging.info('Restoring XMR mining') logging.info('Restoring XMR mining')
pause_event.set() pause_event.set()

Loading…
Cancel
Save