commit 7ecc903350e6e95e2387f681bf9991b63590b771
parent b4bb30b92805e45b9ac2ea6a1ad45f250b331f01
Author: Kristaps Kaupe <kristaps@blogiem.lv>
Date: Thu, 3 Mar 2022 09:51:01 +0200
Add configurable dust limit for onchain payments (#46)
* Fix BTC amount formatting for amounts below 0.0001
* Add configurable dust limit for onchain payments
Diffstat:
8 files changed, 43 insertions(+), 6 deletions(-)
diff --git a/config.py b/config.py
@@ -30,6 +30,7 @@ tunnel_host = get_opt("tunnel_host", None)
tor_bitcoinrpc_host = get_opt("tor_bitcoinrpc_host", None)
tor_proxy = get_opt("tor_proxy", None)
pay_method = get_opt("pay_method", "bitcoind")
+onchain_dust_limit = get_opt("onchain_dust_limit", 0.00000546)
lnd_dir = get_opt("lnd_dir", "~/.lnd/")
lnd_rpcport = get_opt("lnd_rpcport", "10009")
lnd_macaroon = get_opt("lnd_macaroon", "admin.macaroon")
diff --git a/config.toml b/config.toml
@@ -36,6 +36,10 @@ api_key_path = "SatSale_API_key"
#### Payment method ####
pay_method = "bitcoind"
+# Dust limit for onchain payments in BTC. Don't generate onchain invoices
+# below this value.
+onchain_dust_limit = 0.00000546
+
## Lightning
# Switch payment_method to lnd if you want to use lightning payments instead. And uncomment lnd_dir.
#pay_method = "lnd"
diff --git a/node/bitcoind.py b/node/bitcoind.py
@@ -32,6 +32,8 @@ class btcd:
def __init__(self):
from bitcoinrpc.authproxy import AuthServiceProxy
+ self.is_onchain = True
+
if config.rpc_cookie_file:
if os.path.isfile(config.rpc_cookie_file):
rpc_credentials_str = open(config.rpc_cookie_file, "r").read()
diff --git a/node/clightning.py b/node/clightning.py
@@ -23,6 +23,8 @@ class clightning:
def __init__(self):
from pyln.client import LightningRpc
+ self.is_onchain = False
+
for i in range(config.connection_attempts):
try:
logging.info("Attempting to connect to clightning...")
diff --git a/node/lnd.py b/node/lnd.py
@@ -18,6 +18,8 @@ class lnd:
def __init__(self):
from lndgrpc import LNDClient
+ self.is_onchain = False
+
# Copy admin macaroon and tls cert to local machine
self.copy_certs()
diff --git a/satsale.py b/satsale.py
@@ -122,6 +122,7 @@ status_model = api.model(
class create_payment(Resource):
@api.response(200, "Success", invoice_model)
@api.response(400, "Invalid payment method")
+ @api.response(406, "Amount below dust limit")
def get(self):
"Create Payment"
"""Initiate a new payment with an `amount` in `config.base_currecy`."""
@@ -144,13 +145,22 @@ class create_payment(Resource):
logging.warning("Invalid payment method {}".format(payment_method))
return {"message": "Invalid payment method."}, 400
+ btc_value = get_btc_value(base_amount, currency)
+ if node.is_onchain and btc_value < config.onchain_dust_limit:
+ logging.warning(
+ "Requested onchain payment for {} {} below dust limit ({} < {})".format(
+ base_amount, currency, btc_amount_format(btc_value),
+ btc_amount_format(config.onchain_dust_limit)))
+ return {"message": "Amount below dust limit."}, 406
+
invoice = {
"uuid": str(uuid.uuid4().hex),
"fiat_value": base_amount,
- "btc_value": btc_amount_format(get_btc_value(base_amount, currency)),
+ "btc_value": btc_amount_format(btc_value),
"method": payment_method,
"time": time.time(),
"webhook": webhook,
+ "onchain_dust_limit": config.onchain_dust_limit
}
# Get an address / invoice, and create a QR code
diff --git a/static/satsale.js b/static/satsale.js
@@ -17,14 +17,24 @@ function payment(payment_data) {
$('#amount').text(invoice.btc_value).html();
$('#amount_sats').text(Math.round(invoice.btc_value * 10**8)).html();
$('#timer').text(Math.round(invoice.time_left)).html();
+ $('#paymentDetails').show();
+
+ if (invoice.btc_value >= invoice.onchain_dust_limit) {
+ $('#paymentMethodSwitchButton').show();
+ }
return payment_uuid
+ }, function(data) {
+ $('#error').show();
+ return "";
}).then(function(payment_uuid) {
- load_qr(payment_uuid);
- document.getElementById('timerContainer').style.visibility = "visible";
+ if (payment_uuid != "") {
+ load_qr(payment_uuid);
+ document.getElementById('timerContainer').style.visibility = "visible";
- // Pass payment uuid and the interval process to check_payment
- var checkinterval = setInterval(function() {check_payment(payment_uuid, checkinterval, payment_data);}, 1000);
+ // Pass payment uuid and the interval process to check_payment
+ var checkinterval = setInterval(function() {check_payment(payment_uuid, checkinterval, payment_data);}, 1000);
+ }
})
});
}
diff --git a/templates/index.html b/templates/index.html
@@ -33,7 +33,7 @@
</div>
- <div id="paymentDetails" style="display:block; padding: 0;">
+ <div id="paymentDetails" style="display:none; padding: 0;">
<p style="padding:0;">Send: <b><span id="amount_sats"></span></b> sats</p>
<p style="padding:0;">     (<b><span id="amount"></span></b> BTC)</p>
<p style="padding:0;">To: </p><b><p id="address" onclick="copyTextFromElement('address')"></p></b>
@@ -41,10 +41,15 @@
<p id="timerContainer" style="padding:0;visibility:hidden;"><span id="timer"></span> seconds remaining.</p>
</div>
+ <div id="error" style="display:none;">
+ <p style="padding:0;">Error generating invoice! Amount too small?</p>
+ </div>
+
</br>
<div id="row">
<div id="left" style="text-align: left; padding: 0;">
+ <div id="paymentMethodSwitchButton" style="display:none;">
<!-- Alternate between offering lightning or on chain payment switch -->
{% if params.lnd_enabled %}
{% if params.method != "bitcoind"%}
@@ -60,6 +65,7 @@
<button class="button button1" onclick="replaceUrlParam(window.location, 'method', 'clightning');">Lightning Payment</button>
{% endif %}
{% endif %}
+ </div>
</div>
<div id="right" style="text-align: right; padding: 10px 10px;">