diff --git a/LNbits/__init__.py b/LNbits/__init__.py index ebccacd..d8517b0 100644 --- a/LNbits/__init__.py +++ b/LNbits/__init__.py @@ -336,3 +336,34 @@ def api_checkinvoice(payhash): db.execute("UPDATE apipayments SET pending = 0 WHERE payhash = ?", (payhash,)) return jsonify({"PAID": "TRUE"}), 200 + +@app.route("/v1/checkpending", methods=["POST"]) +def api_checkpending(): + with Database() as db: + for pendingtx in db.fetchall(""" + SELECT + payhash, + CASE + WHEN amount < 0 THEN 'send' + ELSE 'recv' + END AS kind + FROM apipayments + INNER JOIN wallets ON apipayments.wallet = wallets.id + WHERE time > strftime('%s', 'now') - 86400 + AND pending = 1 + AND (adminkey = ? OR inkey = ?) + """, (request.headers["Grpc-Metadata-macaroon"], request.headers["Grpc-Metadata-macaroon"])): + payhash = pendingtx['payhash'] + kind = pendingtx['kind'] + + if kind == 'send': + status = WALLET.get_final_payment_status(payhash) + if status == 'complete': + db.execute("UPDATE apipayments SET pending = 0 WHERE payhash = ?", (payhash,)) + elif status == 'failed': + db.execute("DELETE FROM apipayments WHERE payhash = ?", (payhash,)) + + elif kind == 'recv': + if WALLET.is_invoice_paid(payhash): + db.execute("UPDATE apipayments SET pending = 0 WHERE payhash = ?", (payhash,)) + return '' diff --git a/LNbits/static/app.js b/LNbits/static/app.js index 3d12314..3ce06d1 100644 --- a/LNbits/static/app.js +++ b/LNbits/static/app.js @@ -347,3 +347,7 @@ function convertTimestamp(timestamp) { if (transactions.length) { drawChart(transactions) } + +if (wallet) { + postAjax('/v1/checkpending', '', wallet.adminkey, function(data) {}) +} diff --git a/LNbits/wallets.py b/LNbits/wallets.py index f82abc1..891abba 100644 --- a/LNbits/wallets.py +++ b/LNbits/wallets.py @@ -19,7 +19,7 @@ class Wallet(ABC): pass @abstractmethod - def get_invoice_status(self, payment_hash: str) -> WalletResponse: + def get_invoice_status(self, payment_hash: str, wait: bool = True) -> WalletResponse: pass @@ -42,5 +42,24 @@ class LntxbotWallet(Wallet): def pay_invoice(self, bolt11: str) -> WalletResponse: return requests.post(url=f"{self.endpoint}/payinvoice", headers=self.auth_admin, json={"invoice": bolt11}) - def get_invoice_status(self, payment_hash: str) -> Response: - return requests.post(url=f"{self.endpoint}/invoicestatus/{payment_hash}", headers=self.auth_invoice) + def get_invoice_status(self, payment_hash: str, wait: bool = True) -> Response: + wait = 'true' if wait else 'false' + return requests.post(url=f"{self.endpoint}/invoicestatus/{payment_hash}?wait={wait}", headers=self.auth_invoice) + + def is_invoice_paid(self, payment_hash: str) -> False: + r = self.get_invoice_status(payment_hash) + if not r.ok or r.json().get('error'): + return False + + data = r.json() + if "preimage" not in data or not data["preimage"]: + return False + + return True + + def get_final_payment_status(self, payment_hash: str) -> str: + r = requests.post(url=f"{self.endpoint}/paymentstatus/{payment_hash}", headers=self.auth_invoice) + if not r.ok: + return "unknown" + + return r.json().get('status', 'unknown')