mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-02-24 22:58:46 +01:00
199 lines
5.8 KiB
Python
199 lines
5.8 KiB
Python
import shortuuid # type: ignore
|
|
import hashlib
|
|
import math
|
|
import json
|
|
from http import HTTPStatus
|
|
from datetime import datetime
|
|
from lnbits.core.services import pay_invoice, create_invoice
|
|
from http import HTTPStatus
|
|
from starlette.exceptions import HTTPException
|
|
from starlette.responses import HTMLResponse, JSONResponse # type: ignore
|
|
from lnbits.utils.exchange_rates import get_fiat_rate_satoshis
|
|
from fastapi import FastAPI, Request
|
|
from fastapi.params import Depends
|
|
from typing import Optional
|
|
from fastapi.param_functions import Query
|
|
from . import satsdice_ext
|
|
from .crud import (
|
|
get_satsdice_withdraw_by_hash,
|
|
update_satsdice_withdraw,
|
|
get_satsdice_pay,
|
|
create_satsdice_payment,
|
|
)
|
|
from lnurl import (
|
|
LnurlPayResponse,
|
|
LnurlPayActionResponse,
|
|
LnurlErrorResponse,
|
|
)
|
|
from .models import CreateSatsDicePayment
|
|
|
|
|
|
##############LNURLP STUFF
|
|
|
|
|
|
@satsdice_ext.get(
|
|
"/api/v1/lnurlp/{link_id}",
|
|
response_class=HTMLResponse,
|
|
name="satsdice.lnurlp_response",
|
|
)
|
|
async def api_lnurlp_response(req: Request, link_id: str = Query(None)):
|
|
link = await get_satsdice_pay(link_id)
|
|
if not link:
|
|
raise HTTPException(
|
|
status_code=HTTPStatus.NOT_FOUND, detail="LNURL-pay not found."
|
|
)
|
|
payResponse = {
|
|
"tag": "payRequest",
|
|
"callback": req.url_for("satsdice.api_lnurlp_callback", link_id=link.id),
|
|
"metadata": link.lnurlpay_metadata,
|
|
"minSendable": math.ceil(link.min_bet * 1) * 1000,
|
|
"maxSendable": round(link.max_bet * 1) * 1000,
|
|
}
|
|
return json.dumps(payResponse)
|
|
|
|
|
|
@satsdice_ext.get(
|
|
"/api/v1/lnurlp/cb/{link_id}",
|
|
response_class=HTMLResponse,
|
|
name="satsdice.api_lnurlp_callback",
|
|
)
|
|
async def api_lnurlp_callback(
|
|
req: Request,
|
|
link_id: str = Query(None),
|
|
amount: str = Query(None),
|
|
):
|
|
link = await get_satsdice_pay(link_id)
|
|
print(link)
|
|
if not link:
|
|
raise HTTPException(
|
|
status_code=HTTPStatus.NOT_FOUND, detail="LNURL-pay not found."
|
|
)
|
|
|
|
min, max = link.min_bet, link.max_bet
|
|
min = link.min_bet * 1000
|
|
max = link.max_bet * 1000
|
|
|
|
amount_received = int(amount or 0)
|
|
if amount_received < min:
|
|
raise HTTPException(
|
|
status_code=HTTPStatus.FORBIDDEN,
|
|
detail=f"Amount {amount_received} is smaller than minimum {min}.",
|
|
)
|
|
elif amount_received > max:
|
|
raise HTTPException(
|
|
status_code=HTTPStatus.FORBIDDEN,
|
|
detail=f"Amount {amount_received} is greater than maximum {max}.",
|
|
)
|
|
|
|
payment_hash, payment_request = await create_invoice(
|
|
wallet_id=link.wallet,
|
|
amount=int(amount_received / 1000),
|
|
memo="Satsdice bet",
|
|
description_hash=hashlib.sha256(
|
|
link.lnurlpay_metadata.encode("utf-8")
|
|
).digest(),
|
|
extra={"tag": "satsdice", "link": link.id, "comment": "comment"},
|
|
)
|
|
|
|
success_action = link.success_action(payment_hash=payment_hash, req=req)
|
|
|
|
data: CreateSatsDicePayment = {
|
|
"satsdice_pay": link.id,
|
|
"value": amount_received / 1000,
|
|
"payment_hash": payment_hash,
|
|
}
|
|
|
|
await create_satsdice_payment(data)
|
|
payResponse = {
|
|
"pr": payment_request,
|
|
"successAction": success_action,
|
|
"routes": [],
|
|
}
|
|
print(json.dumps(payResponse))
|
|
|
|
return json.dumps(payResponse)
|
|
|
|
|
|
##############LNURLW STUFF
|
|
|
|
|
|
@satsdice_ext.get(
|
|
"/api/v1/lnurlw/{unique_hash}",
|
|
response_class=HTMLResponse,
|
|
name="satsdice.lnurlw_response",
|
|
)
|
|
async def api_lnurlw_response(req: Request, unique_hash: str = Query(None)):
|
|
link = await get_satsdice_withdraw_by_hash(unique_hash)
|
|
|
|
if not link:
|
|
raise HTTPException(
|
|
status_code=HTTPStatus.NOT_FOUND, detail="LNURL-satsdice not found."
|
|
)
|
|
if link.used:
|
|
raise HTTPException(status_code=HTTPStatus.OK, detail="satsdice is spent.")
|
|
url = req.url_for("satsdice.api_lnurlw_callback", unique_hash=link.unique_hash)
|
|
withdrawResponse = {
|
|
"tag": "withdrawRequest",
|
|
"callback": url,
|
|
"k1": link.k1,
|
|
"minWithdrawable": link.value * 1000,
|
|
"maxWithdrawable": link.value * 1000,
|
|
"defaultDescription": "Satsdice winnings!",
|
|
}
|
|
return json.dumps(withdrawResponse)
|
|
|
|
|
|
# CALLBACK
|
|
|
|
|
|
@satsdice_ext.get(
|
|
"/api/v1/lnurlw/cb/{unique_hash}",
|
|
response_class=HTMLResponse,
|
|
name="satsdice.api_lnurlw_callback",
|
|
)
|
|
async def api_lnurlw_callback(
|
|
req: Request,
|
|
unique_hash: str = Query(None),
|
|
k1: str = Query(None),
|
|
pr: str = Query(None),
|
|
):
|
|
link = await get_satsdice_withdraw_by_hash(unique_hash)
|
|
paylink = await get_satsdice_pay(link.satsdice_pay)
|
|
payment_request = pr
|
|
now = int(datetime.now().timestamp())
|
|
|
|
if not link:
|
|
raise HTTPException(
|
|
status_code=HTTPStatus.NOT_FOUND, detail="LNURL-satsdice not found."
|
|
)
|
|
|
|
if link.used:
|
|
raise HTTPException(status_code=HTTPStatus.OK, detail="satsdice is spent.")
|
|
|
|
if link.k1 != k1:
|
|
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Bad request..")
|
|
|
|
if now < link.open_time:
|
|
return {"status": "ERROR", "reason": f"Wait {link.open_time - now} seconds."}
|
|
|
|
try:
|
|
await update_satsdice_withdraw(link.id, used=1)
|
|
|
|
await pay_invoice(
|
|
wallet_id=paylink.wallet,
|
|
payment_request=payment_request,
|
|
max_sat=link.value,
|
|
extra={"tag": "withdraw"},
|
|
)
|
|
|
|
except ValueError as e:
|
|
await update_satsdice_withdraw(link.id, used=1)
|
|
return {"status": "ERROR", "reason": str(e)}
|
|
except PermissionError:
|
|
await update_satsdice_withdraw(link.id, used=1)
|
|
return {"status": "ERROR", "reason": "satsdice link is empty."}
|
|
except Exception as e:
|
|
await update_satsdice_withdraw(link.id, used=1)
|
|
return {"status": "ERROR", "reason": str(e)}
|
|
|
|
return {"status": "OK"}
|