ui: Expose min bid amount.

2024-05-20_merge
tecnovert 2 years ago
parent 1c4f208d27
commit 1ee2db137b
No known key found for this signature in database
GPG Key ID: 8ED6D8750C4E3F93
  1. 5
      basicswap/http_server.py
  2. 10
      basicswap/static/css/simple/style.css
  3. 27
      basicswap/static/js/new_offer.js
  4. 3
      basicswap/templates/header.html
  5. 4
      basicswap/templates/offer.html
  6. 5
      basicswap/templates/offer_confirm.html
  7. 8
      basicswap/templates/offer_new_1.html
  8. 5
      basicswap/templates/offer_new_2.html
  9. 41
      basicswap/ui/page_offers.py
  10. 4
      doc/install.md

@ -704,6 +704,11 @@ class HttpHandler(BaseHTTPRequestHandler):
with open(os.path.join(static_path, 'css', filename), 'rb') as fp:
self.putHeaders(status_code, 'text/css; charset=utf-8')
return fp.read()
elif len(url_split) > 3 and url_split[2] == 'js':
filename = os.path.join(*url_split[3:])
with open(os.path.join(static_path, 'js', filename), 'rb') as fp:
self.putHeaders(status_code, 'application/javascript')
return fp.read()
else:
self.putHeaders(status_code, 'text/html')
return self.page_404(url_split)

@ -22,3 +22,13 @@
margin: 0;
width:calc(33.33% - 25px);
}
.error
{
background:#ff5b5b;
}
.error_msg
{
color:red;
}

@ -0,0 +1,27 @@
window.addEventListener('DOMContentLoaded', (event) => {
let err_msgs = document.querySelectorAll('p.error_msg');
for (let i=0; i < err_msgs.length; i++) {
err_msg = err_msgs[i].innerText
if (err_msg.indexOf('coin_to') >= 0 || err_msg.indexOf('Coin To') >= 0) {
e = document.getElementById('coin_to');
e.classList.add('error');
}
if (err_msg.indexOf('Coin From') >= 0) {
e = document.getElementById('coin_from');
e.classList.add('error');
}
if (err_msg.indexOf('Amount From') >= 0) {
e = document.getElementById('amt_from');
e.classList.add('error');
}
if (err_msg.indexOf('Amount To') >= 0) {
e = document.getElementById('amt_to');
e.classList.add('error');
}
if (err_msg.indexOf('Minimum Bid Amount') >= 0) {
e = document.getElementById('amt_bid_min');
e.classList.add('error');
}
}
});

@ -19,6 +19,7 @@
floating_div = document.createElement('div');
floating_div.classList.add('floatright');
messages = document.createElement('ul');
messages.setAttribute('id', 'ul_updates');
ws.onmessage = function (event) {
let json = JSON.parse(event.data);
@ -33,7 +34,7 @@
event_message = '<a href=/bid/' + json['bid_id'] + '>Bid accepted</a>';
}
let messages = document.getElementsByTagName('ul')[0],
let messages = document.getElementById('ul_updates'),
message = document.createElement('li');
message.innerHTML = event_message;
messages.appendChild(message);

@ -10,6 +10,9 @@
{% for m in messages %}
<p>{{ m }}</p>
{% endfor %}
{% for m in err_messages %}
<p class="error_msg">Error: {{ m }}</p>
{% endfor %}
{% if sent_bid_id %}
<p><a href="/bid/{{ sent_bid_id }}">Sent Bid {{ sent_bid_id }}</a></p>
@ -21,6 +24,7 @@
<tr><td>Coin To</td><td>{{ data.coin_to }}</td></tr>
<tr><td>Amount From</td><td>{{ data.amt_from }} {{ data.tla_from }}</td></tr>
<tr><td>Amount To</td><td>{{ data.amt_to }} {{ data.tla_to }}</td></tr>
<tr><td>Minimum Bid Amount</td><td>{{ data.amt_bid_min }} {{ data.tla_from }}</td></tr>
<tr><td>Rate</td><td>{{ data.rate }}</td></tr>
<tr><td title="Total coin-from value of completed bids, that this node is involved in">Amount Swapped</td><td>{{ data.amt_swapped }} {{ data.tla_from }}</td></tr>
<tr><td title="If bids can be sent with a different amount">Amount Variable</td><td>{{ data.amount_negotiable }}</td></tr>

