mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-05 18:29:26 +00:00
ui: Split wallet page
This commit is contained in:
parent
1c09a8b79e
commit
f90a96d9ca
11 changed files with 344 additions and 76 deletions
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2019-2021 tecnovert
|
# Copyright (c) 2019-2022 tecnovert
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
@ -326,6 +326,8 @@ class BasicSwap(BaseApp):
|
||||||
else:
|
else:
|
||||||
self.thread_pool.shutdown()
|
self.thread_pool.shutdown()
|
||||||
|
|
||||||
|
self.zmqContext.destroy()
|
||||||
|
|
||||||
close_all_sessions()
|
close_all_sessions()
|
||||||
self.engine.dispose()
|
self.engine.dispose()
|
||||||
|
|
||||||
|
@ -5260,7 +5262,10 @@ class BasicSwap(BaseApp):
|
||||||
# Requires? self.mxDB.acquire()
|
# Requires? self.mxDB.acquire()
|
||||||
try:
|
try:
|
||||||
session = scoped_session(self.session_factory)
|
session = scoped_session(self.session_factory)
|
||||||
inner_str = 'SELECT coin_id, MAX(created_at) as max_created_at FROM wallets GROUP BY coin_id'
|
where_str = ''
|
||||||
|
if opts is not None and 'coin_id' in opts:
|
||||||
|
where_str = 'WHERE coin_id = {}'.format(opts['coin_id'])
|
||||||
|
inner_str = f'SELECT coin_id, MAX(created_at) as max_created_at FROM wallets {where_str} GROUP BY coin_id'
|
||||||
query_str = 'SELECT a.coin_id, wallet_data, created_at FROM wallets a, ({}) b WHERE a.coin_id = b.coin_id AND a.created_at = b.max_created_at'.format(inner_str)
|
query_str = 'SELECT a.coin_id, wallet_data, created_at FROM wallets a, ({}) b WHERE a.coin_id = b.coin_id AND a.created_at = b.max_created_at'.format(inner_str)
|
||||||
|
|
||||||
q = session.execute(query_str)
|
q = session.execute(query_str)
|
||||||
|
@ -5285,6 +5290,9 @@ class BasicSwap(BaseApp):
|
||||||
session.close()
|
session.close()
|
||||||
session.remove()
|
session.remove()
|
||||||
|
|
||||||
|
if opts is not None and 'coin_id' in opts:
|
||||||
|
return rv
|
||||||
|
|
||||||
for c in Coins:
|
for c in Coins:
|
||||||
if c not in chainparams:
|
if c not in chainparams:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2019-2021 tecnovert
|
# Copyright (c) 2019-2022 tecnovert
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
@ -207,6 +207,20 @@ chainparams = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ticker_map = {}
|
||||||
|
|
||||||
|
|
||||||
|
for c, params in chainparams.items():
|
||||||
|
ticker_map[params['ticker'].lower()] = c
|
||||||
|
|
||||||
|
|
||||||
|
def getCoinIdFromTicker(ticker):
|
||||||
|
try:
|
||||||
|
return ticker_map[ticker.lower()]
|
||||||
|
except Exception:
|
||||||
|
raise ValueError('Unknown coin')
|
||||||
|
|
||||||
|
|
||||||
class CoinInterface:
|
class CoinInterface:
|
||||||
def __init__(self, network):
|
def __init__(self, network):
|
||||||
self.setDefaults()
|
self.setDefaults()
|
||||||
|
@ -235,6 +249,10 @@ class CoinInterface:
|
||||||
ticker = 'rt' + ticker
|
ticker = 'rt' + ticker
|
||||||
return ticker
|
return ticker
|
||||||
|
|
||||||
|
def ticker_mainnet(self):
|
||||||
|
ticker = chainparams[self.coin_type()]['ticker']
|
||||||
|
return ticker
|
||||||
|
|
||||||
def min_amount(self):
|
def min_amount(self):
|
||||||
return chainparams[self.coin_type()][self._network]['min_amount']
|
return chainparams[self.coin_type()][self._network]['min_amount']
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2019-2021 tecnovert
|
# Copyright (c) 2019-2022 tecnovert
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
@ -17,11 +17,13 @@ from jinja2 import Environment, PackageLoader
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from .util import (
|
from .util import (
|
||||||
dumpj,
|
dumpj,
|
||||||
|
ensure,
|
||||||
format_timestamp,
|
format_timestamp,
|
||||||
)
|
)
|
||||||
from .chainparams import (
|
from .chainparams import (
|
||||||
chainparams,
|
|
||||||
Coins,
|
Coins,
|
||||||
|
chainparams,
|
||||||
|
getCoinIdFromTicker,
|
||||||
)
|
)
|
||||||
from .basicswap_util import (
|
from .basicswap_util import (
|
||||||
SwapTypes,
|
SwapTypes,
|
||||||
|
@ -370,16 +372,12 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ci = swap_client.ci(k)
|
ci = swap_client.ci(k)
|
||||||
fee_rate, fee_src = swap_client.getFeeRateForCoin(k)
|
|
||||||
est_fee = swap_client.estimateWithdrawFee(k, fee_rate)
|
|
||||||
cid = str(int(k))
|
cid = str(int(k))
|
||||||
wf = {
|
wf = {
|
||||||
'name': w['name'],
|
'name': w['name'],
|
||||||
'version': w['version'],
|
'version': w['version'],
|
||||||
|
'ticker': ci.ticker_mainnet(),
|
||||||
'cid': cid,
|
'cid': cid,
|
||||||
'fee_rate': ci.format_amount(int(fee_rate * ci.COIN())),
|
|
||||||
'fee_rate_src': fee_src,
|
|
||||||
'est_fee': 'Unknown' if est_fee is None else ci.format_amount(int(est_fee * ci.COIN())),
|
|
||||||
'balance': w['balance'],
|
'balance': w['balance'],
|
||||||
'blocks': w['blocks'],
|
'blocks': w['blocks'],
|
||||||
'synced': w['synced'],
|
'synced': w['synced'],
|
||||||
|
@ -402,21 +400,6 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
if float(w['anon_pending']) > 0.0:
|
if float(w['anon_pending']) > 0.0:
|
||||||
wf['anon_pending'] = w['anon_pending']
|
wf['anon_pending'] = w['anon_pending']
|
||||||
|
|
||||||
elif k == Coins.XMR:
|
|
||||||
wf['main_address'] = w.get('main_address', 'Refresh necessary')
|
|
||||||
|
|
||||||
if 'wd_type_from_' + cid in page_data:
|
|
||||||
wf['wd_type_from'] = page_data['wd_type_from_' + cid]
|
|
||||||
if 'wd_type_to_' + cid in page_data:
|
|
||||||
wf['wd_type_to'] = page_data['wd_type_to_' + cid]
|
|
||||||
|
|
||||||
if 'wd_value_' + cid in page_data:
|
|
||||||
wf['wd_value'] = page_data['wd_value_' + cid]
|
|
||||||
if 'wd_address_' + cid in page_data:
|
|
||||||
wf['wd_address'] = page_data['wd_address_' + cid]
|
|
||||||
if 'wd_subfee_' + cid in page_data:
|
|
||||||
wf['wd_subfee'] = page_data['wd_subfee_' + cid]
|
|
||||||
|
|
||||||
wallets_formatted.append(wf)
|
wallets_formatted.append(wf)
|
||||||
|
|
||||||
template = env.get_template('wallets.html')
|
template = env.get_template('wallets.html')
|
||||||
|
@ -428,6 +411,146 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
form_id=os.urandom(8).hex(),
|
form_id=os.urandom(8).hex(),
|
||||||
), 'UTF-8')
|
), 'UTF-8')
|
||||||
|
|
||||||
|
def page_wallet(self, url_split, post_string):
|
||||||
|
ensure(len(url_split) > 2, 'Wallet not specified')
|
||||||
|
wallet_ticker = url_split[2]
|
||||||
|
swap_client = self.server.swap_client
|
||||||
|
|
||||||
|
coin_id = getCoinIdFromTicker(wallet_ticker)
|
||||||
|
|
||||||
|
page_data = {}
|
||||||
|
messages = []
|
||||||
|
form_data = self.checkForm(post_string, 'settings', messages)
|
||||||
|
if form_data:
|
||||||
|
cid = str(int(coin_id))
|
||||||
|
|
||||||
|
if bytes('newaddr_' + cid, 'utf-8') in form_data:
|
||||||
|
swap_client.cacheNewAddressForCoin(coin_id)
|
||||||
|
elif bytes('reseed_' + cid, 'utf-8') in form_data:
|
||||||
|
try:
|
||||||
|
swap_client.reseedWallet(coin_id)
|
||||||
|
messages.append('Reseed complete ' + str(coin_id))
|
||||||
|
except Exception as ex:
|
||||||
|
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:
|
||||||
|
messages.append('Error: 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:
|
||||||
|
messages.append('Error: 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')
|
||||||
|
type_to = form_data[bytes('withdraw_type_to_' + cid, 'utf-8')][0].decode('utf-8')
|
||||||
|
page_data['wd_type_from_' + cid] = type_from
|
||||||
|
page_data['wd_type_to_' + cid] = type_to
|
||||||
|
except Exception as e:
|
||||||
|
messages.append('Error: Missing type')
|
||||||
|
|
||||||
|
if len(messages) == 0:
|
||||||
|
ci = swap_client.ci(coin_id)
|
||||||
|
ticker = ci.ticker()
|
||||||
|
if coin_id == Coins.PART:
|
||||||
|
try:
|
||||||
|
txid = swap_client.withdrawParticl(type_from, type_to, value, address, subfee)
|
||||||
|
messages.append('Withdrew {} {} ({} to {}) to address {}<br/>In txid: {}'.format(value, ticker, type_from, type_to, address, txid))
|
||||||
|
except Exception as e:
|
||||||
|
messages.append('Error: {}'.format(str(e)))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
txid = swap_client.withdrawCoin(coin_id, value, address, subfee)
|
||||||
|
messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
|
||||||
|
except Exception as e:
|
||||||
|
messages.append('Error: {}'.format(str(e)))
|
||||||
|
swap_client.updateWalletsInfo(True, coin_id)
|
||||||
|
|
||||||
|
swap_client.updateWalletsInfo()
|
||||||
|
wallets = swap_client.getCachedWalletsInfo({'coin_id': coin_id})
|
||||||
|
for k in wallets.keys():
|
||||||
|
w = wallets[k]
|
||||||
|
if 'error' in w:
|
||||||
|
wallet_data = {
|
||||||
|
'cid': str(int(k)),
|
||||||
|
'error': w['error']
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
|
||||||
|
if 'balance' not in w:
|
||||||
|
wallet_data = {
|
||||||
|
'name': w['name'],
|
||||||
|
'havedata': False,
|
||||||
|
'updating': w['updating'],
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
|
||||||
|
ci = swap_client.ci(k)
|
||||||
|
fee_rate, fee_src = swap_client.getFeeRateForCoin(k)
|
||||||
|
est_fee = swap_client.estimateWithdrawFee(k, fee_rate)
|
||||||
|
cid = str(int(k))
|
||||||
|
wallet_data = {
|
||||||
|
'name': w['name'],
|
||||||
|
'version': w['version'],
|
||||||
|
'ticker': ci.ticker_mainnet(),
|
||||||
|
'cid': cid,
|
||||||
|
'fee_rate': ci.format_amount(int(fee_rate * ci.COIN())),
|
||||||
|
'fee_rate_src': fee_src,
|
||||||
|
'est_fee': 'Unknown' if est_fee is None else ci.format_amount(int(est_fee * ci.COIN())),
|
||||||
|
'balance': w['balance'],
|
||||||
|
'blocks': w['blocks'],
|
||||||
|
'synced': w['synced'],
|
||||||
|
'deposit_address': w['deposit_address'],
|
||||||
|
'expected_seed': w['expected_seed'],
|
||||||
|
'balance_all': float(w['balance']) + float(w['unconfirmed']),
|
||||||
|
'updating': w['updating'],
|
||||||
|
'lastupdated': format_timestamp(w['lastupdated']),
|
||||||
|
'havedata': True,
|
||||||
|
}
|
||||||
|
if float(w['unconfirmed']) > 0.0:
|
||||||
|
wallet_data['unconfirmed'] = w['unconfirmed']
|
||||||
|
|
||||||
|
if k == Coins.PART:
|
||||||
|
wallet_data['stealth_address'] = w['stealth_address']
|
||||||
|
wallet_data['blind_balance'] = w['blind_balance']
|
||||||
|
if float(w['blind_unconfirmed']) > 0.0:
|
||||||
|
wallet_data['blind_unconfirmed'] = w['blind_unconfirmed']
|
||||||
|
wallet_data['anon_balance'] = w['anon_balance']
|
||||||
|
if float(w['anon_pending']) > 0.0:
|
||||||
|
wallet_data['anon_pending'] = w['anon_pending']
|
||||||
|
|
||||||
|
elif k == Coins.XMR:
|
||||||
|
wallet_data['main_address'] = w.get('main_address', 'Refresh necessary')
|
||||||
|
|
||||||
|
if 'wd_type_from_' + cid in page_data:
|
||||||
|
wallet_data['wd_type_from'] = page_data['wd_type_from_' + cid]
|
||||||
|
if 'wd_type_to_' + cid in page_data:
|
||||||
|
wallet_data['wd_type_to'] = page_data['wd_type_to_' + cid]
|
||||||
|
|
||||||
|
if 'wd_value_' + cid in page_data:
|
||||||
|
wallet_data['wd_value'] = page_data['wd_value_' + cid]
|
||||||
|
if 'wd_address_' + cid in page_data:
|
||||||
|
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]
|
||||||
|
|
||||||
|
template = env.get_template('wallet.html')
|
||||||
|
return bytes(template.render(
|
||||||
|
title=self.server.title,
|
||||||
|
h2=self.server.title,
|
||||||
|
messages=messages,
|
||||||
|
w=wallet_data,
|
||||||
|
form_id=os.urandom(8).hex(),
|
||||||
|
), 'UTF-8')
|
||||||
|
|
||||||
def page_settings(self, url_split, post_string):
|
def page_settings(self, url_split, post_string):
|
||||||
swap_client = self.server.swap_client
|
swap_client = self.server.swap_client
|
||||||
|
|
||||||
|
@ -764,7 +887,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
), 'UTF-8')
|
), 'UTF-8')
|
||||||
|
|
||||||
def page_offer(self, url_split, post_string):
|
def page_offer(self, url_split, post_string):
|
||||||
assert(len(url_split) > 2), 'Offer ID not specified'
|
ensure(len(url_split) > 2, 'Offer ID not specified')
|
||||||
try:
|
try:
|
||||||
offer_id = bytes.fromhex(url_split[2])
|
offer_id = bytes.fromhex(url_split[2])
|
||||||
assert(len(offer_id) == 28)
|
assert(len(offer_id) == 28)
|
||||||
|
@ -772,7 +895,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
raise ValueError('Bad offer ID')
|
raise ValueError('Bad offer ID')
|
||||||
swap_client = self.server.swap_client
|
swap_client = self.server.swap_client
|
||||||
offer, xmr_offer = swap_client.getXmrOffer(offer_id)
|
offer, xmr_offer = swap_client.getXmrOffer(offer_id)
|
||||||
assert(offer), 'Unknown offer ID'
|
ensure(offer, 'Unknown offer ID')
|
||||||
|
|
||||||
extend_data = { # Defaults
|
extend_data = { # Defaults
|
||||||
'nb_validmins': 10,
|
'nb_validmins': 10,
|
||||||
|
@ -928,11 +1051,11 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
|
|
||||||
if have_data_entry(form_data, 'sort_by'):
|
if have_data_entry(form_data, 'sort_by'):
|
||||||
sort_by = get_data_entry(form_data, 'sort_by')
|
sort_by = get_data_entry(form_data, 'sort_by')
|
||||||
assert(sort_by in ['created_at', 'rate']), 'Invalid sort by'
|
ensure(sort_by in ['created_at', 'rate'], 'Invalid sort by')
|
||||||
filters['sort_by'] = sort_by
|
filters['sort_by'] = sort_by
|
||||||
if have_data_entry(form_data, 'sort_dir'):
|
if have_data_entry(form_data, 'sort_dir'):
|
||||||
sort_dir = get_data_entry(form_data, 'sort_dir')
|
sort_dir = get_data_entry(form_data, 'sort_dir')
|
||||||
assert(sort_dir in ['asc', 'desc']), 'Invalid sort dir'
|
ensure(sort_dir in ['asc', 'desc'], 'Invalid sort dir')
|
||||||
filters['sort_dir'] = sort_dir
|
filters['sort_dir'] = sort_dir
|
||||||
|
|
||||||
if form_data and have_data_entry(form_data, 'pageback'):
|
if form_data and have_data_entry(form_data, 'pageback'):
|
||||||
|
@ -973,7 +1096,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
), 'UTF-8')
|
), 'UTF-8')
|
||||||
|
|
||||||
def page_bid(self, url_split, post_string):
|
def page_bid(self, url_split, post_string):
|
||||||
assert(len(url_split) > 2), 'Bid ID not specified'
|
ensure(len(url_split) > 2, 'Bid ID not specified')
|
||||||
try:
|
try:
|
||||||
bid_id = bytes.fromhex(url_split[2])
|
bid_id = bytes.fromhex(url_split[2])
|
||||||
assert(len(bid_id) == 28)
|
assert(len(bid_id) == 28)
|
||||||
|
@ -1023,7 +1146,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
show_lock_transfers = True
|
show_lock_transfers = True
|
||||||
|
|
||||||
bid, xmr_swap, offer, xmr_offer, events = swap_client.getXmrBidAndOffer(bid_id)
|
bid, xmr_swap, offer, xmr_offer, events = swap_client.getXmrBidAndOffer(bid_id)
|
||||||
assert(bid), 'Unknown bid ID'
|
ensure(bid, 'Unknown bid ID')
|
||||||
|
|
||||||
data = describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, events, edit_bid, show_txns, view_tx_ind, show_lock_transfers=show_lock_transfers)
|
data = describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, events, edit_bid, show_txns, view_tx_ind, show_lock_transfers=show_lock_transfers)
|
||||||
|
|
||||||
|
@ -1077,11 +1200,11 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
if form_data and have_data_entry(form_data, 'applyfilters'):
|
if form_data and have_data_entry(form_data, 'applyfilters'):
|
||||||
if have_data_entry(form_data, 'sort_by'):
|
if have_data_entry(form_data, 'sort_by'):
|
||||||
sort_by = get_data_entry(form_data, 'sort_by')
|
sort_by = get_data_entry(form_data, 'sort_by')
|
||||||
assert(sort_by in ['created_at', ]), 'Invalid sort by'
|
ensure(sort_by in ['created_at', ], 'Invalid sort by')
|
||||||
filters['sort_by'] = sort_by
|
filters['sort_by'] = sort_by
|
||||||
if have_data_entry(form_data, 'sort_dir'):
|
if have_data_entry(form_data, 'sort_dir'):
|
||||||
sort_dir = get_data_entry(form_data, 'sort_dir')
|
sort_dir = get_data_entry(form_data, 'sort_dir')
|
||||||
assert(sort_dir in ['asc', 'desc']), 'Invalid sort dir'
|
ensure(sort_dir in ['asc', 'desc'], 'Invalid sort dir')
|
||||||
filters['sort_dir'] = sort_dir
|
filters['sort_dir'] = sort_dir
|
||||||
|
|
||||||
if form_data and have_data_entry(form_data, 'pageback'):
|
if form_data and have_data_entry(form_data, 'pageback'):
|
||||||
|
@ -1144,7 +1267,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
edit_address_id = int(form_data[b'edit_address_id'][0].decode('utf-8'))
|
edit_address_id = int(form_data[b'edit_address_id'][0].decode('utf-8'))
|
||||||
edit_addr = form_data[b'edit_address'][0].decode('utf-8')
|
edit_addr = form_data[b'edit_address'][0].decode('utf-8')
|
||||||
active_ind = int(form_data[b'active_ind'][0].decode('utf-8'))
|
active_ind = int(form_data[b'active_ind'][0].decode('utf-8'))
|
||||||
assert(active_ind == 0 or active_ind == 1), 'Invalid sort by'
|
ensure(active_ind in (0, 1), 'Invalid sort by')
|
||||||
addressnote = '' if b'addressnote' not in form_data else form_data[b'addressnote'][0].decode('utf-8')
|
addressnote = '' if b'addressnote' not in form_data else form_data[b'addressnote'][0].decode('utf-8')
|
||||||
if not validateTextInput(addressnote, 'Address note', messages, max_length=30):
|
if not validateTextInput(addressnote, 'Address note', messages, max_length=30):
|
||||||
listaddresses = False
|
listaddresses = False
|
||||||
|
@ -1196,7 +1319,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
), 'UTF-8')
|
), 'UTF-8')
|
||||||
|
|
||||||
def page_identity(self, url_split, post_string):
|
def page_identity(self, url_split, post_string):
|
||||||
assert(len(url_split) > 2), 'Address not specified'
|
ensure(len(url_split) > 2, 'Address not specified')
|
||||||
identity_address = url_split[2]
|
identity_address = url_split[2]
|
||||||
swap_client = self.server.swap_client
|
swap_client = self.server.swap_client
|
||||||
|
|
||||||
|
@ -1333,6 +1456,8 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
return self.page_active(url_split, post_string)
|
return self.page_active(url_split, post_string)
|
||||||
if url_split[1] == 'wallets':
|
if url_split[1] == 'wallets':
|
||||||
return self.page_wallets(url_split, post_string)
|
return self.page_wallets(url_split, post_string)
|
||||||
|
if url_split[1] == 'wallet':
|
||||||
|
return self.page_wallet(url_split, post_string)
|
||||||
if url_split[1] == 'settings':
|
if url_split[1] == 'settings':
|
||||||
return self.page_settings(url_split, post_string)
|
return self.page_settings(url_split, post_string)
|
||||||
if url_split[1] == 'rpc':
|
if url_split[1] == 'rpc':
|
||||||
|
|
82
basicswap/templates/wallet.html
Normal file
82
basicswap/templates/wallet.html
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
{% include 'header.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
<p><a id="refresh" href="/wallet/{{ w.ticker }}">refresh</a></p>
|
||||||
|
<p><a id="back" href="/wallets">back</a></p>
|
||||||
|
|
||||||
|
<h3>{{ w.name }} Wallet</h3>
|
||||||
|
{% if refresh %}
|
||||||
|
<p>Page Refresh: {{ refresh }} seconds</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for m in messages %}
|
||||||
|
<p>{{ m }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
|
||||||
|
|
||||||
|
{% if w.updating %}
|
||||||
|
<h5>Updating</h5>
|
||||||
|
{% endif %}
|
||||||
|
{% if w.havedata %}
|
||||||
|
{% if w.error %}
|
||||||
|
<p>Error: {{ w.error }}</p>
|
||||||
|
{% else %}
|
||||||
|
<table>
|
||||||
|
|
||||||
|
<tr><td>Last updated:</td><td>{{ w.lastupdated }}</td></tr>
|
||||||
|
<tr><td>Version:</td><td>{{ w.version }}</td></tr>
|
||||||
|
<tr><td>Balance:</td><td>{{ w.balance }}</td>{% if w.unconfirmed %}<td>Unconfirmed:</td><td>{{ w.unconfirmed }}</td>{% endif %}</tr>
|
||||||
|
|
||||||
|
{% if w.cid == '1' %}
|
||||||
|
<tr><td>Blind Balance:</td><td>{{ w.blind_balance }}</td>{% if w.blind_unconfirmed %}<td>Blind Unconfirmed:</td><td>{{ w.blind_unconfirmed }}</td>{% endif %}</tr>
|
||||||
|
<tr><td>Anon Balance:</td><td>{{ w.anon_balance }}</td>{% if w.anon_pending %}<td>Anon Pending:</td><td>{{ w.anon_pending }}</td>{% endif %}</tr>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
<tr><td>Blocks:</td><td>{{ w.blocks }}</td></tr>
|
||||||
|
<tr><td>Synced:</td><td>{{ w.synced }}</td></tr>
|
||||||
|
<tr><td>Expected Seed:</td><td>{{ w.expected_seed }}</td>{% if w.expected_seed != true %}<td><input type="submit" name="reseed_{{ w.cid }}" value="Reseed wallet" onclick="return confirmReseed();"></td>{% endif %}</tr>
|
||||||
|
{% if w.cid == '1' %}
|
||||||
|
<tr><td>Stealth Address</td><td colspan=2>{{ w.stealth_address }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
{% if w.cid == '6' %}
|
||||||
|
<tr><td>Main Address</td><td colspan=2>{{ w.main_address }}</td></tr>
|
||||||
|
<tr><td><input type="submit" name="newaddr_{{ w.cid }}" value="New Subaddress"></td><td colspan=2>{{ w.deposit_address }}</td></tr>
|
||||||
|
{% else %}
|
||||||
|
<tr><td><input type="submit" name="newaddr_{{ w.cid }}" value="New Deposit Address"></td><td colspan=2>{{ w.deposit_address }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
<tr><td><input type="submit" name="withdraw_{{ w.cid }}" value="Withdraw" onclick="return confirmWithdrawal();"></td><td>Amount: <input type="text" name="amt_{{ w.cid }}" value="{{ w.wd_value }}"></td><td>Address: <input type="text" name="to_{{ w.cid }}" value="{{ w.wd_address }}"></td><td>Subtract fee: <input type="checkbox" name="subfee_{{ w.cid }}" {% if w.wd_subfee==true %} checked="true"{% endif %}></td></tr>
|
||||||
|
{% if w.cid == '1' %}
|
||||||
|
<tr><td>Type From, To</td><td>
|
||||||
|
<select name="withdraw_type_from_{{ w.cid }}">
|
||||||
|
<option value="plain"{% if w.wd_type_from == 'plain' %} selected{% endif %}>Plain</option>
|
||||||
|
<option value="blind"{% if w.wd_type_from == 'blind' %} selected{% endif %}>Blind</option>
|
||||||
|
<option value="anon"{% if w.wd_type_from == 'anon' %} selected{% endif %}>Anon</option>
|
||||||
|
</select>
|
||||||
|
<select name="withdraw_type_to_{{ w.cid }}">
|
||||||
|
<option value="plain"{% if w.wd_type_to == 'plain' %} selected{% endif %}>Plain</option>
|
||||||
|
<option value="blind"{% if w.wd_type_to == 'blind' %} selected{% endif %}>Blind</option>
|
||||||
|
<option value="anon"{% if w.wd_type_to == 'anon' %} selected{% endif %}>Anon</option>
|
||||||
|
</select></td></tr>
|
||||||
|
{% endif %}
|
||||||
|
<tr><td>Fee Rate:</td><td>{{ w.fee_rate }}</td><td>Est Fee:</td><td>{{ w.est_fee }}</td></tr>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %} <!-- havedata -->
|
||||||
|
|
||||||
|
<input type="hidden" name="formid" value="{{ form_id }}">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p><a href="/">home</a></p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function confirmReseed() {
|
||||||
|
return confirm("Are you sure?\nBackup your wallet before and after.\nWon't detect used keys.\nShould only be used for new wallets.");
|
||||||
|
}
|
||||||
|
function confirmWithdrawal() {
|
||||||
|
return confirm("Are you sure?");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body></html>
|
|
@ -1,6 +1,6 @@
|
||||||
{% include 'header.html' %}
|
{% include 'header.html' %}
|
||||||
|
|
||||||
<p><a href="/wallets">refresh</a></p>
|
<p><a id="refresh" href="/wallets">refresh</a></p>
|
||||||
|
|
||||||
<h3>Wallets</h3>
|
<h3>Wallets</h3>
|
||||||
{% if refresh %}
|
{% if refresh %}
|
||||||
|
@ -35,31 +35,8 @@
|
||||||
|
|
||||||
<tr><td>Blocks:</td><td>{{ w.blocks }}</td></tr>
|
<tr><td>Blocks:</td><td>{{ w.blocks }}</td></tr>
|
||||||
<tr><td>Synced:</td><td>{{ w.synced }}</td></tr>
|
<tr><td>Synced:</td><td>{{ w.synced }}</td></tr>
|
||||||
<tr><td>Expected Seed:</td><td>{{ w.expected_seed }}</td>{% if w.expected_seed != true %}<td><input type="submit" name="reseed_{{ w.cid }}" value="Reseed wallet" onclick="return confirmReseed();"></td>{% endif %}</tr>
|
<tr><td>Expected Seed:</td><td>{{ w.expected_seed }}</td></tr>
|
||||||
{% if w.cid == '1' %}
|
<tr><td><a href="/wallet/{{ w.ticker }}">Manage</a></td></tr>
|
||||||
<tr><td>Stealth Address</td><td colspan=2>{{ w.stealth_address }}</td></tr>
|
|
||||||
{% endif %}
|
|
||||||
{% if w.cid == '6' %}
|
|
||||||
<tr><td>Main Address</td><td colspan=2>{{ w.main_address }}</td></tr>
|
|
||||||
<tr><td><input type="submit" name="newaddr_{{ w.cid }}" value="New Subaddress"></td><td colspan=2>{{ w.deposit_address }}</td></tr>
|
|
||||||
{% else %}
|
|
||||||
<tr><td><input type="submit" name="newaddr_{{ w.cid }}" value="New Deposit Address"></td><td colspan=2>{{ w.deposit_address }}</td></tr>
|
|
||||||
{% endif %}
|
|
||||||
<tr><td><input type="submit" name="withdraw_{{ w.cid }}" value="Withdraw" onclick="return confirmWithdrawal();"></td><td>Amount: <input type="text" name="amt_{{ w.cid }}" value="{{ w.wd_value }}"></td><td>Address: <input type="text" name="to_{{ w.cid }}" value="{{ w.wd_address }}"></td><td>Subtract fee: <input type="checkbox" name="subfee_{{ w.cid }}" {% if w.wd_subfee==true %} checked="true"{% endif %}></td></tr>
|
|
||||||
{% if w.cid == '1' %}
|
|
||||||
<tr><td>Type From, To</td><td>
|
|
||||||
<select name="withdraw_type_from_{{ w.cid }}">
|
|
||||||
<option value="plain"{% if w.wd_type_from == 'plain' %} selected{% endif %}>Plain</option>
|
|
||||||
<option value="blind"{% if w.wd_type_from == 'blind' %} selected{% endif %}>Blind</option>
|
|
||||||
<option value="anon"{% if w.wd_type_from == 'anon' %} selected{% endif %}>Anon</option>
|
|
||||||
</select>
|
|
||||||
<select name="withdraw_type_to_{{ w.cid }}">
|
|
||||||
<option value="plain"{% if w.wd_type_to == 'plain' %} selected{% endif %}>Plain</option>
|
|
||||||
<option value="blind"{% if w.wd_type_to == 'blind' %} selected{% endif %}>Blind</option>
|
|
||||||
<option value="anon"{% if w.wd_type_to == 'anon' %} selected{% endif %}>Anon</option>
|
|
||||||
</select></td></tr>
|
|
||||||
{% endif %}
|
|
||||||
<tr><td>Fee Rate:</td><td>{{ w.fee_rate }}</td><td>Est Fee:</td><td>{{ w.est_fee }}</td></tr>
|
|
||||||
</table>
|
</table>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %} <!-- havedata -->
|
{% endif %} <!-- havedata -->
|
||||||
|
|
|
@ -12,6 +12,7 @@ import mmap
|
||||||
import stat
|
import stat
|
||||||
import gnupg
|
import gnupg
|
||||||
import signal
|
import signal
|
||||||
|
import socket
|
||||||
import hashlib
|
import hashlib
|
||||||
import tarfile
|
import tarfile
|
||||||
import zipfile
|
import zipfile
|
||||||
|
@ -114,7 +115,12 @@ def downloadFile(url, path):
|
||||||
opener = urllib.request.build_opener()
|
opener = urllib.request.build_opener()
|
||||||
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
|
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
|
||||||
urllib.request.install_opener(opener)
|
urllib.request.install_opener(opener)
|
||||||
|
|
||||||
|
# Set one second timeout for urlretrieve connections
|
||||||
|
old_timeout = socket.getdefaulttimeout()
|
||||||
|
socket.setdefaulttimeout(1)
|
||||||
urlretrieve(url, path, make_reporthook())
|
urlretrieve(url, path, make_reporthook())
|
||||||
|
socket.setdefaulttimeout(old_timeout)
|
||||||
|
|
||||||
|
|
||||||
def extractCore(coin, version_pair, settings, bin_dir, release_path):
|
def extractCore(coin, version_pair, settings, bin_dir, release_path):
|
||||||
|
|
|
@ -158,7 +158,7 @@ def runClient(fp, data_dir, chain):
|
||||||
swap_client.start()
|
swap_client.start()
|
||||||
|
|
||||||
if 'htmlhost' in settings:
|
if 'htmlhost' in settings:
|
||||||
swap_client.log.info('Starting server at %s:%d.' % (settings['htmlhost'], settings['htmlport']))
|
swap_client.log.info('Starting server at http://%s:%d.' % (settings['htmlhost'], settings['htmlport']))
|
||||||
allow_cors = settings['allowcors'] if 'allowcors' in settings else cfg.DEFAULT_ALLOW_CORS
|
allow_cors = settings['allowcors'] if 'allowcors' in settings else cfg.DEFAULT_ALLOW_CORS
|
||||||
tS1 = HttpThread(fp, settings['htmlhost'], settings['htmlport'], allow_cors, swap_client)
|
tS1 = HttpThread(fp, settings['htmlhost'], settings['htmlport'], allow_cors, swap_client)
|
||||||
threads.append(tS1)
|
threads.append(tS1)
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
import urllib
|
||||||
import signal
|
import signal
|
||||||
import logging
|
import logging
|
||||||
import urllib
|
|
||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
|
|
||||||
from basicswap.rpc import callrpc
|
from basicswap.rpc import callrpc
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2020-2021 tecnovert
|
# Copyright (c) 2020-2022 tecnovert
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
@ -149,18 +149,18 @@ class XmrTestBase(unittest.TestCase):
|
||||||
|
|
||||||
waitForServer(self.delay_event, 12701)
|
waitForServer(self.delay_event, 12701)
|
||||||
|
|
||||||
def waitForDepositAddress():
|
def waitForMainAddress():
|
||||||
for i in range(20):
|
for i in range(20):
|
||||||
if self.delay_event.is_set():
|
if self.delay_event.is_set():
|
||||||
raise ValueError('Test stopped.')
|
raise ValueError('Test stopped.')
|
||||||
try:
|
try:
|
||||||
wallets = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').read())
|
wallets = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').read())
|
||||||
return wallets['6']['deposit_address']
|
return wallets['6']['main_address']
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Waiting for deposit address {}'.format(str(e)))
|
print('Waiting for main address {}'.format(str(e)))
|
||||||
self.delay_event.wait(1)
|
self.delay_event.wait(1)
|
||||||
raise ValueError('waitForDepositAddress timedout')
|
raise ValueError('waitForMainAddress timedout')
|
||||||
xmr_addr1 = waitForDepositAddress()
|
xmr_addr1 = waitForMainAddress()
|
||||||
|
|
||||||
num_blocks = 100
|
num_blocks = 100
|
||||||
|
|
||||||
|
@ -178,11 +178,15 @@ class XmrTestBase(unittest.TestCase):
|
||||||
for i in range(60):
|
for i in range(60):
|
||||||
if self.delay_event.is_set():
|
if self.delay_event.is_set():
|
||||||
raise ValueError('Test stopped.')
|
raise ValueError('Test stopped.')
|
||||||
wallets = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').read())
|
try:
|
||||||
particl_blocks = wallets['1']['blocks']
|
wallets = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').read())
|
||||||
print('particl_blocks', particl_blocks)
|
particl_blocks = wallets['1']['blocks']
|
||||||
if particl_blocks >= num_blocks:
|
print('particl_blocks', particl_blocks)
|
||||||
break
|
if particl_blocks >= num_blocks:
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print('Error reading wallets', str(e))
|
||||||
|
|
||||||
self.delay_event.wait(1)
|
self.delay_event.wait(1)
|
||||||
assert(particl_blocks >= num_blocks)
|
assert(particl_blocks >= num_blocks)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2021 tecnovert
|
# Copyright (c) 2021-2022 tecnovert
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ class Test(unittest.TestCase):
|
||||||
|
|
||||||
wallets = json.loads(urlopen('http://127.0.0.1:{}/json/wallets'.format(UI_PORT + 1)).read())
|
wallets = json.loads(urlopen('http://127.0.0.1:{}/json/wallets'.format(UI_PORT + 1)).read())
|
||||||
|
|
||||||
self.xmr_addr = wallets['6']['deposit_address']
|
self.xmr_addr = wallets['6']['main_address']
|
||||||
num_blocks = 100
|
num_blocks = 100
|
||||||
if callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')['count'] < num_blocks:
|
if callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')['count'] < num_blocks:
|
||||||
logging.info('Mining {} Monero blocks to {}.'.format(num_blocks, self.xmr_addr))
|
logging.info('Mining {} Monero blocks to {}.'.format(num_blocks, self.xmr_addr))
|
||||||
|
|
48
tests/basicswap/selenium/test_wallets.py
Normal file
48
tests/basicswap/selenium/test_wallets.py
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2022 tecnovert
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
"""
|
||||||
|
cd /tmp
|
||||||
|
wget -4 https://chromedriver.storage.googleapis.com/96.0.4664.45/chromedriver_linux64.zip
|
||||||
|
7z x chromedriver_linux64.zip
|
||||||
|
sudo mv chromedriver /opt/chromedriver96
|
||||||
|
|
||||||
|
|
||||||
|
python tests/basicswap/extended/test_xmr_persistent.py
|
||||||
|
|
||||||
|
python tests/basicswap/selenium/test_wallets.py
|
||||||
|
|
||||||
|
html = driver.page_source
|
||||||
|
print('html', html)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
from selenium import webdriver
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.chrome.service import Service
|
||||||
|
|
||||||
|
|
||||||
|
def test_html():
|
||||||
|
base_url = 'http://localhost:12701'
|
||||||
|
|
||||||
|
driver = webdriver.Chrome(service=Service('/opt/chromedriver96'))
|
||||||
|
url = base_url + '/wallets'
|
||||||
|
driver.get(url)
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
driver.refresh()
|
||||||
|
|
||||||
|
driver.find_element(By.ID, "refresh").click()
|
||||||
|
time.sleep(1)
|
||||||
|
driver.refresh()
|
||||||
|
|
||||||
|
driver.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_html()
|
Loading…
Reference in a new issue