diff --git a/lnbits/core/services.py b/lnbits/core/services.py
index d623b1183..73bfa0610 100644
--- a/lnbits/core/services.py
+++ b/lnbits/core/services.py
@@ -27,8 +27,6 @@ from .crud import (
update_payment_status,
get_wallet_payment,
)
-
-
async def create_invoice(
*,
wallet_id: str,
diff --git a/lnbits/extensions/satspay/crud.py b/lnbits/extensions/satspay/crud.py
index bb9b0203a..56c22b31a 100644
--- a/lnbits/extensions/satspay/crud.py
+++ b/lnbits/extensions/satspay/crud.py
@@ -8,34 +8,56 @@ from lnbits.helpers import urlsafe_short_hash
from quart import jsonify
import httpx
-
+from lnbits.core.services import create_invoice, check_invoice_status
+from ..watchonly.crud import get_watch_wallet, get_derive_address
###############CHARGES##########################
-async def create_charge(walletid: str, user: str, title: Optional[str] = None, time: Optional[int] = None, amount: Optional[int] = None) -> Charges:
- wallet = await get_watch_wallet(walletid)
- address = await get_derive_address(walletid, wallet[4] + 1)
-
+async def create_charge(user: str, description: Optional[str] = None, onchainwallet: Optional[str] = None, lnbitswallet: Optional[str] = None, webhook: Optional[str] = None, time: Optional[int] = None, amount: Optional[int] = None) -> Charges:
charge_id = urlsafe_short_hash()
+ if onchainwallet:
+ wallet = await get_watch_wallet(onchainwallet)
+ onchainaddress = await get_derive_address(onchainwallet, wallet[4] + 1)
+ else:
+ onchainaddress = None
+ if lnbitswallet:
+ payment_hash, payment_request = await create_invoice(
+ wallet_id=lnbitswallet,
+ amount=amount,
+ memo=charge_id)
+ else:
+ payment_hash = None
+ payment_request = None
await db.execute(
"""
INSERT INTO charges (
id,
user,
- title,
- wallet,
- address,
- time_to_pay,
+ description,
+ onchainwallet,
+ onchainaddress,
+ lnbitswallet,
+ payment_request,
+ payment_hash,
+ webhook,
+ time,
amount,
- balance
+ balance,
+ paid
)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
- (charge_id, user, title, walletid, address, time, amount, 0),
+ (charge_id, user, description, onchainwallet, onchainaddress, lnbitswallet, payment_request, payment_hash, webhook, time, amount, 0, False),
)
return await get_charge(charge_id)
+async def update_charge(charge_id: str, **kwargs) -> Optional[Charges]:
+ q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
+ await db.execute(f"UPDATE charges SET {q} WHERE id = ?", (*kwargs.values(), wallet_id))
+ row = await db.fetchone("SELECT * FROM charges WHERE id = ?", (wallet_id,))
+ return Charges.from_row(row) if row else None
+
async def get_charge(charge_id: str) -> Charges:
row = await db.fetchone("SELECT * FROM charges WHERE id = ?", (charge_id,))
@@ -45,7 +67,7 @@ async def get_charge(charge_id: str) -> Charges:
async def get_charges(user: str) -> List[Charges]:
rows = await db.fetchall("SELECT * FROM charges WHERE user = ?", (user,))
for row in rows:
- await check_address_balance(row.address)
+ await check_address_balance(row.id)
rows = await db.fetchall("SELECT * FROM charges WHERE user = ?", (user,))
return [charges.from_row(row) for row in rows]
@@ -53,15 +75,23 @@ async def get_charges(user: str) -> List[Charges]:
async def delete_charge(charge_id: str) -> None:
await db.execute("DELETE FROM charges WHERE id = ?", (charge_id,))
-async def check_address_balance(address: str) -> List[Charges]:
- address_data = await get_address(address)
- mempool = await get_mempool(address_data.user)
-
- try:
- async with httpx.AsyncClient() as client:
- r = await client.get(mempool.endpoint + "/api/address/" + address)
- except Exception:
- pass
-
- amount_paid = r.json()['chain_stats']['funded_txo_sum'] - r.json()['chain_stats']['spent_txo_sum']
- print(amount_paid)
+async def check_address_balance(charge_id: str) -> List[Charges]:
+ charge = await get_charge(charge_id)
+ if charge.onchainaddress:
+ mempool = await get_mempool(charge.user)
+ try:
+ async with httpx.AsyncClient() as client:
+ r = await client.get(mempool.endpoint + "/api/address/" + charge.onchainaddress)
+ respAmount = r.json()['chain_stats']['funded_txo_sum']
+ if (charge.balance + respAmount) >= charge.balance:
+ return await update_charge(charge_id = charge_id, balance = (charge.balance + respAmount), paid = True)
+ else:
+ return await update_charge(charge_id = charge_id, balance = (charge.balance + respAmount), paid = False)
+ except Exception:
+ pass
+ if charge.lnbitswallet:
+ invoice_status = await check_invoice_status(charge.lnbitswallet, charge.payment_hash)
+ if invoice_status.paid:
+ return await update_charge(charge_id = charge_id, balance = charge.balance, paid = True)
+ row = await db.fetchone("SELECT * FROM charges WHERE id = ?", (charge_id,))
+ return Charges.from_row(row) if row else None
diff --git a/lnbits/extensions/satspay/migrations.py b/lnbits/extensions/satspay/migrations.py
index ff0bf81be..fddcb5867 100644
--- a/lnbits/extensions/satspay/migrations.py
+++ b/lnbits/extensions/satspay/migrations.py
@@ -9,13 +9,19 @@ async def m001_initial(db):
CREATE TABLE IF NOT EXISTS charges (
id TEXT NOT NULL PRIMARY KEY,
user TEXT,
- title TEXT,
- wallet TEXT NOT NULL,
- address TEXT NOT NULL,
- time_to_pay INTEGER,
+ description TEXT,
+ onchainwallet TEXT,
+ onchainaddress TEXT,
+ lnbitswallet TEXT,
+ lnbitskey TEXT,
+ payment_request TEXT,
+ payment_hash TEXT,
+ webhook TEXT,
+ time INTEGER,
amount INTEGER,
balance INTEGER DEFAULT 0,
- time TIMESTAMP NOT NULL DEFAULT (strftime('%s', 'now'))
+ paid BOOLEAN,
+ timestamp TIMESTAMP NOT NULL DEFAULT (strftime('%s', 'now'))
);
"""
)
\ No newline at end of file
diff --git a/lnbits/extensions/satspay/models.py b/lnbits/extensions/satspay/models.py
index ea1afe427..013dc1d7f 100644
--- a/lnbits/extensions/satspay/models.py
+++ b/lnbits/extensions/satspay/models.py
@@ -4,13 +4,18 @@ from typing import NamedTuple
class Charges(NamedTuple):
id: str
user: str
- wallet: str
- title: str
- address: str
- time_to_pay: str
+ description: str
+ onchainwallet: str
+ onchainaddress: str
+ lnbitswallet: str
+ payment_request: str
+ payment_hash: str
+ webhook: str
+ time: str
amount: int
balance: int
- time: int
+ paid: bool
+ timestamp: int
@classmethod
def from_row(cls, row: Row) -> "Payments":
diff --git a/lnbits/extensions/satspay/templates/satspay/index.html b/lnbits/extensions/satspay/templates/satspay/index.html
index 7eab8bf1f..31879c55c 100644
--- a/lnbits/extensions/satspay/templates/satspay/index.html
+++ b/lnbits/extensions/satspay/templates/satspay/index.html
@@ -215,7 +215,7 @@
-
+
@@ -223,7 +223,7 @@
filled
dense
emit-value
- v-model="formDialog.data.wallet"
+ v-model="formDialogCharge.data.lnbitswallet"
:options="g.user.walletOptions"
label="Wallet *"
>
@@ -442,10 +442,11 @@
LNbits.api
.request(
'GET',
- '/satspay/api/v1/ChargeLinks',
+ '/satspay/api/v1/charges',
this.g.user.wallets[0].inkey
)
.then(function (response) {
+ console.log(response.data)
var i
var now = parseInt(new Date() / 1000)
for (i = 0; i < response.data.length; i++) {
@@ -468,8 +469,9 @@
},
sendFormDataCharge: function () {
var self = this
- var wallet = self.g.user.wallets[0]
+ var wallet = self.g.user.wallets[0].inkey
var data = self.formDialogCharge.data
+ console.log(data)
data.amount = parseInt(data.amount)
data.time = parseInt(data.time)
if (data.id) {
@@ -501,10 +503,11 @@
var self = this
LNbits.api
- .request('POST', '/satspay/api/v1/Charge', wallet.inkey, data)
+ .request('POST', '/satspay/api/v1/charge', wallet, data)
.then(function (response) {
self.ChargeLinks.push(mapCharge(response.data))
self.formDialogCharge.show = false
+ self.formDialogCharge.data = null
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
diff --git a/lnbits/extensions/satspay/views_api.py b/lnbits/extensions/satspay/views_api.py
index 2617cc56c..c12ec2e93 100644
--- a/lnbits/extensions/satspay/views_api.py
+++ b/lnbits/extensions/satspay/views_api.py
@@ -81,6 +81,7 @@ async def api_wallet_delete(wallet_id):
async def api_charges_retrieve():
charges = await get_charges(g.wallet.user)
+ print(charges)
if not charges:
return (
jsonify(""),
@@ -106,8 +107,10 @@ async def api_charge_retrieve(charge_id):
@api_check_wallet_key("invoice")
@api_validate_post_request(
schema={
- "walletid": {"type": "string", "empty": False, "required": True},
- "title": {"type": "string", "empty": False, "required": True},
+ "onchainwallet": {"type": "string", "empty": False, "required": True},
+ "lnbitswallet": {"type": "string", "empty": False, "required": True},
+ "description": {"type": "string", "empty": False, "required": True},
+ "webhook": {"type": "string", "empty": False, "required": True},
"time": {"type": "integer", "min": 1, "required": True},
"amount": {"type": "integer", "min": 1, "required": True},
}
@@ -117,7 +120,6 @@ async def api_charge_create_or_update(charge_id=None):
if not charge_id:
charge = await create_charge(user = g.wallet.user, **g.data)
return jsonify(charge), HTTPStatus.CREATED
-
else:
charge = await update_charge(user = g.wallet.user, **g.data)
return jsonify(charge), HTTPStatus.OK
diff --git a/lnbits/extensions/watchonly/models.py b/lnbits/extensions/watchonly/models.py
index ceff089f0..86e63a8c5 100644
--- a/lnbits/extensions/watchonly/models.py
+++ b/lnbits/extensions/watchonly/models.py
@@ -8,11 +8,12 @@ class Wallets(NamedTuple):
title: str
address_no: int
balance: int
-
+
@classmethod
def from_row(cls, row: Row) -> "Wallets":
return cls(**dict(row))
+
class Mempool(NamedTuple):
user: str
endpoint: str
diff --git a/lnbits/extensions/watchonly/templates/watchonly/index.html b/lnbits/extensions/watchonly/templates/watchonly/index.html
index d46b06d2c..8b241d5aa 100644
--- a/lnbits/extensions/watchonly/templates/watchonly/index.html
+++ b/lnbits/extensions/watchonly/templates/watchonly/index.html
@@ -285,6 +285,22 @@
)
return obj
}
+ var mapAddresses = function (obj) {
+ obj._data = _.clone(obj)
+ obj.date = Quasar.utils.date.formatDate(
+ new Date(obj.time * 1000),
+ 'YYYY-MM-DD HH:mm'
+ )
+ return obj
+ }
+ var mapTxs = function (obj) {
+ obj._data = _.clone(obj)
+ obj.date = Quasar.utils.date.formatDate(
+ new Date(obj.time * 1000),
+ 'YYYY-MM-DD HH:mm'
+ )
+ return obj
+ }
var mapCharge = function (obj) {
obj._data = _.clone(obj)
obj.date = Quasar.utils.date.formatDate(
@@ -304,6 +320,8 @@
balance: null,
checker: null,
walletLinks: [],
+ AddressesLinks: [],
+ txsLinks: [],
ChargeLinks: [],
currentaddress: "",
Addresses: {
@@ -322,13 +340,6 @@
label: 'Title',
field: 'title'
},
-
- {
- name: 'amount',
- align: 'left',
- label: 'Amount',
- field: 'amount'
- },
{
name: 'masterpub',
align: 'left',
@@ -397,26 +408,64 @@
},
methods: {
+ getAddressDetails: function (address){
+ LNbits.api
+ .request(
+ 'GET',
+ '/watchonly/api/v1/mempool/' + address,
+ this.g.user.wallets[0].inkey
+ )
+ .then(function (response) {
+
+ return reponse.data
+ })
+ .catch(function (error) {
+
+ LNbits.utils.notifyApiError(error)
+ })
+ },
+ getAddressTxs: function (address){
+ LNbits.api
+ .request(
+ 'GET',
+ '/watchonly/api/v1/mempool/txs/' + address,
+ this.g.user.wallets[0].inkey
+ )
+ .then(function (response) {
+
+ self.txsLinks = response.data.map(function (obj) {
+ console.log(obj)
+ return mapTxs(obj)
+
+ })
+ })
+ .catch(function (error) {
+
+ LNbits.utils.notifyApiError(error)
+ })
+ },
getAddresses: function (walletID) {
var self = this
-
LNbits.api
- .request(
- 'GET',
- '/watchonly/api/v1/addresses/' + walletID,
- this.g.user.wallets[0].inkey
- )
- .then(function (response) {
+ .request(
+ 'GET',
+ '/watchonly/api/v1/addresses/' + walletID,
+ this.g.user.wallets[0].inkey
+ )
+ .then(function (response) {
+ self.Addresses.data = response.data
+ self.currentaddress = self.Addresses.data[self.Addresses.data.length - 1].address
+ self.AddressesLinks = response.data.map(function (obj) {
+ console.log(obj)
+
+ return mapAddresses(obj)
- self.Addresses.data = response.data
- self.currentaddress = self.Addresses.data[self.Addresses.data.length - 1].address
- console.log(self.currentaddress)
-
- })
-
- .catch(function (error) {
- LNbits.utils.notifyApiError(error)
- })
+ })
+ })
+ .catch(function (error) {
+
+ LNbits.utils.notifyApiError(error)
+ })
},
getFreshAddress: function (walletID) {
var self = this
@@ -428,16 +477,11 @@
this.g.user.wallets[0].inkey
)
.then(function (response) {
- console.log(response.data)
self.Addresses.data = response.data
self.currentaddress = self.Addresses.data[self.Addresses.data.length - 1].address
-
})
-
},
-
-
- getMempool: function () {
+ getMempool: function () {
var self = this
LNbits.api
@@ -447,9 +491,7 @@
this.g.user.wallets[0].inkey
)
.then(function (response) {
- console.log(response.data.endpoint)
self.mempool.endpoint = response.data.endpoint
- console.log(this.mempool.endpoint)
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
@@ -482,15 +524,19 @@
this.g.user.wallets[0].inkey
)
.then(function (response) {
+ console.log(response)
+
self.walletLinks = response.data.map(function (obj) {
-
- return mapWalletLink(obj)
+ self.getAddresses(obj.id)
+ return mapWalletLink(obj)
})
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
},
+
+
closeFormDialog: function () {
this.formDialog.data = {
is_unique: false
@@ -547,7 +593,6 @@
.then(function (response) {
self.walletLinks.push(mapWalletLink(response.data))
self.formDialog.show = false
- console.log(response.data[1][1])
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
@@ -556,7 +601,6 @@
deleteWalletLink: function (linkId) {
var self = this
var link = _.findWhere(this.walletLinks, {id: linkId})
- console.log(self.g.user.wallets[0].adminkey)
LNbits.utils
.confirmDialog('Are you sure you want to delete this pay link?')
.onOk(function () {
@@ -582,13 +626,13 @@
},
created: function () {
if (this.g.user.wallets.length) {
- var getWalletLinks = this.getWalletLinks
- getWalletLinks()
var getMempool = this.getMempool
getMempool()
-
+ var getWalletLinks = this.getWalletLinks
+ getWalletLinks()
+
+
}
-
}
})
diff --git a/lnbits/extensions/watchonly/views_api.py b/lnbits/extensions/watchonly/views_api.py
index 032498583..549e24d0b 100644
--- a/lnbits/extensions/watchonly/views_api.py
+++ b/lnbits/extensions/watchonly/views_api.py
@@ -1,8 +1,7 @@
import hashlib
-from quart import g, jsonify, url_for
+from quart import g, jsonify, url_for, request
from http import HTTPStatus
-import httpx
-
+import httpx, json
from lnbits.core.crud import get_user
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
@@ -38,6 +37,7 @@ async def api_wallets_retrieve():
@api_check_wallet_key("invoice")
async def api_wallet_retrieve(wallet_id):
wallet = await get_watch_wallet(wallet_id)
+ addresses = await api_get_addresses(wallet_id)
if not wallet:
return jsonify({"message": "wallet does not exist"}), HTTPStatus.NOT_FOUND
@@ -130,4 +130,63 @@ async def api_get_mempool():
mempool = await get_mempool(g.wallet.user)
if not mempool:
mempool = await create_mempool(user=g.wallet.user)
- return jsonify(mempool._asdict()), HTTPStatus.OK
\ No newline at end of file
+ return jsonify(mempool._asdict()), HTTPStatus.OK
+
+@watchonly_ext.route("/api/v1/mempool/
", methods=["GET"])
+@api_check_wallet_key("invoice")
+async def api_get_mempool_wallet_balance(address):
+ mempool = await get_mempool(g.wallet.user)
+ if not mempool:
+ mempool = await create_mempool(user=g.wallet.user)
+ url = (
+ mempool.endpoint
+ + "/api/address/"
+ + address
+ )
+ header = {
+ "Content-Type": "application/json",
+ }
+ async with httpx.AsyncClient() as client:
+ try:
+ r = await client.get(
+ url,
+ headers=header,
+ timeout=40,
+ )
+ mp_response = json.loads(r.text)
+ print(mp_response)
+ except AssertionError:
+ mp_response = "Error occured"
+ return jsonify(mp_response), HTTPStatus.OK
+
+@watchonly_ext.route("/api/v1/mempool/txs/", methods=["GET"])
+@api_check_wallet_key("invoice")
+async def api_get_mempool_wallet_txs(address):
+ mempool = await get_mempool(g.wallet.user)
+ if not mempool:
+ mempool = await create_mempool(user=g.wallet.user)
+ url = (
+ mempool.endpoint
+ + "/api/address/"
+ + address
+ + "/txs"
+ )
+ header = {
+ "Content-Type": "application/json",
+ }
+ async with httpx.AsyncClient() as client:
+ try:
+ r = await client.get(
+ url,
+ headers=header,
+ timeout=40,
+ )
+ mp_response = json.loads(r.text)
+ print(mp_response)
+ except AssertionError:
+ mp_response = "Error occured"
+ return jsonify(mp_response), HTTPStatus.OK
+
+
+
+
\ No newline at end of file