From 871d7165390def25c9ef09f12c162443a37f7c61 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Fri, 25 Nov 2022 10:48:57 +0200 Subject: [PATCH] feat: store onchain charge config with the charge --- lnbits/extensions/satspay/crud.py | 34 +++++++++++-------- lnbits/extensions/satspay/helpers.py | 13 +++++-- lnbits/extensions/satspay/migrations.py | 11 ++++++ lnbits/extensions/satspay/models.py | 7 ++++ lnbits/extensions/satspay/tasks.py | 4 +-- .../satspay/templates/satspay/display.html | 10 +++--- .../satspay/templates/satspay/index.html | 9 +++-- lnbits/extensions/satspay/views.py | 23 ++++++------- lnbits/extensions/satspay/views_api.py | 9 ++--- 9 files changed, 73 insertions(+), 47 deletions(-) diff --git a/lnbits/extensions/satspay/crud.py b/lnbits/extensions/satspay/crud.py index 512bcaa3b..6c0c1cb3a 100644 --- a/lnbits/extensions/satspay/crud.py +++ b/lnbits/extensions/satspay/crud.py @@ -1,6 +1,8 @@ +import json from typing import List, Optional import httpx +from loguru import logger from lnbits.core.services import create_invoice from lnbits.core.views.api import api_payment @@ -18,6 +20,10 @@ from .models import Charges, CreateCharge async def create_charge(user: str, data: CreateCharge) -> Charges: charge_id = urlsafe_short_hash() if data.onchainwallet: + config = await get_config(user) + data.extra = json.dumps( + {"mempool_endpoint": config.mempool_endpoint, "network": config.network} + ) onchain = await get_fresh_address(data.onchainwallet) onchainaddress = onchain.address else: @@ -48,9 +54,10 @@ async def create_charge(user: str, data: CreateCharge) -> Charges: completelinktext, time, amount, - balance + balance, + extra ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( charge_id, @@ -67,6 +74,7 @@ async def create_charge(user: str, data: CreateCharge) -> Charges: data.time, data.amount, 0, + data.extra, ), ) return await get_charge(charge_id) @@ -100,31 +108,27 @@ async def delete_charge(charge_id: str) -> None: async def check_address_balance(charge_id: str) -> Optional[Charges]: charge = await get_charge(charge_id) + if not charge.paid: if charge.onchainaddress: - config = await get_charge_config(charge_id) + endpoint = ( + f"{charge.config['mempool_endpoint']}/testnet" + if charge.config["network"] == "Testnet" + else charge.config["mempool_endpoint"] + ) try: async with httpx.AsyncClient() as client: r = await client.get( - config.mempool_endpoint - + "/api/address/" - + charge.onchainaddress + endpoint + "/api/address/" + charge.onchainaddress ) respAmount = r.json()["chain_stats"]["funded_txo_sum"] if respAmount > charge.balance: await update_charge(charge_id=charge_id, balance=respAmount) - except Exception: - pass + except Exception as e: + logger.warning(e) if charge.lnbitswallet: invoice_status = await api_payment(charge.payment_hash) if invoice_status["paid"]: return await update_charge(charge_id=charge_id, balance=charge.amount) return await get_charge(charge_id) - - -async def get_charge_config(charge_id: str): - row = await db.fetchone( - """SELECT "user" FROM satspay.charges WHERE id = ?""", (charge_id,) - ) - return await get_config(row.user) diff --git a/lnbits/extensions/satspay/helpers.py b/lnbits/extensions/satspay/helpers.py index 2d15b5578..1ebaa062c 100644 --- a/lnbits/extensions/satspay/helpers.py +++ b/lnbits/extensions/satspay/helpers.py @@ -1,8 +1,8 @@ from .models import Charges -def compact_charge(charge: Charges): - return { +def public_charge(charge: Charges): + c = { "id": charge.id, "description": charge.description, "onchainaddress": charge.onchainaddress, @@ -13,5 +13,12 @@ def compact_charge(charge: Charges): "balance": charge.balance, "paid": charge.paid, "timestamp": charge.timestamp, - "completelink": charge.completelink, # should be secret? + "time_elapsed": charge.time_elapsed, + "time_left": charge.time_left, + "paid": charge.paid, } + + if charge.paid: + c["completelink"] = charge.completelink + + return c diff --git a/lnbits/extensions/satspay/migrations.py b/lnbits/extensions/satspay/migrations.py index 87446c800..d5f6ba13a 100644 --- a/lnbits/extensions/satspay/migrations.py +++ b/lnbits/extensions/satspay/migrations.py @@ -26,3 +26,14 @@ async def m001_initial(db): ); """ ) + + +async def m002_add_charge_extra_data(db): + """ + Add 'exta' for storing various config about the charge + """ + await db.execute( + """ALTER TABLE satspay.charges + ADD COLUMN extra TEXT DEFAULT '{"mempool_endpoint": "https://mempool.space", "network": "Mainnet"}'; + """ + ) diff --git a/lnbits/extensions/satspay/models.py b/lnbits/extensions/satspay/models.py index daf63f429..8d2602e15 100644 --- a/lnbits/extensions/satspay/models.py +++ b/lnbits/extensions/satspay/models.py @@ -1,3 +1,4 @@ +import json from datetime import datetime, timedelta from sqlite3 import Row from typing import Optional @@ -15,6 +16,7 @@ class CreateCharge(BaseModel): completelinktext: str = Query(None) time: int = Query(..., ge=1) amount: int = Query(..., ge=1) + extra: str = "{}" class Charges(BaseModel): @@ -28,6 +30,7 @@ class Charges(BaseModel): webhook: Optional[str] completelink: Optional[str] completelinktext: Optional[str] = "Back to Merchant" + extra: str = "{}" time: int amount: int balance: int @@ -54,3 +57,7 @@ class Charges(BaseModel): return True else: return False + + @property + def config(self): + return json.loads(self.extra) diff --git a/lnbits/extensions/satspay/tasks.py b/lnbits/extensions/satspay/tasks.py index 2cac64311..3a77501b2 100644 --- a/lnbits/extensions/satspay/tasks.py +++ b/lnbits/extensions/satspay/tasks.py @@ -8,7 +8,7 @@ from lnbits.extensions.satspay.crud import check_address_balance, get_charge from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener -from .helpers import compact_charge +from .helpers import public_charge from .models import Charges @@ -43,7 +43,7 @@ async def call_webhook(charge: Charges): try: r = await client.post( charge.webhook, - json=compact_charge(charge), + json=public_charge(charge), timeout=40, ) except AssertionError: diff --git a/lnbits/extensions/satspay/templates/satspay/display.html b/lnbits/extensions/satspay/templates/satspay/display.html index cfc702b14..a24ed84c7 100644 --- a/lnbits/extensions/satspay/templates/satspay/display.html +++ b/lnbits/extensions/satspay/templates/satspay/display.html @@ -109,7 +109,7 @@ @@ -131,7 +131,7 @@ @@ -222,7 +222,7 @@
({ @@ -538,7 +539,9 @@ '/watchonly/api/v1/config', this.g.user.wallets[0].inkey ) + console.log('### data', data) this.mempool.endpoint = data.mempool_endpoint + this.mempool.network = data.network || 'Mainnet' const url = new URL(this.mempool.endpoint) this.mempool.hostname = url.hostname } catch (error) { @@ -697,8 +700,8 @@ }, created: async function () { await this.getCharges() - await this.getWalletLinks() await this.getWalletConfig() + await this.getWalletLinks() setInterval(() => this.refreshActiveChargesBalance(), 10 * 2000) await this.rescanOnchainAddresses() setInterval(() => this.rescanOnchainAddresses(), 10 * 1000) diff --git a/lnbits/extensions/satspay/views.py b/lnbits/extensions/satspay/views.py index 5029f1682..5faebe7a9 100644 --- a/lnbits/extensions/satspay/views.py +++ b/lnbits/extensions/satspay/views.py @@ -6,12 +6,12 @@ from starlette.exceptions import HTTPException from starlette.requests import Request from starlette.responses import HTMLResponse -from lnbits.core.crud import get_wallet from lnbits.core.models import User from lnbits.decorators import check_user_exists +from lnbits.extensions.satspay.helpers import public_charge from . import satspay_ext, satspay_renderer -from .crud import get_charge, get_charge_config +from .crud import get_charge templates = Jinja2Templates(directory="templates") @@ -31,16 +31,15 @@ async def display(request: Request, charge_id: str): status_code=HTTPStatus.NOT_FOUND, detail="Charge link does not exist." ) - onchainwallet_config = await get_charge_config(charge_id) - if onchainwallet_config: - mempool_endpoint = onchainwallet_config.mempool_endpoint - network = onchainwallet_config.network + view_data = { + "request": request, + "charge_data": public_charge(charge), + } + if "mempool_endpoint" in charge.config: + view_data["mempool_endpoint"] = charge.config["mempool_endpoint"] + view_data["network"] = charge.config["network"] + return satspay_renderer().TemplateResponse( "satspay/display.html", - { - "request": request, - "charge_data": charge.dict(), - "mempool_endpoint": mempool_endpoint, - "network": network, - }, + view_data, ) diff --git a/lnbits/extensions/satspay/views_api.py b/lnbits/extensions/satspay/views_api.py index e516219e4..73581022f 100644 --- a/lnbits/extensions/satspay/views_api.py +++ b/lnbits/extensions/satspay/views_api.py @@ -19,7 +19,7 @@ from .crud import ( get_charges, update_charge, ) -from .helpers import compact_charge +from .helpers import public_charge from .models import CreateCharge #############################CHARGES########################## @@ -118,9 +118,4 @@ async def api_charge_balance(charge_id): status_code=HTTPStatus.NOT_FOUND, detail="Charge does not exist." ) - return { - **compact_charge(charge), - **{"time_elapsed": charge.time_elapsed}, - **{"time_left": charge.time_left}, - **{"paid": charge.paid}, - } + return {**public_charge(charge)}