@ -4,6 +4,9 @@
{% for m in messages %}
<p>{{ m }}</p>
{% endfor %}
{% for m in err_messages %}
<p class="error_msg">Error: {{ m }}</p>
{% endfor %}
<form method="post">
@ -59,6 +62,7 @@
<option value="100"{% if data.fee_to_extra==100 %} selected{% endif %}>100%</option>
</select></td></tr>
{% endif %}
<tr><td>Minimum Bid Amount</td><td><input type="text" id="amt_bid_min" name="amt_bid_min" value="{{ data.amt_bid_min }}" title="Bids with an amount below the minimum bid value will be discarded" readonly></td></tr>
<tr><td>Rate</td><td><input type="text" id="rate" name="rate" value="{{ data.rate }}" readonly></td></tr>
<tr><td>Amount Variable</td><td colspan=3><input type="checkbox" id="amt_var" name="amt_var_" value="av" {% if data.amt_var==true %} checked=checked{% endif %} disabled></td></tr>
<tr><td>Rate Variable</td><td colspan=3><input type="checkbox" id="rate_var" name="rate_var_" value="rv" {% if data.rate_var==true %} checked=checked{% endif %} disabled></td></tr>
@ -97,5 +101,6 @@
<input type="hidden" name="rate_var" value="rv">
{% endif %}
</form>
<script src="static/js/new_offer.js"></script>
</body></html>

@ -4,6 +4,9 @@
{% for m in messages %}
<p>{{ m }}</p>
{% endfor %}
{% for m in err_messages %}
<p class="error_msg">Error: {{ m }}</p>
{% endfor %}
<form method="post">
@ -36,8 +39,9 @@
{% endfor %}
</select>
</td><td>Amount To</td><td><input type="text" id="amt_to" name="amt_to" value="{{ data.amt_to }}" onchange="set_rate('amt_to');"></td><td>The amount you will receive.</td></tr>
<tr><td>Minimum Bid Amount</td><td><input type="text" id="amt_bid_min" name="amt_bid_min" value="{{ data.amt_bid_min }}" title="Bids with an amount below the minimum bid value will be discarded"></td></tr>
<tr><td>Rate</td><td><input type="text" id="rate" name="rate" value="{{ data.rate }}" onchange="set_rate('rate');"></td><td>Lock Rate: <input type="checkbox" id="rate_lock" name="rate_lock" value="rl" checked=checked></td></tr>
<tr><td>Amount Variable</td><td><input type="checkbox" id="amt_var" name="amt_var" value="av" {% if data.amt_var==true %} checked=checked{% endif %}></td></tr>
<tr><td>Rate Variable</td><td><input type="checkbox" id="rate_var" name="rate_var" value="rv" {% if data.rate_var==true %} checked=checked{% endif %}></td></tr>
</table>
@ -131,6 +135,6 @@ function set_rate(value_changed) {
xhr_rate.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr_rate.send(params);
}
</script>
<script src="static/js/new_offer.js"></script>
</body></html>

