feat: add get_pr_from_lnurl to lnurl services (#3286)

This commit is contained in:
dni ⚡ 2025-07-21 10:28:14 +02:00 committed by GitHub
parent 01fdc1defb
commit ff535ae065
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 31 additions and 72 deletions

View file

@ -7,11 +7,11 @@ from datetime import datetime, timezone
from enum import Enum
from ecdsa import SECP256k1, SigningKey
from lnurl import encode as lnurl_encode
from pydantic import BaseModel, Field
from lnbits.db import FilterModel
from lnbits.helpers import url_for
from lnbits.lnurl import encode as lnurl_encode
from lnbits.settings import settings

View file

@ -2,7 +2,7 @@ from .funding_source import (
get_balance_delta,
switch_to_voidwallet,
)
from .lnurl import fetch_lnurl_pay_request
from .lnurl import fetch_lnurl_pay_request, get_pr_from_lnurl
from .notifications import enqueue_admin_notification, send_payment_notification
from .payments import (
calculate_fiat_amounts,
@ -55,6 +55,7 @@ __all__ = [
"fetch_lnurl_pay_request",
"get_balance_delta",
"get_payments_daily_stats",
"get_pr_from_lnurl",
"pay_invoice",
"send_payment_notification",
"service_fee",

View file

@ -1,11 +1,35 @@
from lnurl import LnurlPayActionResponse
from lnurl import execute_pay_request as lnurlp
from lnurl import (
LnurlPayActionResponse,
LnurlPayResponse,
LnurlResponseException,
execute_pay_request,
handle,
)
from lnbits.core.models import CreateLnurlPayment
from lnbits.settings import settings
from lnbits.utils.exchange_rates import fiat_amount_as_satoshis
async def get_pr_from_lnurl(lnurl: str, amount_msat: int) -> str:
res = await handle(lnurl, user_agent=settings.user_agent, timeout=10)
if not isinstance(res, LnurlPayResponse):
raise LnurlResponseException(
"Invalid LNURL response. Expected LnurlPayResponse."
)
res2 = await execute_pay_request(
res,
msat=str(amount_msat),
user_agent=settings.user_agent,
timeout=10,
)
if not isinstance(res, LnurlPayActionResponse):
raise LnurlResponseException(
"Invalid LNURL pay response. Expected LnurlPayActionResponse."
)
return res2.pr
async def fetch_lnurl_pay_request(data: CreateLnurlPayment) -> LnurlPayActionResponse:
"""
Pay an LNURL payment request.
@ -21,9 +45,9 @@ async def fetch_lnurl_pay_request(data: CreateLnurlPayment) -> LnurlPayActionRes
else:
amount_msat = data.amount
return await lnurlp(
return await execute_pay_request(
data.res,
msat=str(amount_msat),
user_agent=settings.user_agent,
timeout=5,
timeout=10,
)

View file

@ -1,66 +0,0 @@
from http import HTTPStatus
from typing import Callable
from fastapi import HTTPException, Request, Response
from fastapi.responses import JSONResponse
from fastapi.routing import APIRoute
from lnurl import LnurlErrorResponse, decode, encode, handle
from loguru import logger
from lnbits.exceptions import InvoiceError, PaymentError
class LnurlErrorResponseHandler(APIRoute):
"""
Custom APIRoute class to handle LNURL errors.
LNURL errors always return with status 200 and
a JSON response with `status="ERROR"` and a `reason` key.
Helps to catch HTTPException and return a valid lnurl error response
Example:
withdraw_lnurl_router = APIRouter(prefix="/api/v1/lnurl")
withdraw_lnurl_router.route_class = LnurlErrorResponseHandler
"""
def get_route_handler(self) -> Callable:
original_route_handler = super().get_route_handler()
async def lnurl_route_handler(request: Request) -> Response:
try:
response = await original_route_handler(request)
return response
except (InvoiceError, PaymentError) as exc:
logger.debug(f"Wallet Error: {exc}")
response = JSONResponse(
status_code=HTTPStatus.OK,
content={"status": "ERROR", "reason": f"{exc.message}"},
)
return response
except HTTPException as exc:
logger.debug(f"HTTPException: {exc}")
response = JSONResponse(
status_code=HTTPStatus.OK,
content={"status": "ERROR", "reason": f"{exc.detail}"},
)
return response
except Exception as exc:
logger.error("Unknown Error:", exc)
response = JSONResponse(
status_code=HTTPStatus.OK,
content={
"status": "ERROR",
"reason": f"UNKNOWN ERROR: {exc!s}",
},
)
return response
return lnurl_route_handler
__all__ = [
"LnurlErrorResponse",
"LnurlErrorResponseHandler",
"decode",
"encode",
"handle",
]