diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py
index f80cf47..0497003 100644
--- a/basicswap/basicswap.py
+++ b/basicswap/basicswap.py
@@ -1910,7 +1910,10 @@ class BasicSwap(BaseApp):
def withdrawCoin(self, coin_type, value, addr_to, subfee: bool) -> str:
ci = self.ci(coin_type)
- self.log.info('withdrawCoin {} {} to {} {}'.format(value, ci.ticker(), addr_to, ' subfee' if subfee else ''))
+ 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 ''))
txid = ci.withdrawCoin(value, addr_to, subfee)
self.log.debug('In txn: {}'.format(txid))
diff --git a/basicswap/interface/xmr.py b/basicswap/interface/xmr.py
index 265da44..2bd255b 100644
--- a/basicswap/interface/xmr.py
+++ b/basicswap/interface/xmr.py
@@ -473,25 +473,24 @@ class XMRInterface(CoinInterface):
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:
- value_sats = make_int(value, self.exp())
-
self.openWallet(self._wallet_filename)
self.rpc_wallet('refresh')
- if subfee:
+ if sweepall:
balance = self.rpc_wallet('get_balance')
- diff = balance['unlocked_balance'] - value_sats
- if diff >= 0 and diff <= 10:
- self._log.info('subfee enabled and value close to total, using sweep_all.')
- params = {'address': addr_to}
- if self._fee_priority > 0:
- params['priority'] = self._fee_priority
- rv = self.rpc_wallet('sweep_all', params)
- return rv['tx_hash_list'][0]
- raise ValueError('Withdraw value must be close to total to use subfee/sweep_all.')
+ if balance['balance'] != balance['unlocked_balance']:
+ raise ValueError('Balance must be fully confirmed to use sweep all.')
+ self._log.info('XMR withdraw sweep_all.')
+ self._log.debug('XMR balance: {}'.format(balance['balance']))
+ params = {'address': addr_to}
+ if self._fee_priority > 0:
+ params['priority'] = self._fee_priority
+ rv = self.rpc_wallet('sweep_all', params)
+ return rv['tx_hash_list'][0]
+ value_sats: int = make_int(value, self.exp())
params = {'destinations': [{'amount': value_sats, 'address': addr_to}]}
if self._fee_priority > 0:
params['priority'] = self._fee_priority
diff --git a/basicswap/js_server.py b/basicswap/js_server.py
index 6ae75eb..d137fe3 100644
--- a/basicswap/js_server.py
+++ b/basicswap/js_server.py
@@ -52,12 +52,20 @@ def getFormData(post_string: str, is_json: bool):
def withdraw_coin(swap_client, coin_type, post_string, is_json):
post_data = getFormData(post_string, is_json)
-
- value = get_data_entry(post_data, 'value')
address = get_data_entry(post_data, 'address')
- subfee = get_data_entry(post_data, 'subfee')
- if not isinstance(subfee, bool):
- subfee = toBool(subfee)
+
+ 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')
+ subfee = get_data_entry(post_data, 'subfee')
+ if not isinstance(subfee, bool):
+ subfee = toBool(subfee)
if coin_type == Coins.PART:
type_from = get_data_entry_or(post_data, 'type_from', 'plain')
@@ -66,6 +74,8 @@ def withdraw_coin(swap_client, coin_type, post_string, is_json):
elif coin_type == Coins.LTC:
type_from = get_data_entry_or(post_data, 'type_from', 'plain')
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:
txid_hex = swap_client.withdrawCoin(coin_type, value, address, subfee)
diff --git a/basicswap/templates/wallet.html b/basicswap/templates/wallet.html
index d807f14..5fa2c7f 100644
--- a/basicswap/templates/wallet.html
+++ b/basicswap/templates/wallet.html
@@ -326,14 +326,21 @@
-
+
|
+ {% if w.cid == '6' %} {# XMR #}
+ | Sweep All: |
+
+
+ |
+ {% else %}
Subtract Fee: |
|
+ {% endif %}
|
{% if w.cid == '1' %} {# PART #}
@@ -623,6 +630,24 @@ document.addEventListener('DOMContentLoaded', () => {
}
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);
+ })
+ }
});
diff --git a/basicswap/ui/page_wallet.py b/basicswap/ui/page_wallet.py
index 861f1c4..17ed173 100644
--- a/basicswap/ui/page_wallet.py
+++ b/basicswap/ui/page_wallet.py
@@ -150,20 +150,24 @@ def page_wallet(self, url_split, post_string):
err_messages.append('Reseed failed ' + str(ex))
swap_client.updateWalletsInfo(True, coin_id)
elif bytes('withdraw_' + cid, 'utf-8') in form_data:
- try:
- value = form_data[bytes('amt_' + cid, 'utf-8')][0].decode('utf-8')
- page_data['wd_value_' + cid] = value
- except Exception as e:
- err_messages.append('Missing value')
+ 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:
+ value = form_data[bytes('amt_' + cid, 'utf-8')][0].decode('utf-8')
+ page_data['wd_value_' + cid] = value
+ except Exception as e:
+ err_messages.append('Missing value')
try:
address = form_data[bytes('to_' + cid, 'utf-8')][0].decode('utf-8')
page_data['wd_address_' + cid] = address
except Exception as e:
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:
try:
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:
err_messages.append('Missing type')
- if len(messages) == 0:
+ if len(err_messages) == 0:
ci = swap_client.ci(coin_id)
ticker = ci.ticker()
try:
@@ -189,6 +193,12 @@ def page_wallet(self, url_split, post_string):
elif coin_id == Coins.LTC:
txid = swap_client.withdrawLTC(type_from, value, address, subfee)
messages.append('Withdrew {} {} (from {}) to address {}
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 {}
In txid: {}'.format(ticker, address, txid))
+ else:
+ messages.append('Withdrew {} {} to address {}
In txid: {}'.format(value, ticker, address, txid))
else:
txid = swap_client.withdrawCoin(coin_id, value, address, subfee)
messages.append('Withdrew {} {} to address {}
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]
if 'wd_subfee_' + cid in page_data:
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:
wallet_data['utxo_value'] = page_data['utxo_value']
diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py
index 2417847..1518657 100644
--- a/tests/basicswap/test_xmr.py
+++ b/tests/basicswap/test_xmr.py
@@ -1151,21 +1151,10 @@ class Test(BaseTest):
js_1 = read_json_api(1801, 'wallets')
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 = {
'value': 1.1,
'address': address_to,
- 'subfee': False,
+ 'sweepall': False,
}
rv = read_json_api(1801, 'wallets/xmr/withdraw', post_json)
assert (len(rv['txid']) == 64)
@@ -1552,28 +1541,44 @@ class Test(BaseTest):
def test_97_withdraw_all(self):
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:
logging.info('Disabling XMR mining')
pause_event.clear()
- js_0 = read_json_api(1800, 'wallets')
- address_to = js_0[Coins.XMR.name]['deposit_address']
+ address_to = read_json_api(1800, 'wallets')[Coins.XMR.name]['deposit_address']
wallets1 = read_json_api(TEST_HTTP_PORT + 1, 'wallets')
xmr_total = float(wallets1[Coins.XMR.name]['balance'])
assert (xmr_total > 10)
post_json = {
- 'value': 10,
'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))
- assert (json_rv['error'] == 'Withdraw value must be close to total to use subfee/sweep_all.')
-
- 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)
+ assert ('Balance must be fully confirmed to use sweep all' in json_rv['error'])
finally:
logging.info('Restoring XMR mining')
pause_event.set()