mirror of
https://github.com/lnbits/lnbits.git
synced 2025-06-07 05:33:06 +02:00
Merge branch 'lnbits:main' into main
This commit is contained in:
commit
453d65a91d
@ -88,7 +88,7 @@ class Payment(BaseModel):
|
|||||||
preimage: str
|
preimage: str
|
||||||
payment_hash: str
|
payment_hash: str
|
||||||
expiry: Optional[float]
|
expiry: Optional[float]
|
||||||
extra: Optional[Dict] = {}
|
extra: Dict = {}
|
||||||
wallet_id: str
|
wallet_id: str
|
||||||
webhook: Optional[str]
|
webhook: Optional[str]
|
||||||
webhook_status: Optional[int]
|
webhook_status: Optional[int]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import secrets
|
import secrets
|
||||||
from datetime import date, datetime
|
from datetime import datetime
|
||||||
from typing import List, Optional, Union
|
from typing import List, Optional, Union
|
||||||
|
|
||||||
from lnbits.helpers import urlsafe_short_hash
|
from lnbits.helpers import urlsafe_short_hash
|
||||||
@ -124,7 +124,6 @@ async def get_card_by_otp(otp: str) -> Optional[Card]:
|
|||||||
|
|
||||||
async def delete_card(card_id: str) -> None:
|
async def delete_card(card_id: str) -> None:
|
||||||
# Delete cards
|
# Delete cards
|
||||||
card = await get_card(card_id)
|
|
||||||
await db.execute("DELETE FROM boltcards.cards WHERE id = ?", (card_id,))
|
await db.execute("DELETE FROM boltcards.cards WHERE id = ?", (card_id,))
|
||||||
# Delete hits
|
# Delete hits
|
||||||
hits = await get_hits([card_id])
|
hits = await get_hits([card_id])
|
||||||
@ -146,7 +145,7 @@ async def update_card_counter(counter: int, id: str):
|
|||||||
|
|
||||||
|
|
||||||
async def enable_disable_card(enable: bool, id: str) -> Optional[Card]:
|
async def enable_disable_card(enable: bool, id: str) -> Optional[Card]:
|
||||||
row = await db.execute(
|
await db.execute(
|
||||||
"UPDATE boltcards.cards SET enable = ? WHERE id = ?",
|
"UPDATE boltcards.cards SET enable = ? WHERE id = ?",
|
||||||
(enable, id),
|
(enable, id),
|
||||||
)
|
)
|
||||||
@ -161,7 +160,7 @@ async def update_card_otp(otp: str, id: str):
|
|||||||
|
|
||||||
|
|
||||||
async def get_hit(hit_id: str) -> Optional[Hit]:
|
async def get_hit(hit_id: str) -> Optional[Hit]:
|
||||||
row = await db.fetchone(f"SELECT * FROM boltcards.hits WHERE id = ?", (hit_id))
|
row = await db.fetchone(f"SELECT * FROM boltcards.hits WHERE id = ?", (hit_id,))
|
||||||
if not row:
|
if not row:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -182,7 +181,7 @@ async def get_hits(cards_ids: Union[str, List[str]]) -> List[Hit]:
|
|||||||
return [Hit(**row) for row in rows]
|
return [Hit(**row) for row in rows]
|
||||||
|
|
||||||
|
|
||||||
async def get_hits_today(card_id: str) -> Optional[Hit]:
|
async def get_hits_today(card_id: str) -> List[Hit]:
|
||||||
rows = await db.fetchall(
|
rows = await db.fetchall(
|
||||||
f"SELECT * FROM boltcards.hits WHERE card_id = ?",
|
f"SELECT * FROM boltcards.hits WHERE card_id = ?",
|
||||||
(card_id,),
|
(card_id,),
|
||||||
@ -259,7 +258,7 @@ async def create_refund(hit_id, refund_amount) -> Refund:
|
|||||||
|
|
||||||
async def get_refund(refund_id: str) -> Optional[Refund]:
|
async def get_refund(refund_id: str) -> Optional[Refund]:
|
||||||
row = await db.fetchone(
|
row = await db.fetchone(
|
||||||
f"SELECT * FROM boltcards.refunds WHERE id = ?", (refund_id)
|
f"SELECT * FROM boltcards.refunds WHERE id = ?", (refund_id,)
|
||||||
)
|
)
|
||||||
if not row:
|
if not row:
|
||||||
return None
|
return None
|
||||||
@ -267,7 +266,7 @@ async def get_refund(refund_id: str) -> Optional[Refund]:
|
|||||||
return Refund.parse_obj(refund)
|
return Refund.parse_obj(refund)
|
||||||
|
|
||||||
|
|
||||||
async def get_refunds(hits_ids: Union[str, List[str]]) -> List[Refund]:
|
async def get_refunds(hits_ids: List[Hit]) -> List[Refund]:
|
||||||
if len(hits_ids) == 0:
|
if len(hits_ids) == 0:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@ -3,13 +3,9 @@ import secrets
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import HTTPException, Query, Request
|
||||||
from fastapi.param_functions import Query
|
from lnurl import encode as lnurl_encode
|
||||||
from fastapi.params import Depends, Query
|
from lnurl.types import LnurlPayMetadata
|
||||||
from lnurl import encode as lnurl_encode # type: ignore
|
|
||||||
from lnurl.types import LnurlPayMetadata # type: ignore
|
|
||||||
from starlette.exceptions import HTTPException
|
|
||||||
from starlette.requests import Request
|
|
||||||
from starlette.responses import HTMLResponse
|
from starlette.responses import HTMLResponse
|
||||||
|
|
||||||
from lnbits import bolt11
|
from lnbits import bolt11
|
||||||
@ -28,14 +24,13 @@ from .crud import (
|
|||||||
update_card_counter,
|
update_card_counter,
|
||||||
update_card_otp,
|
update_card_otp,
|
||||||
)
|
)
|
||||||
from .models import CreateCardData
|
|
||||||
from .nxp424 import decryptSUN, getSunMAC
|
from .nxp424 import decryptSUN, getSunMAC
|
||||||
|
|
||||||
###############LNURLWITHDRAW#################
|
###############LNURLWITHDRAW#################
|
||||||
|
|
||||||
# /boltcards/api/v1/scan?p=00000000000000000000000000000000&c=0000000000000000
|
# /boltcards/api/v1/scan?p=00000000000000000000000000000000&c=0000000000000000
|
||||||
@boltcards_ext.get("/api/v1/scan/{external_id}")
|
@boltcards_ext.get("/api/v1/scan/{external_id}")
|
||||||
async def api_scan(p, c, request: Request, external_id: str = None):
|
async def api_scan(p, c, request: Request, external_id: str = Query(None)):
|
||||||
# some wallets send everything as lower case, no bueno
|
# some wallets send everything as lower case, no bueno
|
||||||
p = p.upper()
|
p = p.upper()
|
||||||
c = c.upper()
|
c = c.upper()
|
||||||
@ -63,6 +58,7 @@ async def api_scan(p, c, request: Request, external_id: str = None):
|
|||||||
await update_card_counter(ctr_int, card.id)
|
await update_card_counter(ctr_int, card.id)
|
||||||
|
|
||||||
# gathering some info for hit record
|
# gathering some info for hit record
|
||||||
|
assert request.client
|
||||||
ip = request.client.host
|
ip = request.client.host
|
||||||
if "x-real-ip" in request.headers:
|
if "x-real-ip" in request.headers:
|
||||||
ip = request.headers["x-real-ip"]
|
ip = request.headers["x-real-ip"]
|
||||||
@ -95,7 +91,6 @@ async def api_scan(p, c, request: Request, external_id: str = None):
|
|||||||
name="boltcards.lnurl_callback",
|
name="boltcards.lnurl_callback",
|
||||||
)
|
)
|
||||||
async def lnurl_callback(
|
async def lnurl_callback(
|
||||||
request: Request,
|
|
||||||
pr: str = Query(None),
|
pr: str = Query(None),
|
||||||
k1: str = Query(None),
|
k1: str = Query(None),
|
||||||
):
|
):
|
||||||
@ -120,7 +115,9 @@ async def lnurl_callback(
|
|||||||
return {"status": "ERROR", "reason": "Failed to decode payment request"}
|
return {"status": "ERROR", "reason": "Failed to decode payment request"}
|
||||||
|
|
||||||
card = await get_card(hit.card_id)
|
card = await get_card(hit.card_id)
|
||||||
|
assert card
|
||||||
hit = await spend_hit(id=hit.id, amount=int(invoice.amount_msat / 1000))
|
hit = await spend_hit(id=hit.id, amount=int(invoice.amount_msat / 1000))
|
||||||
|
assert hit
|
||||||
try:
|
try:
|
||||||
await pay_invoice(
|
await pay_invoice(
|
||||||
wallet_id=card.wallet,
|
wallet_id=card.wallet,
|
||||||
@ -155,7 +152,7 @@ async def api_auth(a, request: Request):
|
|||||||
|
|
||||||
response = {
|
response = {
|
||||||
"card_name": card.card_name,
|
"card_name": card.card_name,
|
||||||
"id": 1,
|
"id": str(1),
|
||||||
"k0": card.k0,
|
"k0": card.k0,
|
||||||
"k1": card.k1,
|
"k1": card.k1,
|
||||||
"k2": card.k2,
|
"k2": card.k2,
|
||||||
@ -163,7 +160,7 @@ async def api_auth(a, request: Request):
|
|||||||
"k4": card.k2,
|
"k4": card.k2,
|
||||||
"lnurlw_base": "lnurlw://" + lnurlw_base,
|
"lnurlw_base": "lnurlw://" + lnurlw_base,
|
||||||
"protocol_name": "new_bolt_card_response",
|
"protocol_name": "new_bolt_card_response",
|
||||||
"protocol_version": 1,
|
"protocol_version": str(1),
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
@ -179,7 +176,9 @@ async def api_auth(a, request: Request):
|
|||||||
)
|
)
|
||||||
async def lnurlp_response(req: Request, hit_id: str = Query(None)):
|
async def lnurlp_response(req: Request, hit_id: str = Query(None)):
|
||||||
hit = await get_hit(hit_id)
|
hit = await get_hit(hit_id)
|
||||||
|
assert hit
|
||||||
card = await get_card(hit.card_id)
|
card = await get_card(hit.card_id)
|
||||||
|
assert card
|
||||||
if not hit:
|
if not hit:
|
||||||
return {"status": "ERROR", "reason": f"LNURL-pay record not found."}
|
return {"status": "ERROR", "reason": f"LNURL-pay record not found."}
|
||||||
if not card.enable:
|
if not card.enable:
|
||||||
@ -199,17 +198,17 @@ async def lnurlp_response(req: Request, hit_id: str = Query(None)):
|
|||||||
response_class=HTMLResponse,
|
response_class=HTMLResponse,
|
||||||
name="boltcards.lnurlp_callback",
|
name="boltcards.lnurlp_callback",
|
||||||
)
|
)
|
||||||
async def lnurlp_callback(
|
async def lnurlp_callback(hit_id: str = Query(None), amount: str = Query(None)):
|
||||||
req: Request, hit_id: str = Query(None), amount: str = Query(None)
|
|
||||||
):
|
|
||||||
hit = await get_hit(hit_id)
|
hit = await get_hit(hit_id)
|
||||||
|
assert hit
|
||||||
card = await get_card(hit.card_id)
|
card = await get_card(hit.card_id)
|
||||||
|
assert card
|
||||||
if not hit:
|
if not hit:
|
||||||
return {"status": "ERROR", "reason": f"LNURL-pay record not found."}
|
return {"status": "ERROR", "reason": f"LNURL-pay record not found."}
|
||||||
|
|
||||||
payment_hash, payment_request = await create_invoice(
|
_, payment_request = await create_invoice(
|
||||||
wallet_id=card.wallet,
|
wallet_id=card.wallet,
|
||||||
amount=int(amount) / 1000,
|
amount=int(int(amount) / 1000),
|
||||||
memo=f"Refund {hit_id}",
|
memo=f"Refund {hit_id}",
|
||||||
unhashed_description=LnurlPayMetadata(
|
unhashed_description=LnurlPayMetadata(
|
||||||
json.dumps([["text/plain", "Refund"]])
|
json.dumps([["text/plain", "Refund"]])
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
|
import json
|
||||||
from sqlite3 import Row
|
from sqlite3 import Row
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Query, Request
|
||||||
from fastapi.params import Query
|
|
||||||
from lnurl import Lnurl
|
from lnurl import Lnurl
|
||||||
from lnurl import encode as lnurl_encode # type: ignore
|
from lnurl import encode as lnurl_encode
|
||||||
from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore
|
from lnurl.types import LnurlPayMetadata
|
||||||
from lnurl.types import LnurlPayMetadata # type: ignore
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from pydantic.main import BaseModel
|
|
||||||
|
|
||||||
ZERO_KEY = "00000000000000000000000000000000"
|
ZERO_KEY = "00000000000000000000000000000000"
|
||||||
|
|
||||||
@ -32,6 +29,7 @@ class Card(BaseModel):
|
|||||||
otp: str
|
otp: str
|
||||||
time: int
|
time: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
def from_row(cls, row: Row) -> "Card":
|
def from_row(cls, row: Row) -> "Card":
|
||||||
return cls(**dict(row))
|
return cls(**dict(row))
|
||||||
|
|
||||||
@ -40,7 +38,7 @@ class Card(BaseModel):
|
|||||||
return lnurl_encode(url)
|
return lnurl_encode(url)
|
||||||
|
|
||||||
async def lnurlpay_metadata(self) -> LnurlPayMetadata:
|
async def lnurlpay_metadata(self) -> LnurlPayMetadata:
|
||||||
return LnurlPayMetadata(json.dumps([["text/plain", self.title]]))
|
return LnurlPayMetadata(json.dumps([["text/plain", self.card_name]]))
|
||||||
|
|
||||||
|
|
||||||
class CreateCardData(BaseModel):
|
class CreateCardData(BaseModel):
|
||||||
@ -69,6 +67,7 @@ class Hit(BaseModel):
|
|||||||
amount: int
|
amount: int
|
||||||
time: int
|
time: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
def from_row(cls, row: Row) -> "Hit":
|
def from_row(cls, row: Row) -> "Hit":
|
||||||
return cls(**dict(row))
|
return cls(**dict(row))
|
||||||
|
|
||||||
@ -79,5 +78,6 @@ class Refund(BaseModel):
|
|||||||
refund_amount: int
|
refund_amount: int
|
||||||
time: int
|
time: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
def from_row(cls, row: Row) -> "Refund":
|
def from_row(cls, row: Row) -> "Refund":
|
||||||
return cls(**dict(row))
|
return cls(**dict(row))
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
from lnbits.core import db as core_db
|
from lnbits.core import db as core_db
|
||||||
from lnbits.core.models import Payment
|
from lnbits.core.models import Payment
|
||||||
from lnbits.helpers import get_current_extension_name
|
from lnbits.helpers import get_current_extension_name
|
||||||
@ -21,22 +19,23 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
|
|
||||||
if not payment.extra.get("refund"):
|
if not payment.extra.get("refund"):
|
||||||
return
|
return
|
||||||
|
|
||||||
if payment.extra.get("wh_status"):
|
if payment.extra.get("wh_status"):
|
||||||
# this webhook has already been sent
|
# this webhook has already been sent
|
||||||
return
|
return
|
||||||
hit = await get_hit(payment.extra.get("refund"))
|
|
||||||
|
hit = await get_hit(str(payment.extra.get("refund")))
|
||||||
|
|
||||||
if hit:
|
if hit:
|
||||||
refund = await create_refund(
|
await create_refund(hit_id=hit.id, refund_amount=(payment.amount / 1000))
|
||||||
hit_id=hit.id, refund_amount=(payment.amount / 1000)
|
|
||||||
)
|
|
||||||
await mark_webhook_sent(payment, 1)
|
await mark_webhook_sent(payment, 1)
|
||||||
|
|
||||||
|
|
||||||
async def mark_webhook_sent(payment: Payment, status: int) -> None:
|
async def mark_webhook_sent(payment: Payment, status: int) -> None:
|
||||||
|
|
||||||
payment.extra["wh_status"] = status
|
payment.extra["wh_status"] = status
|
||||||
|
|
||||||
await core_db.execute(
|
await core_db.execute(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
from fastapi import FastAPI, Request
|
from fastapi import Depends, Request
|
||||||
from fastapi.params import Depends
|
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from starlette.responses import HTMLResponse
|
from starlette.responses import HTMLResponse
|
||||||
|
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
import secrets
|
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi.params import Depends, Query
|
from fastapi import Depends, HTTPException, Query
|
||||||
from loguru import logger
|
|
||||||
from starlette.exceptions import HTTPException
|
|
||||||
from starlette.requests import Request
|
|
||||||
|
|
||||||
from lnbits.core.crud import get_user
|
from lnbits.core.crud import get_user
|
||||||
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
|
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
|
||||||
@ -15,13 +11,11 @@ from .crud import (
|
|||||||
delete_card,
|
delete_card,
|
||||||
enable_disable_card,
|
enable_disable_card,
|
||||||
get_card,
|
get_card,
|
||||||
get_card_by_otp,
|
|
||||||
get_card_by_uid,
|
get_card_by_uid,
|
||||||
get_cards,
|
get_cards,
|
||||||
get_hits,
|
get_hits,
|
||||||
get_refunds,
|
get_refunds,
|
||||||
update_card,
|
update_card,
|
||||||
update_card_otp,
|
|
||||||
)
|
)
|
||||||
from .models import CreateCardData
|
from .models import CreateCardData
|
||||||
|
|
||||||
@ -33,7 +27,8 @@ async def api_cards(
|
|||||||
wallet_ids = [g.wallet.id]
|
wallet_ids = [g.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
wallet_ids = (await get_user(g.wallet.user)).wallet_ids
|
user = await get_user(g.wallet.user)
|
||||||
|
wallet_ids = user.wallet_ids if user else []
|
||||||
|
|
||||||
return [card.dict() for card in await get_cards(wallet_ids)]
|
return [card.dict() for card in await get_cards(wallet_ids)]
|
||||||
|
|
||||||
@ -41,9 +36,8 @@ async def api_cards(
|
|||||||
@boltcards_ext.post("/api/v1/cards", status_code=HTTPStatus.CREATED)
|
@boltcards_ext.post("/api/v1/cards", status_code=HTTPStatus.CREATED)
|
||||||
@boltcards_ext.put("/api/v1/cards/{card_id}", status_code=HTTPStatus.OK)
|
@boltcards_ext.put("/api/v1/cards/{card_id}", status_code=HTTPStatus.OK)
|
||||||
async def api_card_create_or_update(
|
async def api_card_create_or_update(
|
||||||
# req: Request,
|
|
||||||
data: CreateCardData,
|
data: CreateCardData,
|
||||||
card_id: str = None,
|
card_id: str = Query(None),
|
||||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
@ -95,6 +89,7 @@ async def api_card_create_or_update(
|
|||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST,
|
||||||
)
|
)
|
||||||
card = await create_card(wallet_id=wallet.wallet.id, data=data)
|
card = await create_card(wallet_id=wallet.wallet.id, data=data)
|
||||||
|
assert card
|
||||||
return card.dict()
|
return card.dict()
|
||||||
|
|
||||||
|
|
||||||
@ -110,6 +105,7 @@ async def enable_card(
|
|||||||
if card.wallet != wallet.wallet.id:
|
if card.wallet != wallet.wallet.id:
|
||||||
raise HTTPException(detail="Not your card.", status_code=HTTPStatus.FORBIDDEN)
|
raise HTTPException(detail="Not your card.", status_code=HTTPStatus.FORBIDDEN)
|
||||||
card = await enable_disable_card(enable=enable, id=card_id)
|
card = await enable_disable_card(enable=enable, id=card_id)
|
||||||
|
assert card
|
||||||
return card.dict()
|
return card.dict()
|
||||||
|
|
||||||
|
|
||||||
@ -136,7 +132,8 @@ async def api_hits(
|
|||||||
wallet_ids = [g.wallet.id]
|
wallet_ids = [g.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
wallet_ids = (await get_user(g.wallet.user)).wallet_ids
|
user = await get_user(g.wallet.user)
|
||||||
|
wallet_ids = user.wallet_ids if user else []
|
||||||
|
|
||||||
cards = await get_cards(wallet_ids)
|
cards = await get_cards(wallet_ids)
|
||||||
cards_ids = []
|
cards_ids = []
|
||||||
@ -153,15 +150,13 @@ async def api_refunds(
|
|||||||
wallet_ids = [g.wallet.id]
|
wallet_ids = [g.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
wallet_ids = (await get_user(g.wallet.user)).wallet_ids
|
user = await get_user(g.wallet.user)
|
||||||
|
wallet_ids = user.wallet_ids if user else []
|
||||||
|
|
||||||
cards = await get_cards(wallet_ids)
|
cards = await get_cards(wallet_ids)
|
||||||
cards_ids = []
|
cards_ids = []
|
||||||
for card in cards:
|
for card in cards:
|
||||||
cards_ids.append(card.id)
|
cards_ids.append(card.id)
|
||||||
hits = await get_hits(cards_ids)
|
hits = await get_hits(cards_ids)
|
||||||
hits_ids = []
|
|
||||||
for hit in hits:
|
|
||||||
hits_ids.append(hit.id)
|
|
||||||
|
|
||||||
return [refund.dict() for refund in await get_refunds(hits_ids)]
|
return [refund.dict() for refund in await get_refunds(hits)]
|
||||||
|
@ -28,6 +28,7 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if payment.extra and not payment.extra.get("tag") == "cashu":
|
if payment.extra.get("tag") != "cashu":
|
||||||
return
|
return
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -24,12 +24,12 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
webhook = None
|
if payment.extra.get("tag") != "copilot":
|
||||||
data = None
|
|
||||||
if not payment.extra or payment.extra.get("tag") != "copilot":
|
|
||||||
# not an copilot invoice
|
# not an copilot invoice
|
||||||
return
|
return
|
||||||
|
|
||||||
|
webhook = None
|
||||||
|
data = None
|
||||||
copilot = await get_copilot(payment.extra.get("copilotid", -1))
|
copilot = await get_copilot(payment.extra.get("copilotid", -1))
|
||||||
|
|
||||||
if not copilot:
|
if not copilot:
|
||||||
|
@ -122,7 +122,7 @@ async def get_mempool_info(endPoint: str, gerty) -> dict:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
return response.json()
|
return response.json()
|
||||||
if int(time.time()) - row.time > 20:
|
if float(time.time()) - row.time > 20:
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
response = await client.get(gerty.mempool_endpoint + url)
|
response = await client.get(gerty.mempool_endpoint + url)
|
||||||
await db.execute(
|
await db.execute(
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
async def m001_initial(db):
|
async def m001_initial(db):
|
||||||
"""
|
"""
|
||||||
Initial Gertys table.
|
Initial Gertys table.
|
||||||
@ -57,3 +60,46 @@ async def m005_add_gerty_model_col(db):
|
|||||||
support for Gerty model col
|
support for Gerty model col
|
||||||
"""
|
"""
|
||||||
await db.execute("ALTER TABLE gerty.gertys ADD COLUMN urls TEXT;")
|
await db.execute("ALTER TABLE gerty.gertys ADD COLUMN urls TEXT;")
|
||||||
|
|
||||||
|
|
||||||
|
async def m006_add_gerty_model_col(db):
|
||||||
|
"""
|
||||||
|
Add UUID ID's to links and migrates existing data
|
||||||
|
"""
|
||||||
|
await db.execute("ALTER TABLE gerty.mempool RENAME TO mempool_old")
|
||||||
|
await db.execute(
|
||||||
|
f"""
|
||||||
|
CREATE TABLE gerty.mempool (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
mempool_endpoint TEXT NOT NULL,
|
||||||
|
endpoint TEXT NOT NULL,
|
||||||
|
data TEXT NOT NULL,
|
||||||
|
time FLOAT
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in [
|
||||||
|
list(row) for row in await db.fetchall("SELECT * FROM gerty.mempool_old")
|
||||||
|
]:
|
||||||
|
await db.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO gerty.mempool (
|
||||||
|
id,
|
||||||
|
mempool_endpoint,
|
||||||
|
endpoint,
|
||||||
|
data,
|
||||||
|
time
|
||||||
|
)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
""",
|
||||||
|
(
|
||||||
|
row[0],
|
||||||
|
row[1],
|
||||||
|
row[2],
|
||||||
|
row[3],
|
||||||
|
time.time(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
await db.execute("DROP TABLE gerty.mempool_old")
|
||||||
|
@ -6,7 +6,7 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %}
|
|||||||
v-if="fun_exchange_market_rate || fun_satoshi_quotes"
|
v-if="fun_exchange_market_rate || fun_satoshi_quotes"
|
||||||
>
|
>
|
||||||
<q-card
|
<q-card
|
||||||
v-if="fun_exchange_market_rate"
|
v-if="fun_exchange_market_rate['unit'] != ''"
|
||||||
unelevated
|
unelevated
|
||||||
class="q-pa-sm"
|
class="q-pa-sm"
|
||||||
style="background: none !important"
|
style="background: none !important"
|
||||||
@ -96,7 +96,7 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %}
|
|||||||
</p>
|
</p>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
<q-card class="q-pa-sm" v-if="url_checker" unelevated class="q-pa-sm">
|
<q-card class="q-pa-sm" v-if="url_checker[0]" unelevated class="q-pa-sm">
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<div class="text-h6">Servers to check</div>
|
<div class="text-h6">Servers to check</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
@ -126,7 +126,7 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %}
|
|||||||
v-else-if="item[1].value >= 300"
|
v-else-if="item[1].value >= 300"
|
||||||
square
|
square
|
||||||
size="sm"
|
size="sm"
|
||||||
color="yellow"
|
color="orange"
|
||||||
text-color="white"
|
text-color="white"
|
||||||
icon="sentiment_dissatisfied"
|
icon="sentiment_dissatisfied"
|
||||||
>
|
>
|
||||||
|
@ -25,9 +25,6 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if not payment.extra:
|
|
||||||
return
|
|
||||||
|
|
||||||
if payment.extra.get("tag") != "invoices":
|
if payment.extra.get("tag") != "invoices":
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if payment.extra:
|
if payment.extra.get("tag") != "jukebox":
|
||||||
if payment.extra.get("tag") != "jukebox":
|
# not a jukebox invoice
|
||||||
# not a jukebox invoice
|
return
|
||||||
return
|
|
||||||
await update_jukebox_payment(payment.payment_hash, paid=True)
|
await update_jukebox_payment(payment.payment_hash, paid=True)
|
||||||
|
@ -16,7 +16,7 @@ async def cloudflare_create_record(domain: Domains, ip: str):
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
|
|
||||||
cf_response = ""
|
cf_response = {}
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
try:
|
try:
|
||||||
r = await client.post(
|
r = await client.post(
|
||||||
@ -31,9 +31,9 @@ async def cloudflare_create_record(domain: Domains, ip: str):
|
|||||||
},
|
},
|
||||||
timeout=40,
|
timeout=40,
|
||||||
)
|
)
|
||||||
cf_response = json.loads(r.text)
|
cf_response = r.json()
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
cf_response = "Error occured"
|
cf_response = {"error": "Error occured"}
|
||||||
return cf_response
|
return cf_response
|
||||||
|
|
||||||
|
|
||||||
@ -53,3 +53,4 @@ async def cloudflare_deleterecord(domain: Domains, domain_id: str):
|
|||||||
cf_response = r.text
|
cf_response = r.text
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
cf_response = "Error occured"
|
cf_response = "Error occured"
|
||||||
|
return cf_response
|
||||||
|
@ -128,6 +128,7 @@ async def get_addresses(wallet_ids: Union[str, List[str]]) -> List[Addresses]:
|
|||||||
|
|
||||||
async def set_address_paid(payment_hash: str) -> Addresses:
|
async def set_address_paid(payment_hash: str) -> Addresses:
|
||||||
address = await get_address(payment_hash)
|
address = await get_address(payment_hash)
|
||||||
|
assert address
|
||||||
|
|
||||||
if address.paid == False:
|
if address.paid == False:
|
||||||
await db.execute(
|
await db.execute(
|
||||||
@ -146,6 +147,7 @@ async def set_address_paid(payment_hash: str) -> Addresses:
|
|||||||
|
|
||||||
async def set_address_renewed(address_id: str, duration: int):
|
async def set_address_renewed(address_id: str, duration: int):
|
||||||
address = await get_address(address_id)
|
address = await get_address(address_id)
|
||||||
|
assert address
|
||||||
|
|
||||||
extend_duration = int(address.duration) + duration
|
extend_duration = int(address.duration) + duration
|
||||||
await db.execute(
|
await db.execute(
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
import hashlib
|
|
||||||
import json
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from fastapi.params import Query
|
from fastapi import Query, Request
|
||||||
from lnurl import ( # type: ignore
|
from lnurl import LnurlErrorResponse
|
||||||
LnurlErrorResponse,
|
|
||||||
LnurlPayActionResponse,
|
|
||||||
LnurlPayResponse,
|
|
||||||
)
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from starlette.requests import Request
|
|
||||||
from starlette.responses import HTMLResponse
|
|
||||||
|
|
||||||
from . import lnaddress_ext
|
from . import lnaddress_ext
|
||||||
from .crud import get_address, get_address_by_username, get_domain
|
from .crud import get_address, get_address_by_username, get_domain
|
||||||
@ -52,6 +44,7 @@ async def lnurl_callback(address_id, amount: int = Query(...)):
|
|||||||
amount_received = amount
|
amount_received = amount
|
||||||
|
|
||||||
domain = await get_domain(address.domain)
|
domain = await get_domain(address.domain)
|
||||||
|
assert domain
|
||||||
|
|
||||||
base_url = (
|
base_url = (
|
||||||
address.wallet_endpoint[:-1]
|
address.wallet_endpoint[:-1]
|
||||||
@ -79,7 +72,7 @@ async def lnurl_callback(address_id, amount: int = Query(...)):
|
|||||||
)
|
)
|
||||||
|
|
||||||
r = call.json()
|
r = call.json()
|
||||||
except AssertionError as e:
|
except Exception:
|
||||||
return LnurlErrorResponse(reason="ERROR")
|
return LnurlErrorResponse(reason="ERROR")
|
||||||
|
|
||||||
# resp = LnurlPayActionResponse(pr=r["payment_request"], routes=[])
|
# resp = LnurlPayActionResponse(pr=r["payment_request"], routes=[])
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import json
|
import json
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi.params import Query
|
from fastapi import Query
|
||||||
from lnurl.types import LnurlPayMetadata
|
from lnurl.types import LnurlPayMetadata
|
||||||
from pydantic.main import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class CreateDomain(BaseModel):
|
class CreateDomain(BaseModel):
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from lnbits.core.models import Payment
|
from lnbits.core.models import Payment
|
||||||
from lnbits.helpers import get_current_extension_name
|
from lnbits.helpers import get_current_extension_name
|
||||||
@ -21,7 +22,9 @@ async def wait_for_paid_invoices():
|
|||||||
async def call_webhook_on_paid(payment_hash):
|
async def call_webhook_on_paid(payment_hash):
|
||||||
### Use webhook to notify about cloudflare registration
|
### Use webhook to notify about cloudflare registration
|
||||||
address = await get_address(payment_hash)
|
address = await get_address(payment_hash)
|
||||||
|
assert address
|
||||||
domain = await get_domain(address.domain)
|
domain = await get_domain(address.domain)
|
||||||
|
assert domain
|
||||||
|
|
||||||
if not domain.webhook:
|
if not domain.webhook:
|
||||||
return
|
return
|
||||||
@ -39,24 +42,23 @@ async def call_webhook_on_paid(payment_hash):
|
|||||||
},
|
},
|
||||||
timeout=40,
|
timeout=40,
|
||||||
)
|
)
|
||||||
except AssertionError:
|
r.raise_for_status()
|
||||||
webhook = None
|
except Exception as e:
|
||||||
|
logger.error(f"lnaddress: error calling webhook on paid: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if payment.extra.get("tag") == "lnaddress":
|
|
||||||
|
|
||||||
|
if payment.extra.get("tag") == "lnaddress":
|
||||||
await payment.set_pending(False)
|
await payment.set_pending(False)
|
||||||
await set_address_paid(payment_hash=payment.payment_hash)
|
await set_address_paid(payment_hash=payment.payment_hash)
|
||||||
await call_webhook_on_paid(payment_hash=payment.payment_hash)
|
await call_webhook_on_paid(payment_hash=payment.payment_hash)
|
||||||
|
|
||||||
elif payment.extra.get("tag") == "renew lnaddress":
|
elif payment.extra.get("tag") == "renew lnaddress":
|
||||||
|
|
||||||
await payment.set_pending(False)
|
await payment.set_pending(False)
|
||||||
await set_address_renewed(
|
await set_address_renewed(
|
||||||
address_id=payment.extra["id"], duration=payment.extra["duration"]
|
address_id=payment.extra["id"], duration=payment.extra["duration"]
|
||||||
)
|
)
|
||||||
await call_webhook_on_paid(payment_hash=payment.payment_hash)
|
await call_webhook_on_paid(payment_hash=payment.payment_hash)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Depends, HTTPException, Request
|
||||||
from fastapi.params import Depends
|
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from starlette.exceptions import HTTPException
|
|
||||||
from starlette.responses import HTMLResponse
|
from starlette.responses import HTMLResponse
|
||||||
|
|
||||||
from lnbits.core.crud import get_wallet
|
from lnbits.core.crud import get_wallet
|
||||||
@ -35,6 +33,7 @@ async def display(domain_id, request: Request):
|
|||||||
await purge_addresses(domain_id)
|
await purge_addresses(domain_id)
|
||||||
|
|
||||||
wallet = await get_wallet(domain.wallet)
|
wallet = await get_wallet(domain.wallet)
|
||||||
|
assert wallet
|
||||||
url = urlparse(str(request.url))
|
url = urlparse(str(request.url))
|
||||||
|
|
||||||
return lnaddress_renderer().TemplateResponse(
|
return lnaddress_renderer().TemplateResponse(
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Depends, HTTPException, Query, Request
|
||||||
from fastapi.params import Depends, Query
|
|
||||||
from starlette.exceptions import HTTPException
|
|
||||||
|
|
||||||
from lnbits.core.crud import get_user
|
from lnbits.core.crud import get_user
|
||||||
from lnbits.core.services import check_transaction_status, create_invoice
|
from lnbits.core.services import check_transaction_status, create_invoice
|
||||||
@ -11,7 +9,7 @@ from lnbits.decorators import WalletTypeInfo, get_key_type
|
|||||||
from lnbits.extensions.lnaddress.models import CreateAddress, CreateDomain
|
from lnbits.extensions.lnaddress.models import CreateAddress, CreateDomain
|
||||||
|
|
||||||
from . import lnaddress_ext
|
from . import lnaddress_ext
|
||||||
from .cloudflare import cloudflare_create_record, cloudflare_deleterecord
|
from .cloudflare import cloudflare_create_record
|
||||||
from .crud import (
|
from .crud import (
|
||||||
check_address_available,
|
check_address_available,
|
||||||
create_address,
|
create_address,
|
||||||
@ -35,7 +33,8 @@ async def api_domains(
|
|||||||
wallet_ids = [g.wallet.id]
|
wallet_ids = [g.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
wallet_ids = (await get_user(g.wallet.user)).wallet_ids
|
user = await get_user(g.wallet.user)
|
||||||
|
wallet_ids = user.wallet_ids if user else []
|
||||||
|
|
||||||
return [domain.dict() for domain in await get_domains(wallet_ids)]
|
return [domain.dict() for domain in await get_domains(wallet_ids)]
|
||||||
|
|
||||||
@ -69,7 +68,7 @@ async def api_domain_create(
|
|||||||
|
|
||||||
cf_response = await cloudflare_create_record(domain=domain, ip=root_url)
|
cf_response = await cloudflare_create_record(domain=domain, ip=root_url)
|
||||||
|
|
||||||
if not cf_response or cf_response["success"] != True:
|
if not cf_response or not cf_response["success"]:
|
||||||
await delete_domain(domain.id)
|
await delete_domain(domain.id)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST,
|
||||||
@ -106,7 +105,8 @@ async def api_addresses(
|
|||||||
wallet_ids = [g.wallet.id]
|
wallet_ids = [g.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
wallet_ids = (await get_user(g.wallet.user)).wallet_ids
|
user = await get_user(g.wallet.user)
|
||||||
|
wallet_ids = user.wallet_ids if user else []
|
||||||
|
|
||||||
return [address.dict() for address in await get_addresses(wallet_ids)]
|
return [address.dict() for address in await get_addresses(wallet_ids)]
|
||||||
|
|
||||||
@ -227,7 +227,9 @@ async def api_lnaddress_make_address(
|
|||||||
@lnaddress_ext.get("/api/v1/addresses/{payment_hash}")
|
@lnaddress_ext.get("/api/v1/addresses/{payment_hash}")
|
||||||
async def api_address_send_address(payment_hash):
|
async def api_address_send_address(payment_hash):
|
||||||
address = await get_address(payment_hash)
|
address = await get_address(payment_hash)
|
||||||
|
assert address
|
||||||
domain = await get_domain(address.domain)
|
domain = await get_domain(address.domain)
|
||||||
|
assert domain
|
||||||
try:
|
try:
|
||||||
status = await check_transaction_status(domain.wallet, payment_hash)
|
status = await check_transaction_status(domain.wallet, payment_hash)
|
||||||
is_paid = not status.pending
|
is_paid = not status.pending
|
||||||
|
@ -19,7 +19,7 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if not payment.extra or payment.extra.get("tag") != "lnticket":
|
if payment.extra.get("tag") != "lnticket":
|
||||||
# not a lnticket invoice
|
# not a lnticket invoice
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -120,7 +120,11 @@ async def create_lnurldevicepayment(
|
|||||||
payhash: Optional[str] = None,
|
payhash: Optional[str] = None,
|
||||||
sats: Optional[int] = 0,
|
sats: Optional[int] = 0,
|
||||||
) -> lnurldevicepayment:
|
) -> lnurldevicepayment:
|
||||||
lnurldevicepayment_id = urlsafe_short_hash()
|
device = await get_lnurldevice(deviceid)
|
||||||
|
if device.device == "atm":
|
||||||
|
lnurldevicepayment_id = shortuuid.uuid(name=payload)
|
||||||
|
else:
|
||||||
|
lnurldevicepayment_id = urlsafe_short_hash()
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO lnurldevice.lnurldevicepayment (
|
INSERT INTO lnurldevice.lnurldevicepayment (
|
||||||
|
@ -5,12 +5,14 @@ from http import HTTPStatus
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
import shortuuid
|
||||||
from embit import bech32, compact
|
from embit import bech32, compact
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from fastapi.param_functions import Query
|
from fastapi.param_functions import Query
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
|
|
||||||
|
from lnbits import bolt11
|
||||||
from lnbits.core.services import create_invoice
|
from lnbits.core.services import create_invoice
|
||||||
from lnbits.core.views.api import pay_invoice
|
from lnbits.core.views.api import pay_invoice
|
||||||
from lnbits.utils.exchange_rates import fiat_amount_as_satoshis
|
from lnbits.utils.exchange_rates import fiat_amount_as_satoshis
|
||||||
@ -102,11 +104,6 @@ async def lnurl_v1_params(
|
|||||||
"status": "ERROR",
|
"status": "ERROR",
|
||||||
"reason": f"lnurldevice {device_id} not found on this server",
|
"reason": f"lnurldevice {device_id} not found on this server",
|
||||||
}
|
}
|
||||||
paymentcheck = await get_lnurlpayload(p)
|
|
||||||
if device.device == "atm":
|
|
||||||
if paymentcheck:
|
|
||||||
if paymentcheck.payhash != "payment_hash":
|
|
||||||
return {"status": "ERROR", "reason": f"Payment already claimed"}
|
|
||||||
if device.device == "switch":
|
if device.device == "switch":
|
||||||
price_msat = (
|
price_msat = (
|
||||||
await fiat_amount_as_satoshis(float(profit), device.currency)
|
await fiat_amount_as_satoshis(float(profit), device.currency)
|
||||||
@ -163,13 +160,21 @@ async def lnurl_v1_params(
|
|||||||
if device.device != "atm":
|
if device.device != "atm":
|
||||||
return {"status": "ERROR", "reason": "Not ATM device."}
|
return {"status": "ERROR", "reason": "Not ATM device."}
|
||||||
price_msat = int(price_msat * (1 - (device.profit / 100)) / 1000)
|
price_msat = int(price_msat * (1 - (device.profit / 100)) / 1000)
|
||||||
lnurldevicepayment = await create_lnurldevicepayment(
|
lnurldevicepayment = await get_lnurldevicepayment(shortuuid.uuid(name=p))
|
||||||
deviceid=device.id,
|
if lnurldevicepayment:
|
||||||
payload=p,
|
logger.debug("lnurldevicepayment")
|
||||||
sats=price_msat * 1000,
|
logger.debug(lnurldevicepayment)
|
||||||
pin=pin,
|
logger.debug("lnurldevicepayment")
|
||||||
payhash="payment_hash",
|
if lnurldevicepayment.payload == lnurldevicepayment.payhash:
|
||||||
)
|
return {"status": "ERROR", "reason": f"Payment already claimed"}
|
||||||
|
else:
|
||||||
|
lnurldevicepayment = await create_lnurldevicepayment(
|
||||||
|
deviceid=device.id,
|
||||||
|
payload=p,
|
||||||
|
sats=price_msat * 1000,
|
||||||
|
pin=pin,
|
||||||
|
payhash="payment_hash",
|
||||||
|
)
|
||||||
if not lnurldevicepayment:
|
if not lnurldevicepayment:
|
||||||
return {"status": "ERROR", "reason": "Could not create payment."}
|
return {"status": "ERROR", "reason": "Could not create payment."}
|
||||||
return {
|
return {
|
||||||
@ -222,15 +227,20 @@ async def lnurl_callback(
|
|||||||
status_code=HTTPStatus.FORBIDDEN, detail="lnurldevice not found."
|
status_code=HTTPStatus.FORBIDDEN, detail="lnurldevice not found."
|
||||||
)
|
)
|
||||||
if device.device == "atm":
|
if device.device == "atm":
|
||||||
|
if lnurldevicepayment.payload == lnurldevicepayment.payhash:
|
||||||
|
return {"status": "ERROR", "reason": f"Payment already claimed"}
|
||||||
if not pr:
|
if not pr:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.FORBIDDEN, detail="No payment request"
|
status_code=HTTPStatus.FORBIDDEN, detail="No payment request"
|
||||||
)
|
)
|
||||||
|
invoice = bolt11.decode(pr)
|
||||||
|
if not invoice.payment_hash:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=HTTPStatus.FORBIDDEN, detail="Not valid payment request"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if lnurldevicepayment.payload != k1:
|
if lnurldevicepayment.payload != k1:
|
||||||
return {"status": "ERROR", "reason": "Bad K1"}
|
return {"status": "ERROR", "reason": "Bad K1"}
|
||||||
if lnurldevicepayment.payhash != "payment_hash":
|
|
||||||
return {"status": "ERROR", "reason": f"Payment already claimed"}
|
|
||||||
lnurldevicepayment = await update_lnurldevicepayment(
|
lnurldevicepayment = await update_lnurldevicepayment(
|
||||||
lnurldevicepayment_id=paymentid, payhash=lnurldevicepayment.payload
|
lnurldevicepayment_id=paymentid, payhash=lnurldevicepayment.payload
|
||||||
)
|
)
|
||||||
|
@ -22,7 +22,7 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment):
|
async def on_invoice_paid(payment: Payment):
|
||||||
if not payment.extra or payment.extra.get("tag") != "lnurlp":
|
if payment.extra.get("tag") != "lnurlp":
|
||||||
return
|
return
|
||||||
|
|
||||||
if payment.extra.get("wh_status"):
|
if payment.extra.get("wh_status"):
|
||||||
|
@ -23,9 +23,6 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if not payment.extra:
|
|
||||||
return
|
|
||||||
|
|
||||||
if payment.extra.get("tag") != "market":
|
if payment.extra.get("tag") != "market":
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if not payment.extra:
|
|
||||||
return
|
|
||||||
if payment.extra.get("tag") != "nostrnip5":
|
if payment.extra.get("tag") != "nostrnip5":
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -12,14 +12,13 @@ from . import db
|
|||||||
from .helpers import fetch_onchain_balance
|
from .helpers import fetch_onchain_balance
|
||||||
from .models import Charges, CreateCharge, SatsPayThemes
|
from .models import Charges, CreateCharge, SatsPayThemes
|
||||||
|
|
||||||
###############CHARGES##########################
|
|
||||||
|
|
||||||
|
async def create_charge(user: str, data: CreateCharge) -> Optional[Charges]:
|
||||||
async def create_charge(user: str, data: CreateCharge) -> Charges:
|
|
||||||
data = CreateCharge(**data.dict())
|
data = CreateCharge(**data.dict())
|
||||||
charge_id = urlsafe_short_hash()
|
charge_id = urlsafe_short_hash()
|
||||||
if data.onchainwallet:
|
if data.onchainwallet:
|
||||||
config = await get_config(user)
|
config = await get_config(user)
|
||||||
|
assert config
|
||||||
data.extra = json.dumps(
|
data.extra = json.dumps(
|
||||||
{"mempool_endpoint": config.mempool_endpoint, "network": config.network}
|
{"mempool_endpoint": config.mempool_endpoint, "network": config.network}
|
||||||
)
|
)
|
||||||
@ -92,7 +91,7 @@ async def update_charge(charge_id: str, **kwargs) -> Optional[Charges]:
|
|||||||
return Charges.from_row(row) if row else None
|
return Charges.from_row(row) if row else None
|
||||||
|
|
||||||
|
|
||||||
async def get_charge(charge_id: str) -> Charges:
|
async def get_charge(charge_id: str) -> Optional[Charges]:
|
||||||
row = await db.fetchone("SELECT * FROM satspay.charges WHERE id = ?", (charge_id,))
|
row = await db.fetchone("SELECT * FROM satspay.charges WHERE id = ?", (charge_id,))
|
||||||
return Charges.from_row(row) if row else None
|
return Charges.from_row(row) if row else None
|
||||||
|
|
||||||
@ -111,6 +110,7 @@ async def delete_charge(charge_id: str) -> None:
|
|||||||
|
|
||||||
async def check_address_balance(charge_id: str) -> Optional[Charges]:
|
async def check_address_balance(charge_id: str) -> Optional[Charges]:
|
||||||
charge = await get_charge(charge_id)
|
charge = await get_charge(charge_id)
|
||||||
|
assert charge
|
||||||
|
|
||||||
if not charge.paid:
|
if not charge.paid:
|
||||||
if charge.onchainaddress:
|
if charge.onchainaddress:
|
||||||
@ -131,7 +131,7 @@ async def check_address_balance(charge_id: str) -> Optional[Charges]:
|
|||||||
################## SETTINGS ###################
|
################## SETTINGS ###################
|
||||||
|
|
||||||
|
|
||||||
async def save_theme(data: SatsPayThemes, css_id: str = None):
|
async def save_theme(data: SatsPayThemes, css_id: Optional[str]):
|
||||||
# insert or update
|
# insert or update
|
||||||
if css_id:
|
if css_id:
|
||||||
await db.execute(
|
await db.execute(
|
||||||
@ -162,7 +162,7 @@ async def save_theme(data: SatsPayThemes, css_id: str = None):
|
|||||||
return await get_theme(css_id)
|
return await get_theme(css_id)
|
||||||
|
|
||||||
|
|
||||||
async def get_theme(css_id: str) -> SatsPayThemes:
|
async def get_theme(css_id: str) -> Optional[SatsPayThemes]:
|
||||||
row = await db.fetchone("SELECT * FROM satspay.themes WHERE css_id = ?", (css_id,))
|
row = await db.fetchone("SELECT * FROM satspay.themes WHERE css_id = ?", (css_id,))
|
||||||
return SatsPayThemes.from_row(row) if row else None
|
return SatsPayThemes.from_row(row) if row else None
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ def public_charge(charge: Charges):
|
|||||||
async def call_webhook(charge: Charges):
|
async def call_webhook(charge: Charges):
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
try:
|
try:
|
||||||
|
assert charge.webhook
|
||||||
r = await client.post(
|
r = await client.post(
|
||||||
charge.webhook,
|
charge.webhook,
|
||||||
json=public_charge(charge),
|
json=public_charge(charge),
|
||||||
@ -54,6 +55,8 @@ async def fetch_onchain_balance(charge: Charges):
|
|||||||
if charge.config.network == "Testnet"
|
if charge.config.network == "Testnet"
|
||||||
else charge.config.mempool_endpoint
|
else charge.config.mempool_endpoint
|
||||||
)
|
)
|
||||||
|
assert endpoint
|
||||||
|
assert charge.onchainaddress
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
r = await client.get(endpoint + "/api/address/" + charge.onchainaddress)
|
r = await client.get(endpoint + "/api/address/" + charge.onchainaddress)
|
||||||
return r.json()["chain_stats"]["funded_txo_sum"]
|
return r.json()["chain_stats"]["funded_txo_sum"]
|
||||||
|
@ -22,10 +22,12 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
|
|
||||||
if payment.extra.get("tag") != "charge":
|
if payment.extra.get("tag") != "charge":
|
||||||
# not a charge invoice
|
# not a charge invoice
|
||||||
return
|
return
|
||||||
|
|
||||||
|
assert payment.memo
|
||||||
charge = await get_charge(payment.memo)
|
charge = await get_charge(payment.memo)
|
||||||
if not charge:
|
if not charge:
|
||||||
logger.error("this should never happen", payment)
|
logger.error("this should never happen", payment)
|
||||||
@ -33,6 +35,7 @@ async def on_invoice_paid(payment: Payment) -> None:
|
|||||||
|
|
||||||
await payment.set_pending(False)
|
await payment.set_pending(False)
|
||||||
charge = await check_address_balance(charge_id=charge.id)
|
charge = await check_address_balance(charge_id=charge.id)
|
||||||
|
assert charge
|
||||||
|
|
||||||
if charge.must_call_webhook():
|
if charge.must_call_webhook():
|
||||||
resp = await call_webhook(charge)
|
resp = await call_webhook(charge)
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi import Response
|
from fastapi import Depends, HTTPException, Request, Response
|
||||||
from fastapi.param_functions import Depends
|
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from starlette.exceptions import HTTPException
|
|
||||||
from starlette.requests import Request
|
|
||||||
from starlette.responses import HTMLResponse
|
from starlette.responses import HTMLResponse
|
||||||
|
|
||||||
from lnbits.core.models import User
|
from lnbits.core.models import User
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import json
|
import json
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi import Depends, Query
|
from fastapi import Depends, HTTPException, Query
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from starlette.exceptions import HTTPException
|
|
||||||
|
|
||||||
from lnbits.decorators import (
|
from lnbits.decorators import (
|
||||||
WalletTypeInfo,
|
WalletTypeInfo,
|
||||||
@ -29,8 +28,6 @@ from .crud import (
|
|||||||
from .helpers import call_webhook, public_charge
|
from .helpers import call_webhook, public_charge
|
||||||
from .models import CreateCharge, SatsPayThemes
|
from .models import CreateCharge, SatsPayThemes
|
||||||
|
|
||||||
#############################CHARGES##########################
|
|
||||||
|
|
||||||
|
|
||||||
@satspay_ext.post("/api/v1/charge")
|
@satspay_ext.post("/api/v1/charge")
|
||||||
async def api_charge_create(
|
async def api_charge_create(
|
||||||
@ -38,6 +35,7 @@ async def api_charge_create(
|
|||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
charge = await create_charge(user=wallet.wallet.user, data=data)
|
charge = await create_charge(user=wallet.wallet.user, data=data)
|
||||||
|
assert charge
|
||||||
return {
|
return {
|
||||||
**charge.dict(),
|
**charge.dict(),
|
||||||
**{"time_elapsed": charge.time_elapsed},
|
**{"time_elapsed": charge.time_elapsed},
|
||||||
@ -51,13 +49,15 @@ async def api_charge_create(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@satspay_ext.put("/api/v1/charge/{charge_id}")
|
@satspay_ext.put(
|
||||||
|
"/api/v1/charge/{charge_id}", dependencies=[Depends(require_admin_key)]
|
||||||
|
)
|
||||||
async def api_charge_update(
|
async def api_charge_update(
|
||||||
data: CreateCharge,
|
data: CreateCharge,
|
||||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
charge_id: str,
|
||||||
charge_id=None,
|
|
||||||
):
|
):
|
||||||
charge = await update_charge(charge_id=charge_id, data=data)
|
charge = await update_charge(charge_id=charge_id, data=data)
|
||||||
|
assert charge
|
||||||
return charge.dict()
|
return charge.dict()
|
||||||
|
|
||||||
|
|
||||||
@ -78,10 +78,8 @@ async def api_charges_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@satspay_ext.get("/api/v1/charge/{charge_id}")
|
@satspay_ext.get("/api/v1/charge/{charge_id}", dependencies=[Depends(get_key_type)])
|
||||||
async def api_charge_retrieve(
|
async def api_charge_retrieve(charge_id: str):
|
||||||
charge_id, wallet: WalletTypeInfo = Depends(get_key_type)
|
|
||||||
):
|
|
||||||
charge = await get_charge(charge_id)
|
charge = await get_charge(charge_id)
|
||||||
|
|
||||||
if not charge:
|
if not charge:
|
||||||
@ -97,8 +95,8 @@ async def api_charge_retrieve(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@satspay_ext.delete("/api/v1/charge/{charge_id}")
|
@satspay_ext.delete("/api/v1/charge/{charge_id}", dependencies=[Depends(get_key_type)])
|
||||||
async def api_charge_delete(charge_id, wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_charge_delete(charge_id: str):
|
||||||
charge = await get_charge(charge_id)
|
charge = await get_charge(charge_id)
|
||||||
|
|
||||||
if not charge:
|
if not charge:
|
||||||
@ -155,7 +153,7 @@ async def api_themes_save(
|
|||||||
theme = await save_theme(css_id=css_id, data=data)
|
theme = await save_theme(css_id=css_id, data=data)
|
||||||
else:
|
else:
|
||||||
data.user = wallet.wallet.user
|
data.user = wallet.wallet.user
|
||||||
theme = await save_theme(data=data)
|
theme = await save_theme(data=data, css_id="no_id")
|
||||||
return theme
|
return theme
|
||||||
|
|
||||||
|
|
||||||
@ -169,8 +167,8 @@ async def api_themes_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@satspay_ext.delete("/api/v1/themes/{theme_id}")
|
@satspay_ext.delete("/api/v1/themes/{theme_id}", dependencies=[Depends(get_key_type)])
|
||||||
async def api_theme_delete(theme_id, wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_theme_delete(theme_id):
|
||||||
theme = await get_theme(theme_id)
|
theme = await get_theme(theme_id)
|
||||||
|
|
||||||
if not theme:
|
if not theme:
|
||||||
|
@ -27,7 +27,7 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
async def on_invoice_paid(payment: Payment):
|
async def on_invoice_paid(payment: Payment):
|
||||||
# (avoid loops)
|
# (avoid loops)
|
||||||
if payment.extra and payment.extra.get("tag") == "scrubed":
|
if payment.extra.get("tag") == "scrubed":
|
||||||
# already scrubbed
|
# already scrubbed
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if not payment.extra or payment.extra.get("tag") == "splitpayments":
|
if payment.extra.get("tag") == "splitpayments":
|
||||||
# already a splitted payment, ignore
|
# already a splitted payment, ignore
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -25,15 +25,20 @@ async def get_charge_details(service_id):
|
|||||||
|
|
||||||
These might be different depending for services implemented in the future.
|
These might be different depending for services implemented in the future.
|
||||||
"""
|
"""
|
||||||
details = {"time": 1440}
|
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
|
assert service
|
||||||
|
|
||||||
wallet_id = service.wallet
|
wallet_id = service.wallet
|
||||||
wallet = await get_wallet(wallet_id)
|
wallet = await get_wallet(wallet_id)
|
||||||
|
assert wallet
|
||||||
|
|
||||||
user = wallet.user
|
user = wallet.user
|
||||||
details["user"] = user
|
return {
|
||||||
details["lnbitswallet"] = wallet_id
|
"time": 1440,
|
||||||
details["onchainwallet"] = service.onchain
|
"user": user,
|
||||||
return details
|
"lnbitswallet": wallet_id,
|
||||||
|
"onchainwallet": service.onchain,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def create_donation(
|
async def create_donation(
|
||||||
@ -71,7 +76,7 @@ async def create_donation(
|
|||||||
return donation
|
return donation
|
||||||
|
|
||||||
|
|
||||||
async def post_donation(donation_id: str) -> tuple:
|
async def post_donation(donation_id: str) -> dict:
|
||||||
"""Post donations to their respective third party APIs
|
"""Post donations to their respective third party APIs
|
||||||
|
|
||||||
If the donation has already been posted, it will not be posted again.
|
If the donation has already been posted, it will not be posted again.
|
||||||
@ -97,7 +102,6 @@ async def post_donation(donation_id: str) -> tuple:
|
|||||||
}
|
}
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
response = await client.post(url, data=data)
|
response = await client.post(url, data=data)
|
||||||
status = [s for s in list(HTTPStatus) if s == response.status_code][0]
|
|
||||||
elif service.servicename == "StreamElements":
|
elif service.servicename == "StreamElements":
|
||||||
return {"message": "StreamElements not yet supported!"}
|
return {"message": "StreamElements not yet supported!"}
|
||||||
else:
|
else:
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
from sqlite3 import Row
|
from sqlite3 import Row
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi.params import Query
|
from fastapi import Query
|
||||||
from pydantic.main import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class CreateService(BaseModel):
|
class CreateService(BaseModel):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi.param_functions import Depends
|
from fastapi import Depends
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
from starlette.requests import Request
|
from starlette.requests import Request
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi.params import Depends, Query
|
from fastapi import Depends, Query
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
from starlette.requests import Request
|
from starlette.requests import Request
|
||||||
from starlette.responses import RedirectResponse
|
from starlette.responses import RedirectResponse
|
||||||
@ -84,6 +84,8 @@ async def api_authenticate_service(
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
|
assert service
|
||||||
|
|
||||||
if service.state != state:
|
if service.state != state:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST, detail="State doesn't match!"
|
status_code=HTTPStatus.BAD_REQUEST, detail="State doesn't match!"
|
||||||
@ -113,6 +115,7 @@ async def api_create_donation(data: CreateDonation, request: Request):
|
|||||||
webhook_base = request.url.scheme + "://" + request.headers["Host"]
|
webhook_base = request.url.scheme + "://" + request.headers["Host"]
|
||||||
service_id = data.service
|
service_id = data.service
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
|
assert service
|
||||||
charge_details = await get_charge_details(service.id)
|
charge_details = await get_charge_details(service.id)
|
||||||
name = data.name if data.name else "Anonymous"
|
name = data.name if data.name else "Anonymous"
|
||||||
|
|
||||||
@ -157,7 +160,8 @@ async def api_post_donation(request: Request, data: ValidateDonation):
|
|||||||
@streamalerts_ext.get("/api/v1/services")
|
@streamalerts_ext.get("/api/v1/services")
|
||||||
async def api_get_services(g: WalletTypeInfo = Depends(get_key_type)):
|
async def api_get_services(g: WalletTypeInfo = Depends(get_key_type)):
|
||||||
"""Return list of all services assigned to wallet with given invoice key"""
|
"""Return list of all services assigned to wallet with given invoice key"""
|
||||||
wallet_ids = (await get_user(g.wallet.user)).wallet_ids
|
user = await get_user(g.wallet.user)
|
||||||
|
wallet_ids = user.wallet_ids if user else []
|
||||||
services = []
|
services = []
|
||||||
for wallet_id in wallet_ids:
|
for wallet_id in wallet_ids:
|
||||||
new_services = await get_services(wallet_id)
|
new_services = await get_services(wallet_id)
|
||||||
@ -170,7 +174,8 @@ async def api_get_donations(g: WalletTypeInfo = Depends(get_key_type)):
|
|||||||
"""Return list of all donations assigned to wallet with given invoice
|
"""Return list of all donations assigned to wallet with given invoice
|
||||||
key
|
key
|
||||||
"""
|
"""
|
||||||
wallet_ids = (await get_user(g.wallet.user)).wallet_ids
|
user = await get_user(g.wallet.user)
|
||||||
|
wallet_ids = user.wallet_ids if user else []
|
||||||
donations = []
|
donations = []
|
||||||
for wallet_id in wallet_ids:
|
for wallet_id in wallet_ids:
|
||||||
new_donations = await get_donations(wallet_id)
|
new_donations = await get_donations(wallet_id)
|
||||||
|
@ -20,7 +20,7 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if not payment.extra or payment.extra.get("tag") != "lnsubdomain":
|
if payment.extra.get("tag") != "lnsubdomain":
|
||||||
# not an lnurlp invoice
|
# not an lnurlp invoice
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -20,8 +20,6 @@ async def wait_for_paid_invoices():
|
|||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if not payment.extra:
|
|
||||||
return
|
|
||||||
if payment.extra.get("tag") != "tpos":
|
if payment.extra.get("tag") != "tpos":
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -91,12 +91,8 @@ files = "lnbits"
|
|||||||
exclude = """(?x)(
|
exclude = """(?x)(
|
||||||
^lnbits/extensions/bleskomat.
|
^lnbits/extensions/bleskomat.
|
||||||
| ^lnbits/extensions/boltz.
|
| ^lnbits/extensions/boltz.
|
||||||
| ^lnbits/extensions/boltcards.
|
|
||||||
| ^lnbits/extensions/livestream.
|
| ^lnbits/extensions/livestream.
|
||||||
| ^lnbits/extensions/lnaddress.
|
|
||||||
| ^lnbits/extensions/lnurldevice.
|
| ^lnbits/extensions/lnurldevice.
|
||||||
| ^lnbits/extensions/satspay.
|
|
||||||
| ^lnbits/extensions/streamalerts.
|
|
||||||
| ^lnbits/extensions/watchonly.
|
| ^lnbits/extensions/watchonly.
|
||||||
| ^lnbits/wallets/lnd_grpc_files.
|
| ^lnbits/wallets/lnd_grpc_files.
|
||||||
)"""
|
)"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user