add zbd to settings

update api methods

add zbd as funding source to settings and js

fix statuses

cast str into int for status method

fix outbound payment hash issue

restore create_invoice

remove print stmts
This commit is contained in:
bitkarrot 2024-02-01 18:36:17 -08:00 committed by Pavol Rusnak
parent d69946db8a
commit d20a35eddc
4 changed files with 76 additions and 31 deletions

View file

@ -210,6 +210,7 @@ class ZBDFundingSource(LNbitsSettings):
zbd_api_endpoint: Optional[str] = Field(default="https://api.zebedee.io/v0/")
zbd_api_key: Optional[str] = Field(default=None)
class AlbyFundingSource(LNbitsSettings):
alby_api_endpoint: Optional[str] = Field(default="https://api.getalby.com/")
alby_access_token: Optional[str] = Field(default=None)
@ -249,6 +250,7 @@ class FundingSourcesSettings(
LndGrpcFundingSource,
LnPayFundingSource,
AlbyFundingSource,
ZBDFundingSource,
OpenNodeFundingSource,
SparkFundingSource,
LnTipsFundingSource,
@ -403,6 +405,7 @@ class SuperUserSettings(LNbitsSettings):
"LnTipsWallet",
"LNPayWallet",
"AlbyWallet",
"ZBDWallet",
"LNbitsWallet",
"OpenNodeWallet",
]

View file

@ -110,7 +110,7 @@ Vue.component('lnbits-funding-sources', {
'ZBD',
{
zbd_api_endpoint: 'Endpoint',
zbd_access_token: 'Key'
zbd_api_key: 'Key'
}
],
[

View file

@ -8,7 +8,6 @@ from lnbits.settings import settings
from lnbits.wallets.base import Wallet
from .alby import AlbyWallet
from .zbd import ZBDWallet
from .cliche import ClicheWallet
from .corelightning import CoreLightningWallet
@ -26,6 +25,7 @@ from .lntips import LnTipsWallet
from .opennode import OpenNodeWallet
from .spark import SparkWallet
from .void import VoidWallet
from .zbd import ZBDWallet
def set_wallet_class(class_name: Optional[str] = None):

View file

@ -1,17 +1,18 @@
import asyncio
import hashlib
from typing import AsyncGenerator, Dict, Optional
import httpx
from loguru import logger
from lnbits.settings import settings
from lnbits.wallets.base import PaymentStatus
from .base import (
InvoiceResponse,
PaymentResponse,
PaymentStatus,
StatusResponse,
Unsupported,
Wallet,
)
@ -27,7 +28,7 @@ class ZBDWallet(Wallet):
self.endpoint = self.normalize_endpoint(settings.zbd_api_endpoint)
self.auth = {
"Authorization": "Bearer " + settings.zbd_api_key,
"apikey": settings.zbd_api_key,
"User-Agent": settings.user_agent,
}
self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.auth)
@ -40,16 +41,18 @@ class ZBDWallet(Wallet):
async def status(self) -> StatusResponse:
try:
r = await self.client.get("/balance", timeout=10)
r = await self.client.get("wallet", timeout=10)
except (httpx.ConnectError, httpx.RequestError):
return StatusResponse(f"Unable to connect to '{self.endpoint}'", 0)
if r.is_error:
error_message = r.json()["message"]
return StatusResponse(error_message, 0)
data = r.json()["balance"]
# if no error, multiply balance by 1000 for msats representation in lnbits
return StatusResponse(None, data * 1000)
data = int(r.json()["data"]["balance"])
# ZBD returns everything as a str not int
# balance is returned in msats already in ZBD
return StatusResponse(None, data)
async def create_invoice(
self,
@ -60,16 +63,20 @@ class ZBDWallet(Wallet):
**kwargs,
) -> InvoiceResponse:
# https://api.zebedee.io/v0/charges
data: Dict = {"amount": f"{amount}"}
if description_hash:
data["description_hash"] = description_hash.hex()
elif unhashed_description:
data["description_hash"] = hashlib.sha256(unhashed_description).hexdigest()
else:
data["memo"] = memo or ""
if description_hash or unhashed_description:
raise Unsupported("description_hash")
msats_amount = amount * 1000
data: Dict = {
"amount": f"{msats_amount}",
"description": memo,
"expiresIn": 3600,
"callbackUrl": "",
"internalId": "",
}
r = await self.client.post(
"/invoices",
"charges",
json=data,
timeout=40,
)
@ -78,16 +85,22 @@ class ZBDWallet(Wallet):
error_message = r.json()["message"]
return InvoiceResponse(False, None, None, error_message)
data = r.json()
checking_id = data["payment_hash"]
payment_request = data["payment_request"]
data = r.json()["data"]
checking_id = data["id"] # this is a zbd id
payment_request = data["invoice"]["request"]
return InvoiceResponse(True, checking_id, payment_request, None)
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
# https://api.zebedee.io/v0/payments
r = await self.client.post(
"/payments/bolt11",
json={"invoice": bolt11}, # assume never need amount in body
"payments",
json={
"invoice": bolt11,
"description": "",
"amount": "",
"internalId": "",
"callbackUrl": "",
},
timeout=None,
)
@ -96,28 +109,57 @@ class ZBDWallet(Wallet):
return PaymentResponse(False, None, None, None, error_message)
data = r.json()
checking_id = data["payment_hash"]
fee_msat = -data["fee"]
preimage = data["payment_preimage"]
# get the payment hash from the zbd api
decoded_request = await self.client.post(
"decode-invoice",
json={"invoice": bolt11},
timeout=40,
)
if decoded_request.is_error:
error_message = decoded_request.json()["message"]
return InvoiceResponse(False, None, None, error_message)
decoded_data = decoded_request.json()
checking_id = decoded_data["data"]["paymentHash"]
fee_msat = -int(data["data"]["fee"])
preimage = data["data"]["preimage"]
return PaymentResponse(True, checking_id, fee_msat, preimage, None)
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
return await self.get_payment_status(checking_id)
r = await self.client.get(f"charges/{checking_id}")
if r.is_error:
return PaymentStatus(None)
data = r.json()["data"]
statuses = {
"pending": None,
"paid": True,
"unpaid": None,
"expired": False,
"completed": True,
}
return PaymentStatus(statuses[data.get("status")])
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
r = await self.client.get(f"/invoices/{checking_id}")
r = await self.client.get(f"payments/{checking_id}")
if r.is_error:
return PaymentStatus(None)
data = r.json()
data = r.json()["data"]
statuses = {
"CREATED": None,
"SETTLED": True,
"initial": None,
"pending": None,
"completed": True,
"error": None,
"expired": False,
"failed": False,
}
return PaymentStatus(statuses[data.get("state")], fee_msat=None, preimage=None)
return PaymentStatus(statuses[data.get("status")], fee_msat=None, preimage=None)
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
self.queue: asyncio.Queue = asyncio.Queue(0)