lnbits-legend/lnbits/extensions/bleskomat/models.py
2021-02-15 12:53:02 +01:00

110 lines
3.7 KiB
Python

import json
import time
from typing import NamedTuple, Dict
from lnbits import bolt11
from lnbits.core.services import pay_invoice
from . import db
from .helpers import get_callback_url, LnurlValidationError
class Bleskomat(NamedTuple):
id: str
wallet: str
api_key_id: str
api_key_secret: str
api_key_encoding: str
name: str
fiat_currency: str
exchange_rate_provider: str
fee: str
class BleskomatLnurl(NamedTuple):
id: str
bleskomat: str
wallet: str
hash: str
tag: str
params: str
api_key_id: str
initial_uses: int
remaining_uses: int
created_time: int
updated_time: int
def has_uses_remaining(self) -> bool:
# When initial uses is 0 then the LNURL has unlimited uses.
return self.initial_uses == 0 or self.remaining_uses > 0
def get_info_response_object(self, secret: str) -> Dict[str, str]:
tag = self.tag
params = json.loads(self.params)
response = { "tag": tag }
if tag == "withdrawRequest":
for key in ["minWithdrawable", "maxWithdrawable", "defaultDescription"]:
response[key] = params[key]
response["callback"] = get_callback_url()
response["k1"] = secret
return response
def validate_action(self, query: Dict[str, str]) -> None:
tag = self.tag
params = json.loads(self.params)
# Perform tag-specific checks.
if tag == "withdrawRequest":
for field in ["pr"]:
if not field in query:
raise LnurlValidationError(f"Missing required parameter: \"{field}\"")
# Check the bolt11 invoice(s) provided.
pr = query["pr"]
if "," in pr:
raise LnurlValidationError("Multiple payment requests not supported")
try:
invoice = bolt11.decode(pr)
except ValueError as e:
raise LnurlValidationError("Invalid parameter (\"pr\"): Lightning payment request expected")
if invoice.amount_msat < params["minWithdrawable"]:
raise LnurlValidationError("Amount in invoice must be greater than or equal to \"minWithdrawable\"")
if invoice.amount_msat > params["maxWithdrawable"]:
raise LnurlValidationError("Amount in invoice must be less than or equal to \"maxWithdrawable\"")
else:
raise LnurlValidationError(f"Unknown subprotocol: \"{tag}\"")
async def execute_action(self, query: Dict[str, str]):
self.validate_action(query)
used = False
if self.initial_uses > 0:
await db.commit()
await db.begin()
used = await self.use()
if not used:
await db.rollback()
raise LnurlValidationError("Maximum number of uses already reached")
try:
tag = self.tag
if tag == "withdrawRequest":
payment_hash = await pay_invoice(
wallet_id=self.wallet,
payment_request=query["pr"],
)
if not payment_hash:
raise LnurlValidationError("Failed to pay invoice")
except Exception as e:
if used:
await db.rollback()
raise e
if used:
await db.commit()
async def use(self) -> bool:
now = int(time.time())
result = await db.execute(
"""
UPDATE bleskomat_lnurls
SET remaining_uses = remaining_uses - 1, updated_time = ?
WHERE id = ?
AND remaining_uses > 0
""",
(now, self.id)
)
return result.rowcount > 0