@ -4,6 +4,9 @@
{% for m in messages %}
<p>{{ m }}</p>
{% endfor %}
{% for m in err_messages %}
<p class="error_msg">Error: {{ m }}</p>
{% endfor %}
<form method="post">
@ -56,6 +59,7 @@
<option value="100"{% if data.fee_to_extra==100 %} selected{% endif %}>100%</option>
</select></td></tr>
{% endif %}
<tr><td>Minimum Bid Amount</td><td><input type="text" id="amt_bid_min" name="amt_bid_min" value="{{ data.amt_bid_min }}" title="Bids with an amount below the minimum bid value will be discarded" readonly></td></tr>
<tr><td>Rate</td><td><input type="text" id="rate" name="rate" value="{{ data.rate }}" readonly></td></tr>
<tr><td>Amount Variable</td><td colspan=3><input type="checkbox" id="amt_var" name="amt_var_" value="av" {% if data.amt_var==true %} checked=checked{% endif %} disabled></td></tr>
<tr><td>Rate Variable</td><td colspan=3><input type="checkbox" id="rate_var" name="rate_var_" value="rv" {% if data.rate_var==true %} checked=checked{% endif %} disabled></td></tr>
@ -92,4 +96,5 @@
{% endif %}
</form>
<script src="static/js/new_offer.js"></script>
</body></html>

