commit 2642243f9bfa4700e2d07744c0f162c534a37f27
parent fe4cb535cc68ec2c48e36e1ef7676bf0ceba2963
Author: Nick <nicholas.w.farrow@gmail.com>
Date: Fri, 12 Nov 2021 16:44:24 +1100
Add Lightning Address (#21)
* WIP lightning address server
* add lightning address config arg
* fix url
* Remove response codes and add import
* add identifier metadata
* change metadata string format
* Remove extra invoice print
* add lnd invoice memos
* Use memo for payRequest
* Add description hash
* Change lndgrpc library to sako0938's fork
* metadata and description hash
* add ability to modifiy description - new config arg
* Fix missing char
* switch min max sats
* Force HTTPS and fix min max payments
Diffstat:
5 files changed, 80 insertions(+), 9 deletions(-)
diff --git a/config.py b/config.py
@@ -60,6 +60,10 @@ connection_attempts = 3
# Generic redirect url after payment
redirect = "https://github.com/nickfarrow/satsale"
+# Lightning Address e.g. name@you.satsale.domain (think this requires https url)
+lightning_address = None
+lightning_address_comment = None # Defaults to: "Thank you for your support <3"
+
# DO NOT CHANGE THIS TO TRUE UNLESS YOU WANT ALL PAYMENTS TO AUTOMATICALLY
# BE CONSIDERED AS PAID.
free_mode = False
diff --git a/gateways/lightning_address.py b/gateways/lightning_address.py
@@ -0,0 +1,64 @@
+from flask import request
+from flask_restplus import Resource, Api, Namespace, fields
+import hashlib
+
+import config
+
+min_sats = 10**2
+max_sats = 10**6
+
+# Following https://github.com/andrerfneves/lightning-address/blob/master/DIY.md
+
+description = config.lightning_address_comment
+if description is None:
+ description = "Thank you for your support <3"
+
+metadata = "[[\"text/plain\", \"{}\"], [\"text/identifier\", \"{}\"]]".format(description, config.lightning_address.split("@")[0])
+
+def add_ln_address_decorators(app, api, node):
+ class get_ln_address(Resource):
+ def get(self):
+ try:
+ print("Someone requested our ln address: {}!".format(config.lightning_address))
+ resp = {
+ "callback": "https://{}/lnaddr".format(config.lightning_address.split("@")[1]),
+ "maxSendable": max_sats*10**3,
+ "minSendable": min_sats*10**3,
+ "metadata": metadata,
+ "tag": "payRequest"
+ }
+ return resp
+
+ except Exception as e:
+ print(e)
+ return {"status": "ERROR", "reason": e}
+
+
+
+ class init_ln_addr_payment(Resource):
+ def get(self):
+ if request.args.get("amount") is None:
+ return {"status": "ERROR", "reason": "You need to request an ?amount=MSATS"}
+
+ amount_msats = int(request.args.get("amount"))
+ amount_btc = amount_msats / 10**(3+8)
+
+ print("Received payment request from ln address for {} msats...".format(amount_msats))
+
+ description_hash = hashlib.sha256(metadata.encode()).digest()
+
+ try:
+ invoice, _ = node.create_lnd_invoice(amount_btc, memo="lightning address payment", description_hash=description_hash)
+ print("Responding with invoice {}".format(invoice))
+ return {
+ "pr": invoice,
+ "routes": []
+ }
+ except Exception as e:
+ print(e)
+ return {"status": "ERROR", "reason": e}
+
+
+ api.add_resource(get_ln_address, "/.well-known/lnurlp/{}".format(config.lightning_address.split("@")[0]))
+ api.add_resource(init_ln_addr_payment, "/lnaddr")
+ return
diff --git a/node/lnd.py b/node/lnd.py
@@ -111,16 +111,16 @@ class lnd:
return
# Create lightning invoice
- def create_lnd_invoice(self, btc_amount):
+ def create_lnd_invoice(self, btc_amount, memo=None, description_hash=None):
# Multiplying by 10^8 to convert to satoshi units
sats_amount = int(btc_amount * 10 ** 8)
- res = self.lnd.add_invoice(value=sats_amount)
+ res = self.lnd.add_invoice(value=sats_amount, memo=memo, description_hash=description_hash)
lnd_invoice = json.loads(MessageToJson(res))
- return lnd_invoice["payment_request"], lnd_invoice["r_hash"]
+ return lnd_invoice["paymentRequest"], lnd_invoice["rHash"]
def get_address(self, amount, label):
- address, r_hash = self.create_lnd_invoice(amount)
+ address, r_hash = self.create_lnd_invoice(amount, memo=label)
return address, r_hash
# Check whether the payment has been paid
@@ -129,12 +129,12 @@ class lnd:
MessageToJson(self.lnd.lookup_invoice(r_hash_str=b64decode(rhash).hex()))
)
- if "amt_paid_sat" not in invoice_status.keys():
+ if "amtPaidSat" not in invoice_status.keys():
conf_paid = 0
unconf_paid = 0
else:
# Store amount paid and convert to BTC units
- conf_paid = int(invoice_status["amt_paid_sat"]) * 10 ** 8
+ conf_paid = int(invoice_status["amtPaidSat"]) * 10 ** 8
unconf_paid = 0
return conf_paid, unconf_paid
diff --git a/requirements.txt b/requirements.txt
@@ -13,4 +13,4 @@ PySocks==1.7.1
# For lightning (optional)
setuptools==50.3.2
-lndgrpc==0.2.0
+lnd-grpc-client
diff --git a/satsale.py b/satsale.py
@@ -211,8 +211,6 @@ class complete_payment(Resource):
if status["payment_complete"] != 1:
return {"message": "You havent paid you stingy bastard"}
- print(invoice)
-
# Call webhook to confirm payment with merchant
if (invoice["webhook"] != None) and (invoice["webhook"] != ""):
print("Calling webhook {}".format(invoice["webhook"]))
@@ -301,5 +299,10 @@ if config.pay_method == "lnd":
print("Connection to lightning node successful.")
+if config.lightning_address is not None:
+ from gateways import lightning_address
+ lightning_address.add_ln_address_decorators(app, api, lightning_node)
+
+
if __name__ == "__main__":
app.run(debug=False)