feat: store onchain charge config with the charge
This commit is contained in:
parent
4e984eae56
commit
5440d4ab19
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"}';
|
||||
"""
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
<q-btn
|
||||
flat
|
||||
disable
|
||||
v-if="!charge.lnbitswallet || charge.time_elapsed"
|
||||
v-if="!charge.payment_request || charge.time_elapsed"
|
||||
style="color: primary; width: 100%"
|
||||
label="lightning⚡"
|
||||
>
|
||||
|
@ -131,7 +131,7 @@
|
|||
<q-btn
|
||||
flat
|
||||
disable
|
||||
v-if="!charge.onchainwallet || charge.time_elapsed"
|
||||
v-if="!charge.onchainaddress || charge.time_elapsed"
|
||||
style="color: primary; width: 100%"
|
||||
label="onchain⛓️"
|
||||
>
|
||||
|
@ -222,7 +222,7 @@
|
|||
<div class="col text-center">
|
||||
<a
|
||||
style="color: unset"
|
||||
:href="mempoolEndpoint + '/address/' + charge.onchainaddress"
|
||||
:href="'https://' + mempoolHostname + '/address/' + charge.onchainaddress"
|
||||
target="_blank"
|
||||
><span
|
||||
class="text-subtitle1"
|
||||
|
@ -336,7 +336,7 @@
|
|||
},
|
||||
methods: {
|
||||
checkBalances: async function () {
|
||||
if (!this.charge.lnbitswallet && this.charge.hasOnchainStaleBalance)
|
||||
if (!this.charge.payment_request && this.charge.hasOnchainStaleBalance)
|
||||
return
|
||||
try {
|
||||
const {data} = await LNbits.api.request(
|
||||
|
@ -438,7 +438,7 @@
|
|||
}
|
||||
},
|
||||
created: async function () {
|
||||
if (this.charge.lnbitswallet) this.payInvoice()
|
||||
if (this.charge.payment_request) this.payInvoice()
|
||||
else this.payOnchain()
|
||||
|
||||
await this.checkBalances()
|
||||
|
|
|
@ -412,7 +412,8 @@
|
|||
onchainwallet: null,
|
||||
rescanning: false,
|
||||
mempool: {
|
||||
endpoint: ''
|
||||
endpoint: '',
|
||||
network: 'Mainnet'
|
||||
},
|
||||
|
||||
chargesTable: {
|
||||
|
@ -519,7 +520,7 @@
|
|||
try {
|
||||
const {data} = await LNbits.api.request(
|
||||
'GET',
|
||||
'/watchonly/api/v1/wallet',
|
||||
`/watchonly/api/v1/wallet?network=${this.mempool.network}`,
|
||||
this.g.user.wallets[0].inkey
|
||||
)
|
||||
this.walletLinks = data.map(w => ({
|
||||
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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)}
|
||||
|
|
Loading…
Reference in New Issue
Block a user