lnbits-legend/lnbits/extensions/offlineshop/lnurl.py

88 lines
2.7 KiB
Python
Raw Normal View History

2021-03-07 00:08:36 -03:00
import hashlib
from quart import jsonify, url_for, request
from lnurl import LnurlPayResponse, LnurlPayActionResponse, LnurlErrorResponse # type: ignore
from lnbits.core.services import create_invoice
from lnbits.utils.exchange_rates import fiat_amount_as_satoshis
2021-03-07 00:08:36 -03:00
from . import offlineshop_ext
from .crud import get_shop, get_item
@offlineshop_ext.route("/lnurl/<item_id>", methods=["GET"])
async def lnurl_response(item_id):
item = await get_item(item_id)
if not item:
return jsonify({"status": "ERROR", "reason": "Item not found."})
2021-03-07 14:37:31 -03:00
if not item.enabled:
return jsonify({"status": "ERROR", "reason": "Item disabled."})
price_msat = (
await fiat_amount_as_satoshis(item.price, item.unit)
if item.unit != "sat"
else item.price
) * 1000
2021-03-07 00:08:36 -03:00
resp = LnurlPayResponse(
callback=url_for("offlineshop.lnurl_callback", item_id=item.id, _external=True),
2021-03-07 00:08:36 -03:00
min_sendable=price_msat,
max_sendable=price_msat,
metadata=await item.lnurlpay_metadata(),
)
return jsonify(resp.dict())
@offlineshop_ext.route("/lnurl/cb/<item_id>", methods=["GET"])
async def lnurl_callback(item_id):
item = await get_item(item_id)
if not item:
return jsonify({"status": "ERROR", "reason": "Couldn't find item."})
if item.unit == "sat":
min = item.price * 1000
max = item.price * 1000
else:
price = await fiat_amount_as_satoshis(item.price, item.unit)
2021-03-07 00:08:36 -03:00
# allow some fluctuation (the fiat price may have changed between the calls)
min = price * 995
max = price * 1010
2021-03-07 00:08:36 -03:00
amount_received = int(request.args.get("amount") or 0)
2021-03-07 00:08:36 -03:00
if amount_received < min:
return jsonify(
LnurlErrorResponse(
reason=f"Amount {amount_received} is smaller than minimum {min}."
).dict()
)
2021-03-07 00:08:36 -03:00
elif amount_received > max:
return jsonify(
LnurlErrorResponse(
reason=f"Amount {amount_received} is greater than maximum {max}."
).dict()
)
2021-03-07 00:08:36 -03:00
shop = await get_shop(item.shop)
try:
payment_hash, payment_request = await create_invoice(
wallet_id=shop.wallet,
amount=int(amount_received / 1000),
memo=item.name,
description_hash=hashlib.sha256(
(await item.lnurlpay_metadata()).encode("utf-8")
).digest(),
extra={"tag": "offlineshop", "item": item.id},
)
except Exception as exc:
return jsonify(LnurlErrorResponse(reason=exc.message).dict())
2021-03-07 00:08:36 -03:00
2021-03-14 14:21:26 -03:00
resp = LnurlPayActionResponse(
pr=payment_request,
success_action=item.success_action(shop, payment_hash) if shop.method else None,
routes=[],
)
2021-03-07 00:08:36 -03:00
return jsonify(resp.dict())