@ -22,6 +22,7 @@ from basicswap.db import (
)
from basicswap.util import (
ensure,
format_amount,
format_timestamp,
)
from basicswap.basicswap_util import (
@ -44,7 +45,7 @@ def value_or_none(v):
return v
def parseOfferFormData(swap_client, form_data, page_data):
def parseOfferFormData(swap_client, form_data, page_data, options={}):
errors = []
parsed_data = {}
@ -88,12 +89,24 @@ def parseOfferFormData(swap_client, form_data, page_data):
try:
page_data['amt_from'] = get_data_entry(form_data, 'amt_from')
parsed_data['amt_from'] = inputAmount(page_data['amt_from'], ci_from)
# TODO: Add min_bid to the ui
parsed_data['min_bid'] = ci_from.chainparams_network()['min_amount']
except Exception:
errors.append('Amount From')
try:
if 'amt_bid_min' not in page_data:
if options.get('add_min_bid_amt', False) is True:
parsed_data['amt_bid_min'] = ci_from.chainparams_network()['min_amount']
else:
raise ValueError('missing')
else:
page_data['amt_bid_min'] = get_data_entry(form_data, 'amt_bid_min')
parsed_data['amt_bid_min'] = inputAmount(page_data['amt_bid_min'], ci_from)
if parsed_data['amt_bid_min'] < 0 or parsed_data['amt_bid_min'] > parsed_data['amt_from']:
errors.append('Minimum Bid Amount out of range')
except Exception:
errors.append('Minimum Bid Amount')
try:
page_data['amt_to'] = get_data_entry(form_data, 'amt_to')
parsed_data['amt_to'] = inputAmount(page_data['amt_to'], ci_to)
@ -235,7 +248,7 @@ def postNewOfferFromParsed(swap_client, parsed_data):
parsed_data['coin_to'],
parsed_data['amt_from'],
parsed_data['rate'],
parsed_data['min_bid'],
parsed_data['amt_bid_min'],
swap_type,
lock_type=lock_type,
lock_value=parsed_data['lock_seconds'],
@ -246,7 +259,7 @@ def postNewOfferFromParsed(swap_client, parsed_data):
def postNewOffer(swap_client, form_data):
page_data = {}
parsed_data, errors = parseOfferFormData(swap_client, form_data, page_data)
parsed_data, errors = parseOfferFormData(swap_client, form_data, page_data, options={'add_min_bid_amt': True})
if len(errors) > 0:
raise ValueError('Parse errors: ' + ' '.join(errors))
return postNewOfferFromParsed(swap_client, parsed_data)
@ -257,6 +270,7 @@ def page_newoffer(self, url_split, post_string):
swap_client = server.swap_client
messages = []
err_messages = []
page_data = {
# Set defaults
'addr_to': -1,
@ -267,20 +281,21 @@ def page_newoffer(self, url_split, post_string):
'lockmins': 30, # used in debug mode
'debug_ui': swap_client.debug_ui,
'automation_strat_id': -1,
'amt_bid_min': format_amount(1000, 8),
}
form_data = self.checkForm(post_string, 'newoffer', messages)
form_data = self.checkForm(post_string, 'newoffer', err_messages)
if form_data:
try:
parsed_data, errors = parseOfferFormData(swap_client, form_data, page_data)
for e in errors:
messages.append('Error: {}'.format(str(e)))
err_messages.append(str(e))
except Exception as e:
if swap_client.debug is True:
swap_client.log.error(traceback.format_exc())
messages.append('Error: {}'.format(str(e)))
err_messages.append(str(e))
if len(messages) == 0 and 'submit_offer' in page_data:
if len(err_messages) == 0 and 'submit_offer' in page_data:
try:
offer_id = postNewOfferFromParsed(swap_client, parsed_data)
messages.append('<a href="/offer/' + offer_id.hex() + '">Sent Offer {}</a>'.format(offer_id.hex()))
@ -288,9 +303,9 @@ def page_newoffer(self, url_split, post_string):
except Exception as e:
if swap_client.debug is True:
swap_client.log.error(traceback.format_exc())
messages.append('Error: {}'.format(str(e)))
err_messages.append(str(e))
if len(messages) == 0 and 'check_offer' in page_data:
if len(err_messages) == 0 and 'check_offer' in page_data:
template = server.env.get_template('offer_confirm.html')
elif 'step2' in page_data:
template = server.env.get_template('offer_new_2.html')
@ -309,6 +324,7 @@ def page_newoffer(self, url_split, post_string):
return self.render_template(template, {
'messages': messages,
'err_messages': err_messages,
'coins_from': coins_from,
'coins': coins_to,
'addrs': swap_client.listSmsgAddresses('offer_send_from'),
@ -401,6 +417,7 @@ def page_offer(self, url_split, post_string):
'coin_to_ind': int(ci_to.coin_type()),
'amt_from': ci_from.format_amount(offer.amount_from),
'amt_to': ci_to.format_amount((offer.amount_from * offer.rate) // ci_from.COIN()),
'amt_bid_min': ci_from.format_amount(offer.min_bid_amount),
'rate': ci_to.format_amount(offer.rate),
'lock_type': getLockName(offer.lock_type),
'lock_value': offer.lock_value,

@ -57,14 +57,14 @@ Append `--usebtcfastsync` to the below command to optionally initialise the Bitc
Setup with a local Monero daemon (recommended):
export COINDATA_PATH=/var/data/coinswaps
docker run --rm -t --name swap_prepare -v $COINDATA_PATH:/coindata i_swapclient basicswap-prepare --datadir=/coindata --withcoins=monero --htmlhost="0.0.0.0" --xmrrestoreheight=$CURRENT_XMR_HEIGHT
docker run --rm -t --name swap_prepare -v $COINDATA_PATH:/coindata i_swapclient basicswap-prepare --datadir=/coindata --withcoins=monero --htmlhost="0.0.0.0" --wshost="0.0.0.0" --xmrrestoreheight=$CURRENT_XMR_HEIGHT
To instead use Monero public nodes and not run a local Monero daemon<br>(it can be difficult to find reliable public nodes):
Set XMR_RPC_HOST and BASE_XMR_RPC_PORT to a public XMR node.
export COINDATA_PATH=/var/data/coinswaps
docker run --rm -e XMR_RPC_HOST="node.xmr.to" -e BASE_XMR_RPC_PORT=18081 -t --name swap_prepare -v $COINDATA_PATH:/coindata i_swapclient basicswap-prepare --datadir=/coindata --withcoins=monero --htmlhost="0.0.0.0" --xmrrestoreheight=$CURRENT_XMR_HEIGHT
docker run --rm -e XMR_RPC_HOST="node.xmr.to" -e BASE_XMR_RPC_PORT=18081 -t --name swap_prepare -v $COINDATA_PATH:/coindata i_swapclient basicswap-prepare --datadir=/coindata --withcoins=monero --htmlhost="0.0.0.0" --wshost="0.0.0.0" --xmrrestoreheight=$CURRENT_XMR_HEIGHT
**Record the mnemonic from the output of the above command.**

Loading…
Cancel
Save