webhook to pay_invoice

This commit is contained in:
Gene Takavic 2022-09-25 17:01:22 +02:00
parent 574ba3e874
commit 8b3af03519
4 changed files with 56 additions and 52 deletions

View file

@ -2,7 +2,7 @@ import asyncio
import json import json
from binascii import unhexlify from binascii import unhexlify
from io import BytesIO from io import BytesIO
from typing import Dict, Optional, Tuple from typing import Dict, Optional, Tuple, Union
from urllib.parse import parse_qs, urlparse from urllib.parse import parse_qs, urlparse
import httpx import httpx
@ -102,6 +102,7 @@ async def pay_invoice(
extra: Optional[Dict] = None, extra: Optional[Dict] = None,
description: str = "", description: str = "",
conn: Optional[Connection] = None, conn: Optional[Connection] = None,
webhook: Optional[Union[str, tuple]] = None,
) -> str: ) -> str:
""" """
Pay a Lightning invoice. Pay a Lightning invoice.
@ -231,6 +232,34 @@ async def pay_invoice(
f"didn't receive checking_id from backend, payment may be stuck in database: {temp_id}" f"didn't receive checking_id from backend, payment may be stuck in database: {temp_id}"
) )
if type(webhook) is str:
webhook_url = webhook
elif type(webhook) is tuple:
webhook_url = webhook[0]
additionals = webhook[1]
else:
webhook_url = None
if webhook_url:
async with httpx.AsyncClient() as client:
try:
json = {
"payment_hash": invoice.payment_hash,
"payment_request": payment_request,
"amount": int(invoice.amount_msat / 1000),
}
if type(additionals) is dict:
json.update(additionals)
r = await client.post(
webhook_url,
json=json,
timeout=40,
)
except Exception as exc:
# webhook fails shouldn't cause the lnurlw to fail since invoice is already paid
logger.error("Caught exception when dispatching webhook url:", exc)
return invoice.payment_hash return invoice.payment_hash

View file

@ -1,19 +1,12 @@
import base64
import hashlib
import hmac
import json import json
import secrets import secrets
from http import HTTPStatus from http import HTTPStatus
from io import BytesIO
from typing import Optional
from urllib.parse import urlparse from urllib.parse import urlparse
import httpx
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 fastapi.params import Depends, Query from fastapi.params import Depends, Query
from lnurl import Lnurl, LnurlWithdrawResponse
from lnurl import encode as lnurl_encode # type: ignore from lnurl import encode as lnurl_encode # type: ignore
from lnurl.types import LnurlPayMetadata # type: ignore from lnurl.types import LnurlPayMetadata # type: ignore
from loguru import logger from loguru import logger
@ -34,7 +27,6 @@ from .crud import (
get_hit, get_hit,
get_hits_today, get_hits_today,
spend_hit, spend_hit,
update_card,
update_card_counter, update_card_counter,
update_card_otp, update_card_otp,
) )
@ -120,32 +112,26 @@ async def lnurl_callback(
invoice = bolt11.decode(pr) invoice = bolt11.decode(pr)
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))
try: try:
payment_hash = await pay_invoice( webhook = (
(
card.webhook_url,
{
"notification": "card_payment",
"card_external_id": card.external_id,
"card_name": card.card_name,
},
)
if card.webhook_url
else None
)
await pay_invoice(
wallet_id=card.wallet, wallet_id=card.wallet,
payment_request=pr, payment_request=pr,
max_sat=card.tx_limit, max_sat=card.tx_limit,
extra={"tag": "boltcard", "tag": hit.id}, extra={"tag": "boltcard", "tag": hit.id},
webhook=webhook,
) )
if card.webhook_url:
async with httpx.AsyncClient() as client:
try:
r = await client.post(
card.webhook_url,
json={
"notification": "card_payment",
"payment_hash": payment_hash,
"payment_request": pr,
"card_external_id": card.external_id,
"card_name": card.card_name,
"amount": int(invoice.amount_msat / 1000),
},
timeout=40,
)
except Exception as exc:
# webhook fails shouldn't cause the lnurlw to fail since invoice is already paid
logger.error("Caught exception when dispatching webhook url:", exc)
return {"status": "OK"} return {"status": "OK"}
except: except:
return {"status": "ERROR", "reason": f"Payment failed"} return {"status": "ERROR", "reason": f"Payment failed"}

View file

@ -12,21 +12,16 @@ from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
from . import boltcards_ext from . import boltcards_ext
from .crud import ( from .crud import (
create_card, create_card,
create_hit,
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_counter,
update_card_otp,
) )
from .models import CreateCardData from .models import CreateCardData
from .nxp424 import decryptSUN, getSunMAC
@boltcards_ext.get("/api/v1/cards") @boltcards_ext.get("/api/v1/cards")

View file

@ -3,7 +3,6 @@ import traceback
from datetime import datetime from datetime import datetime
from http import HTTPStatus from http import HTTPStatus
import httpx
import shortuuid # type: ignore import shortuuid # type: ignore
from fastapi import HTTPException from fastapi import HTTPException
from fastapi.param_functions import Query from fastapi.param_functions import Query
@ -115,29 +114,24 @@ async def api_lnurl_callback(
payment_request = pr payment_request = pr
payment_hash = await pay_invoice( webhook = (
(
link.webhook_url,
{
"lnurlw": link.id,
},
)
if link.webhook_url
else None
)
await pay_invoice(
wallet_id=link.wallet, wallet_id=link.wallet,
payment_request=payment_request, payment_request=payment_request,
max_sat=link.max_withdrawable, max_sat=link.max_withdrawable,
extra={"tag": "withdraw"}, extra={"tag": "withdraw"},
webhook=webhook,
) )
if link.webhook_url:
async with httpx.AsyncClient() as client:
try:
r = await client.post(
link.webhook_url,
json={
"payment_hash": payment_hash,
"payment_request": payment_request,
"lnurlw": link.id,
},
timeout=40,
)
except Exception as exc:
# webhook fails shouldn't cause the lnurlw to fail since invoice is already paid
logger.error("Caught exception when dispatching webhook url:", exc)
return {"status": "OK"} return {"status": "OK"}
except Exception as e: except Exception as e: