diff --git a/crud.py b/crud.py index 9179d9a..7a4772b 100644 --- a/crud.py +++ b/crud.py @@ -1,4 +1,3 @@ -import json from typing import Optional from lnbits.core.services import create_invoice @@ -11,7 +10,6 @@ CreateSatsPayTheme, SatspaySettings, SatsPayTheme, - WalletAccountConfig, ) db = Database("ext_satspay") @@ -20,17 +18,12 @@ async def create_charge( user: str, data: CreateCharge, - config: Optional[WalletAccountConfig] = None, onchainaddress: Optional[str] = None, ) -> Charge: - data = CreateCharge(**data.dict()) charge_id = urlsafe_short_hash() if data.onchainwallet: - if not onchainaddress or not config: + if not onchainaddress: raise Exception(f"Wallet '{data.onchainwallet}' can no longer be accessed.") - data.extra = json.dumps( - {"mempool_endpoint": config.mempool_endpoint, "network": config.network} - ) assert data.amount, "Amount is required" if data.lnbitswallet: diff --git a/helpers.py b/helpers.py index e161a8a..7d0a741 100644 --- a/helpers.py +++ b/helpers.py @@ -1,11 +1,10 @@ -import json - import httpx from lnbits.core.crud import get_standalone_payment from lnbits.settings import settings from loguru import logger -from .models import Charge, OnchainBalance, WalletAccountConfig +from .crud import get_or_create_satspay_settings +from .models import Charge, OnchainBalance async def call_webhook(charge: Charge): @@ -36,20 +35,10 @@ async def call_webhook(charge: Charge): return {"webhook_success": False, "webhook_message": str(e)} -def get_endpoint(charge: Charge) -> str: - assert charge.config.mempool_endpoint, "No mempool endpoint configured" - return ( - f"{charge.config.mempool_endpoint}/testnet" - if charge.config.network == "Testnet" - else charge.config.mempool_endpoint or "" - ) - - -async def fetch_onchain_balance( - onchain_address: str, mempool_endpoint: str -) -> OnchainBalance: +async def fetch_onchain_balance(onchain_address: str) -> OnchainBalance: + settings = await get_or_create_satspay_settings() async with httpx.AsyncClient() as client: - res = await client.get(f"{mempool_endpoint}/api/address/{onchain_address}") + res = await client.get(f"{settings.mempool_url}/api/address/{onchain_address}") res.raise_for_status() data = res.json() confirmed = data["chain_stats"]["funded_txo_sum"] @@ -57,29 +46,28 @@ async def fetch_onchain_balance( return OnchainBalance(confirmed=confirmed, unconfirmed=unconfirmed) -async def fetch_onchain_config( - wallet_id: str, api_key: str -) -> tuple[WalletAccountConfig, str]: +async def fetch_onchain_config_network(api_key: str) -> str: async with httpx.AsyncClient() as client: - headers = {"X-API-KEY": api_key} r = await client.get( url=f"http://{settings.host}:{settings.port}/watchonly/api/v1/config", - headers=headers, + headers={"X-API-KEY": api_key}, ) r.raise_for_status() config = r.json() + return config["network"] + +async def fetch_onchain_address(wallet_id: str, api_key: str) -> str: + async with httpx.AsyncClient() as client: r = await client.get( url=f"http://{settings.host}:{settings.port}/watchonly/api/v1/address/{wallet_id}", - headers=headers, + headers={"X-API-KEY": api_key}, ) r.raise_for_status() address_data = r.json() - - if not address_data: + if not address_data and "address" not in address_data: raise ValueError("Cannot fetch new address!") - - return WalletAccountConfig.parse_obj(config), address_data["address"] + return address_data["address"] async def check_charge_balance(charge: Charge) -> Charge: @@ -95,9 +83,7 @@ async def check_charge_balance(charge: Charge) -> Charge: if charge.onchainaddress: try: - balance = await fetch_onchain_balance( - charge.onchainaddress, charge.config.mempool_endpoint - ) + balance = await fetch_onchain_balance(charge.onchainaddress) if ( balance.confirmed != charge.balance or balance.unconfirmed != charge.pending @@ -115,6 +101,6 @@ async def check_charge_balance(charge: Charge) -> Charge: if charge.webhook: resp = await call_webhook(charge) - charge.extra = json.dumps({**charge.config.dict(), **resp}) + charge.add_extra(resp) return charge diff --git a/migrations.py b/migrations.py index 58c2513..72ead72 100644 --- a/migrations.py +++ b/migrations.py @@ -175,3 +175,14 @@ async def m011_persist_paid(db): ) except OperationalError: pass + + +async def m012_add_setting_network(db): + """ + Add 'network' column for storing the network + """ + try: + await db.execute("ALTER TABLE satspay.settings ADD COLUMN network TEXT") + await db.execute("UPDATE satspay.settings SET network = 'Mainnet'") + except OperationalError: + pass diff --git a/models.py b/models.py index adf7a3e..22496d5 100644 --- a/models.py +++ b/models.py @@ -7,14 +7,10 @@ from fastapi.param_functions import Query from pydantic import BaseModel -DEFAULT_MEMPOOL_ENDPOINT = "https://mempool.space" -DEFAULT_MEMPOOL_CONFIG = ( - '{"mempool_endpoint": "https://mempool.space", "network": "Mainnet"}' -) - class SatspaySettings(BaseModel): - mempool_url: str = DEFAULT_MEMPOOL_ENDPOINT + mempool_url: str = "https://mempool.space" + network: str = "Mainnet" class CreateCharge(BaseModel): @@ -28,18 +24,10 @@ class CreateCharge(BaseModel): time: int = Query(..., ge=1) amount: Optional[int] = Query(None, ge=1) zeroconf: bool = Query(False) - extra: str = DEFAULT_MEMPOOL_CONFIG custom_css: Optional[str] = Query(None) currency: str = Query(None) currency_amount: Optional[float] = Query(None) - - -class ChargeConfig(BaseModel): - mempool_endpoint: str - network: Optional[str] - webhook_message: Optional[str] - webhook_success: bool = False - misc: dict = {} + extra: Optional[str] = Query(None) class Charge(BaseModel): @@ -55,7 +43,6 @@ class Charge(BaseModel): completelink: Optional[str] completelinktext: Optional[str] = "Back to Merchant" custom_css: Optional[str] - extra: str = DEFAULT_MEMPOOL_CONFIG time: int amount: int zeroconf: bool @@ -66,11 +53,11 @@ class Charge(BaseModel): currency: Optional[str] = None currency_amount: Optional[float] = None paid: bool = False + extra: Optional[str] = None - @property - def config(self) -> ChargeConfig: - charge_config = json.loads(self.extra) - return ChargeConfig(**charge_config) + def add_extra(self, extra: dict): + old_extra = json.loads(self.extra) if self.extra else {} + self.extra = json.dumps({**old_extra, **extra}) @property def public(self): @@ -110,14 +97,6 @@ class SatsPayTheme(BaseModel): user: str -class WalletAccountConfig(BaseModel): - mempool_endpoint: str - receive_gap_limit: int - change_gap_limit: int - sats_denominated: bool - network: str - - class OnchainBalance(BaseModel): confirmed: int unconfirmed: int diff --git a/static/js/display.js b/static/js/display.js index 6f3f7c4..58f0d10 100644 --- a/static/js/display.js +++ b/static/js/display.js @@ -5,7 +5,7 @@ new Vue({ data() { return { charge: mapCharge(charge_data), - network: network, + mempool_url: mempool_url, ws: null, wallet: { inkey: '' @@ -15,12 +15,9 @@ new Vue({ }, computed: { mempoolLink() { - const onchainaddress = this.charge.onchainaddress - if (this.network === 'Testnet') { - return `https://mempool.space/testnet/address/${onchainaddress}` - } else { - return `https://mempool.space/address/${onchainaddress}` - } + // remove trailing slash + const url = this.mempool_url.replace(/\/$/, '') + return `${url}/address/${this.charge.onchainaddress}` }, unifiedQR() { const bitcoin = (this.charge.onchainaddress || '').toUpperCase() diff --git a/static/js/index.js b/static/js/index.js index 6e510fe..06a2d3b 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -10,8 +10,13 @@ new Vue({ return { currencies: [], fiatRates: {}, - settings: {}, settings: [ + { + type: 'str', + description: + 'Network used by OnchainWallet extension Wallet. default: `Mainnet`, or `Testnet` for testnet', + name: 'network' + }, { type: 'str', description: @@ -21,6 +26,7 @@ new Vue({ ], filter: '', admin: admin, + network: network, balance: null, walletLinks: [], chargeLinks: [], @@ -28,12 +34,7 @@ new Vue({ themeOptions: [], onchainwallet: '', rescanning: false, - mempool: { - endpoint: '', - network: 'Mainnet' - }, showAdvanced: false, - chargesTable: { columns: [ { @@ -171,11 +172,12 @@ new Vue({ getWalletLinks: async function () { try { - const {data} = await LNbits.api.request( + let {data} = await LNbits.api.request( 'GET', - `/watchonly/api/v1/wallet?network=${this.mempool.network}`, + `/watchonly/api/v1/wallet?network=${this.network}`, this.g.user.wallets[0].adminkey ) + data = data.filter(w => w.network === this.network) this.walletLinks = data.map(w => ({ id: w.id, label: w.title + ' - ' + w.id @@ -184,22 +186,6 @@ new Vue({ LNbits.utils.notifyApiError(error) } }, - - getWalletConfig: async function () { - try { - const {data} = await LNbits.api.request( - 'GET', - '/watchonly/api/v1/config', - this.g.user.wallets[0].inkey - ) - 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) { - LNbits.utils.notifyApiError(error) - } - }, getOnchainWalletName: function (walletId) { const wallet = this.walletLinks.find(w => w.id === walletId) if (!wallet) return 'unknown' @@ -426,7 +412,6 @@ new Vue({ await this.getThemes() } await this.getCharges() - await this.getWalletConfig() await this.getWalletLinks() LNbits.api .request('GET', '/api/v1/currencies') diff --git a/tasks.py b/tasks.py index 6fbfaf0..d67a364 100644 --- a/tasks.py +++ b/tasks.py @@ -1,5 +1,4 @@ import asyncio -import json from fastapi import WebSocket from lnbits.core.models import Payment @@ -56,7 +55,7 @@ async def on_invoice_paid(payment: Payment) -> None: await send_success_websocket(charge) if charge.webhook: resp = await call_webhook(charge) - charge.extra = json.dumps({**charge.config.dict(), **resp}) + charge.add_extra(resp) await update_charge(charge) @@ -111,5 +110,5 @@ async def _handle_ws_message(address: str, data: dict): stop_onchain_listener(address) if charge.webhook: resp = await call_webhook(charge) - charge.extra = json.dumps({**charge.config.dict(), **resp}) + charge.add_extra(resp) await update_charge(charge) diff --git a/templates/satspay/display.html b/templates/satspay/display.html index 94d511e..3c612d5 100644 --- a/templates/satspay/display.html +++ b/templates/satspay/display.html @@ -196,7 +196,7 @@ {% endblock %} {% block scripts %} diff --git a/templates/satspay/index.html b/templates/satspay/index.html index ec79da0..4ae8577 100644 --- a/templates/satspay/index.html +++ b/templates/satspay/index.html @@ -618,6 +618,7 @@