-
Notifications
You must be signed in to change notification settings - Fork 14
/
views_lnurl.py
144 lines (120 loc) · 4.16 KB
/
views_lnurl.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from http import HTTPStatus
from typing import Callable, Optional
from fastapi import APIRouter, Request, Response
from fastapi.responses import JSONResponse
from fastapi.routing import APIRoute
from lnbits.core.services import pay_invoice, websocket_updater
from loguru import logger
from starlette.exceptions import HTTPException
from .crud import get_lnurlcharge, get_tpos, update_lnurlcharge, update_tpos
from .models import LnurlCharge
class LNURLErrorResponseHandler(APIRoute):
def get_route_handler(self) -> Callable:
original_route_handler = super().get_route_handler()
async def custom_route_handler(request: Request) -> Response:
try:
response = await original_route_handler(request)
except HTTPException as exc:
logger.debug(f"HTTPException: {exc}")
response = JSONResponse(
status_code=exc.status_code,
content={"status": "ERROR", "reason": f"{exc.detail}"},
)
except Exception as exc:
raise exc
return response
return custom_route_handler
tpos_lnurl_router = APIRouter(route_class=LNURLErrorResponseHandler)
@tpos_lnurl_router.get(
"/api/v1/lnurl/{lnurlcharge_id}/{amount}",
status_code=HTTPStatus.OK,
name="tpos.tposlnurlcharge",
)
async def lnurl_params(
request: Request,
lnurlcharge_id: str,
amount: int,
):
lnurlcharge = await get_lnurlcharge(lnurlcharge_id)
if not lnurlcharge:
return {
"status": "ERROR",
"reason": f"lnurlcharge {lnurlcharge_id} not found on this server",
}
tpos = await get_tpos(lnurlcharge.tpos_id)
if not tpos:
return {
"status": "ERROR",
"reason": f"TPoS {lnurlcharge.tpos_id} not found on this server",
}
if amount > tpos.withdraw_maximum:
return {
"status": "ERROR",
"reason": (
f"Amount requested {amount} is too high, "
f"maximum withdrawable is {tpos.withdraw_maximum}"
),
}
logger.debug(f"Amount to withdraw: {amount}")
return {
"tag": "withdrawRequest",
"callback": str(request.url_for("tpos.tposlnurlcharge.callback")),
"k1": lnurlcharge_id,
"minWithdrawable": amount * 1000,
"maxWithdrawable": amount * 1000,
"defaultDescription": "TPoS withdraw",
}
@tpos_lnurl_router.get(
"/api/v1/lnurl/cb",
status_code=HTTPStatus.OK,
name="tpos.tposlnurlcharge.callback",
)
async def lnurl_callback(
pr: Optional[str] = None,
k1: Optional[str] = None,
):
assert k1, "k1 is required"
assert pr, "pr is required"
lnurlcharge = await get_lnurlcharge(k1)
if not lnurlcharge:
return {
"status": "ERROR",
"reason": f"lnurlcharge {k1} not found on this server",
}
assert lnurlcharge.amount, f"LnurlCharge {k1} has no amount"
if lnurlcharge.claimed:
return {
"status": "ERROR",
"reason": f"LnurlCharge {k1} has already been claimed",
}
tpos = await get_tpos(lnurlcharge.tpos_id)
assert tpos, f"TPoS with ID {lnurlcharge.tpos_id} not found"
assert (
lnurlcharge.amount < tpos.withdraw_maximum
), f"""
Amount requested {lnurlcharge.amount} is too high,
maximum withdrawable is {tpos.withdraw_maximum}
"""
await update_lnurlcharge(
LnurlCharge(
id=k1,
tpos_id=lnurlcharge.tpos_id,
amount=int(lnurlcharge.amount),
claimed=True,
)
)
tpos.withdrawn_amount = int(tpos.withdrawn_amount or 0) + int(lnurlcharge.amount)
await update_tpos(tpos)
try:
await pay_invoice(
wallet_id=tpos.wallet,
payment_request=pr,
max_sat=int(lnurlcharge.amount),
extra={"tag": "TPoSWithdraw", "tpos_id": lnurlcharge.tpos_id},
)
await websocket_updater(k1, "paid")
except Exception as exc:
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, detail=f"withdraw not working. {exc!s}"
) from exc
return {"status": "OK"}