make all methods from all wallets async.

This commit is contained in:
fiatjaf 2021-03-24 01:01:09 -03:00
parent 42bd5ea989
commit d4d069fc77
15 changed files with 219 additions and 187 deletions

View file

@ -55,7 +55,7 @@ def create_app(config_object="lnbits.settings") -> QuartTrio:
def check_funding_source(app: QuartTrio) -> None: def check_funding_source(app: QuartTrio) -> None:
@app.before_serving @app.before_serving
async def check_wallet_status(): async def check_wallet_status():
error_message, balance = WALLET.status() error_message, balance = await WALLET.status()
if error_message: if error_message:
warnings.warn( warnings.warn(
f" × The backend for {WALLET.__class__.__name__} isn't working properly: '{error_message}'", f" × The backend for {WALLET.__class__.__name__} isn't working properly: '{error_message}'",

View file

@ -141,9 +141,9 @@ class Payment(NamedTuple):
return return
if self.is_out: if self.is_out:
pending = WALLET.get_payment_status(self.checking_id) pending = await WALLET.get_payment_status(self.checking_id)
else: else:
pending = WALLET.get_invoice_status(self.checking_id) pending = await WALLET.get_invoice_status(self.checking_id)
await self.set_pending(pending.pending) await self.set_pending(pending.pending)

View file

@ -41,7 +41,7 @@ async def create_invoice(
invoice_memo = None if description_hash else memo invoice_memo = None if description_hash else memo
storeable_memo = memo storeable_memo = memo
ok, checking_id, payment_request, error_message = WALLET.create_invoice( ok, checking_id, payment_request, error_message = await WALLET.create_invoice(
amount=amount, memo=invoice_memo, description_hash=description_hash amount=amount, memo=invoice_memo, description_hash=description_hash
) )
if not ok: if not ok:
@ -139,7 +139,7 @@ async def pay_invoice(
await internal_invoice_paid.send(internal_checking_id) await internal_invoice_paid.send(internal_checking_id)
else: else:
# actually pay the external invoice # actually pay the external invoice
payment: PaymentResponse = WALLET.pay_invoice(payment_request) payment: PaymentResponse = await WALLET.pay_invoice(payment_request)
if payment.ok and payment.checking_id: if payment.ok and payment.checking_id:
await create_payment( await create_payment(
checking_id=payment.checking_id, checking_id=payment.checking_id,
@ -255,4 +255,4 @@ async def check_invoice_status(wallet_id: str, payment_hash: str) -> PaymentStat
if not payment: if not payment:
return PaymentStatus(None) return PaymentStatus(None)
return WALLET.get_invoice_status(payment.checking_id) return await WALLET.get_invoice_status(payment.checking_id)

View file

@ -274,7 +274,7 @@ def get_diagonalleys_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]:
f"SELECT * FROM orders WHERE wallet IN ({q})", (*wallet_ids,) f"SELECT * FROM orders WHERE wallet IN ({q})", (*wallet_ids,)
) )
for r in rows: for r in rows:
PAID = WALLET.get_invoice_status(r["invoiceid"]).paid PAID = (await WALLET.get_invoice_status(r["invoiceid"])).paid
if PAID: if PAID:
with open_ext_db("diagonalley") as db: with open_ext_db("diagonalley") as db:
db.execute( db.execute(

View file

@ -133,7 +133,7 @@ async def lndhub_gettxs():
exclude_uncheckable=True, exclude_uncheckable=True,
): ):
await payment.set_pending( await payment.set_pending(
WALLET.get_payment_status(payment.checking_id).pending (await WALLET.get_payment_status(payment.checking_id)).pending
) )
limit = int(request.args.get("limit", 200)) limit = int(request.args.get("limit", 200))
@ -174,7 +174,7 @@ async def lndhub_getuserinvoices():
exclude_uncheckable=True, exclude_uncheckable=True,
): ):
await invoice.set_pending( await invoice.set_pending(
WALLET.get_invoice_status(invoice.checking_id).pending (await WALLET.get_invoice_status(invoice.checking_id)).pending
) )
limit = int(request.args.get("limit", 200)) limit = int(request.args.get("limit", 200))

View file

@ -1,5 +1,5 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import NamedTuple, Optional, AsyncGenerator from typing import NamedTuple, Optional, AsyncGenerator, Coroutine
class StatusResponse(NamedTuple): class StatusResponse(NamedTuple):
@ -15,7 +15,9 @@ class InvoiceResponse(NamedTuple):
class PaymentResponse(NamedTuple): class PaymentResponse(NamedTuple):
ok: bool ok: Optional[
bool
] = None # when ok is None it means we don't know if this succeeded
checking_id: Optional[str] = None # payment_hash, rcp_id checking_id: Optional[str] = None # payment_hash, rcp_id
fee_msat: int = 0 fee_msat: int = 0
preimage: Optional[str] = None preimage: Optional[str] = None
@ -32,7 +34,7 @@ class PaymentStatus(NamedTuple):
class Wallet(ABC): class Wallet(ABC):
@abstractmethod @abstractmethod
def status(self) -> StatusResponse: def status(self) -> Coroutine[None, None, StatusResponse]:
pass pass
@abstractmethod @abstractmethod
@ -41,19 +43,23 @@ class Wallet(ABC):
amount: int, amount: int,
memo: Optional[str] = None, memo: Optional[str] = None,
description_hash: Optional[bytes] = None, description_hash: Optional[bytes] = None,
) -> InvoiceResponse: ) -> Coroutine[None, None, InvoiceResponse]:
pass pass
@abstractmethod @abstractmethod
def pay_invoice(self, bolt11: str) -> PaymentResponse: def pay_invoice(self, bolt11: str) -> Coroutine[None, None, PaymentResponse]:
pass pass
@abstractmethod @abstractmethod
def get_invoice_status(self, checking_id: str) -> PaymentStatus: def get_invoice_status(
self, checking_id: str
) -> Coroutine[None, None, PaymentStatus]:
pass pass
@abstractmethod @abstractmethod
def get_payment_status(self, checking_id: str) -> PaymentStatus: def get_payment_status(
self, checking_id: str
) -> Coroutine[None, None, PaymentStatus]:
pass pass
@abstractmethod @abstractmethod

View file

@ -49,7 +49,7 @@ class CLightningWallet(Wallet):
self.last_pay_index = inv["pay_index"] self.last_pay_index = inv["pay_index"]
break break
def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
try: try:
funds = self.ln.listfunds() funds = self.ln.listfunds()
return StatusResponse( return StatusResponse(
@ -60,7 +60,7 @@ class CLightningWallet(Wallet):
error_message = f"lightningd '{exc.method}' failed with '{exc.error}'." error_message = f"lightningd '{exc.method}' failed with '{exc.error}'."
return StatusResponse(error_message, 0) return StatusResponse(error_message, 0)
def create_invoice( async def create_invoice(
self, self,
amount: int, amount: int,
memo: Optional[str] = None, memo: Optional[str] = None,
@ -84,7 +84,7 @@ class CLightningWallet(Wallet):
error_message = f"lightningd '{exc.method}' failed with '{exc.error}'." error_message = f"lightningd '{exc.method}' failed with '{exc.error}'."
return InvoiceResponse(False, label, None, error_message) return InvoiceResponse(False, label, None, error_message)
def pay_invoice(self, bolt11: str) -> PaymentResponse: async def pay_invoice(self, bolt11: str) -> PaymentResponse:
try: try:
r = self.ln.pay(bolt11) r = self.ln.pay(bolt11)
except RpcError as exc: except RpcError as exc:
@ -94,7 +94,7 @@ class CLightningWallet(Wallet):
preimage = r["payment_preimage"] preimage = r["payment_preimage"]
return PaymentResponse(True, r["payment_hash"], fee_msat, preimage, None) return PaymentResponse(True, r["payment_hash"], fee_msat, preimage, None)
def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
r = self.ln.listinvoices(checking_id) r = self.ln.listinvoices(checking_id)
if not r["invoices"]: if not r["invoices"]:
return PaymentStatus(False) return PaymentStatus(False)
@ -102,7 +102,7 @@ class CLightningWallet(Wallet):
return PaymentStatus(r["invoices"][0]["status"] == "paid") return PaymentStatus(r["invoices"][0]["status"] == "paid")
raise KeyError("supplied an invalid checking_id") raise KeyError("supplied an invalid checking_id")
def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:
r = self.ln.call("listpays", {"payment_hash": checking_id}) r = self.ln.call("listpays", {"payment_hash": checking_id})
if not r["pays"]: if not r["pays"]:
return PaymentStatus(False) return PaymentStatus(False)

View file

@ -25,8 +25,10 @@ class LNbitsWallet(Wallet):
) )
self.key = {"X-Api-Key": key} self.key = {"X-Api-Key": key}
def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
r = httpx.get(url=f"{self.endpoint}/api/v1/wallet", headers=self.key) async with httpx.AsyncClient() as client:
r = await client.get(url=f"{self.endpoint}/api/v1/wallet", headers=self.key)
try: try:
data = r.json() data = r.json()
except: except:
@ -39,7 +41,7 @@ class LNbitsWallet(Wallet):
return StatusResponse(None, data["balance"]) return StatusResponse(None, data["balance"])
def create_invoice( async def create_invoice(
self, self,
amount: int, amount: int,
memo: Optional[str] = None, memo: Optional[str] = None,
@ -51,7 +53,8 @@ class LNbitsWallet(Wallet):
else: else:
data["memo"] = memo or "" data["memo"] = memo or ""
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
url=f"{self.endpoint}/api/v1/payments", url=f"{self.endpoint}/api/v1/payments",
headers=self.key, headers=self.key,
json=data, json=data,
@ -71,8 +74,9 @@ class LNbitsWallet(Wallet):
return InvoiceResponse(ok, checking_id, payment_request, error_message) return InvoiceResponse(ok, checking_id, payment_request, error_message)
def pay_invoice(self, bolt11: str) -> PaymentResponse: async def pay_invoice(self, bolt11: str) -> PaymentResponse:
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
url=f"{self.endpoint}/api/v1/payments", url=f"{self.endpoint}/api/v1/payments",
headers=self.key, headers=self.key,
json={"out": True, "bolt11": bolt11}, json={"out": True, "bolt11": bolt11},
@ -87,8 +91,9 @@ class LNbitsWallet(Wallet):
return PaymentResponse(ok, checking_id, fee_msat, error_message) return PaymentResponse(ok, checking_id, fee_msat, error_message)
def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
r = httpx.get( async with httpx.AsyncClient() as client:
r = await client.get(
url=f"{self.endpoint}/api/v1/payments/{checking_id}", headers=self.key url=f"{self.endpoint}/api/v1/payments/{checking_id}", headers=self.key
) )
@ -97,8 +102,9 @@ class LNbitsWallet(Wallet):
return PaymentStatus(r.json()["paid"]) return PaymentStatus(r.json()["paid"])
def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:
r = httpx.get( async with httpx.AsyncClient() as client:
r = await client.get(
url=f"{self.endpoint}/api/v1/payments/{checking_id}", headers=self.key url=f"{self.endpoint}/api/v1/payments/{checking_id}", headers=self.key
) )

View file

@ -112,7 +112,7 @@ class LndWallet(Wallet):
macaroon_filepath=self.macaroon_path, macaroon_filepath=self.macaroon_path,
) )
def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
try: try:
resp = self.rpc._ln_stub.ChannelBalance(ln.ChannelBalanceRequest()) resp = self.rpc._ln_stub.ChannelBalance(ln.ChannelBalanceRequest())
except Exception as exc: except Exception as exc:
@ -120,7 +120,7 @@ class LndWallet(Wallet):
return StatusResponse(None, resp.balance * 1000) return StatusResponse(None, resp.balance * 1000)
def create_invoice( async def create_invoice(
self, self,
amount: int, amount: int,
memo: Optional[str] = None, memo: Optional[str] = None,
@ -144,7 +144,7 @@ class LndWallet(Wallet):
payment_request = str(resp.payment_request) payment_request = str(resp.payment_request)
return InvoiceResponse(True, checking_id, payment_request, None) return InvoiceResponse(True, checking_id, payment_request, None)
def pay_invoice(self, bolt11: str) -> PaymentResponse: async def pay_invoice(self, bolt11: str) -> PaymentResponse:
resp = self.rpc.send_payment(payment_request=bolt11) resp = self.rpc.send_payment(payment_request=bolt11)
if resp.payment_error: if resp.payment_error:
@ -156,7 +156,7 @@ class LndWallet(Wallet):
preimage = resp.payment_preimage.hex() preimage = resp.payment_preimage.hex()
return PaymentResponse(True, checking_id, fee_msat, preimage, None) return PaymentResponse(True, checking_id, fee_msat, preimage, None)
def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
try: try:
r_hash = parse_checking_id(checking_id) r_hash = parse_checking_id(checking_id)
if len(r_hash) != 32: if len(r_hash) != 32:
@ -172,7 +172,7 @@ class LndWallet(Wallet):
return PaymentStatus(None) return PaymentStatus(None)
def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:
return PaymentStatus(True) return PaymentStatus(True)
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:

View file

@ -35,12 +35,12 @@ class LndRestWallet(Wallet):
self.auth = {"Grpc-Metadata-macaroon": macaroon} self.auth = {"Grpc-Metadata-macaroon": macaroon}
self.cert = getenv("LND_REST_CERT") self.cert = getenv("LND_REST_CERT")
def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
try: try:
r = httpx.get( async with httpx.AsyncClient(verify=self.cert) as client:
r = await client.get(
f"{self.endpoint}/v1/balance/channels", f"{self.endpoint}/v1/balance/channels",
headers=self.auth, headers=self.auth,
verify=self.cert,
) )
except (httpx.ConnectError, httpx.RequestError): except (httpx.ConnectError, httpx.RequestError):
return StatusResponse(f"Unable to connect to {self.endpoint}.", 0) return StatusResponse(f"Unable to connect to {self.endpoint}.", 0)
@ -54,7 +54,7 @@ class LndRestWallet(Wallet):
return StatusResponse(None, int(data["balance"]) * 1000) return StatusResponse(None, int(data["balance"]) * 1000)
def create_invoice( async def create_invoice(
self, self,
amount: int, amount: int,
memo: Optional[str] = None, memo: Optional[str] = None,
@ -71,10 +71,10 @@ class LndRestWallet(Wallet):
else: else:
data["memo"] = memo or "" data["memo"] = memo or ""
r = httpx.post( async with httpx.AsyncClient(verify=self.cert) as client:
r = await client.post(
url=f"{self.endpoint}/v1/invoices", url=f"{self.endpoint}/v1/invoices",
headers=self.auth, headers=self.auth,
verify=self.cert,
json=data, json=data,
) )
@ -93,11 +93,11 @@ class LndRestWallet(Wallet):
return InvoiceResponse(True, checking_id, payment_request, None) return InvoiceResponse(True, checking_id, payment_request, None)
def pay_invoice(self, bolt11: str) -> PaymentResponse: async def pay_invoice(self, bolt11: str) -> PaymentResponse:
r = httpx.post( async with httpx.AsyncClient(verify=self.cert) as client:
r = await client.post(
url=f"{self.endpoint}/v1/channels/transactions", url=f"{self.endpoint}/v1/channels/transactions",
headers=self.auth, headers=self.auth,
verify=self.cert,
json={"payment_request": bolt11}, json={"payment_request": bolt11},
timeout=180, timeout=180,
) )
@ -116,12 +116,13 @@ class LndRestWallet(Wallet):
preimage = base64.b64decode(data["payment_preimage"]).hex() preimage = base64.b64decode(data["payment_preimage"]).hex()
return PaymentResponse(True, checking_id, 0, preimage, None) return PaymentResponse(True, checking_id, 0, preimage, None)
def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
checking_id = checking_id.replace("_", "/") checking_id = checking_id.replace("_", "/")
r = httpx.get(
async with httpx.AsyncClient(verify=self.cert) as client:
r = await client.get(
url=f"{self.endpoint}/v1/invoice/{checking_id}", url=f"{self.endpoint}/v1/invoice/{checking_id}",
headers=self.auth, headers=self.auth,
verify=self.cert,
) )
if r.is_error or not r.json().get("settled"): if r.is_error or not r.json().get("settled"):
@ -131,11 +132,11 @@ class LndRestWallet(Wallet):
return PaymentStatus(True) return PaymentStatus(True)
def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:
r = httpx.get( async with httpx.AsyncClient(verify=self.cert) as client:
r = await client.get(
url=f"{self.endpoint}/v1/payments", url=f"{self.endpoint}/v1/payments",
headers=self.auth, headers=self.auth,
verify=self.cert,
params={"max_payments": "20", "reversed": True}, params={"max_payments": "20", "reversed": True},
) )

View file

@ -24,10 +24,11 @@ class LNPayWallet(Wallet):
self.wallet_key = getenv("LNPAY_WALLET_KEY") or getenv("LNPAY_ADMIN_KEY") self.wallet_key = getenv("LNPAY_WALLET_KEY") or getenv("LNPAY_ADMIN_KEY")
self.auth = {"X-Api-Key": getenv("LNPAY_API_KEY")} self.auth = {"X-Api-Key": getenv("LNPAY_API_KEY")}
def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
url = f"{self.endpoint}/wallet/{self.wallet_key}" url = f"{self.endpoint}/wallet/{self.wallet_key}"
try: try:
r = httpx.get(url, headers=self.auth, timeout=60) async with httpx.AsyncClient() as client:
r = await client.get(url, headers=self.auth, timeout=60)
except (httpx.ConnectError, httpx.RequestError): except (httpx.ConnectError, httpx.RequestError):
return StatusResponse(f"Unable to connect to '{url}'", 0) return StatusResponse(f"Unable to connect to '{url}'", 0)
@ -43,7 +44,7 @@ class LNPayWallet(Wallet):
return StatusResponse(None, data["balance"] * 1000) return StatusResponse(None, data["balance"] * 1000)
def create_invoice( async def create_invoice(
self, self,
amount: int, amount: int,
memo: Optional[str] = None, memo: Optional[str] = None,
@ -55,7 +56,8 @@ class LNPayWallet(Wallet):
else: else:
data["memo"] = memo or "" data["memo"] = memo or ""
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.endpoint}/wallet/{self.wallet_key}/invoice", f"{self.endpoint}/wallet/{self.wallet_key}/invoice",
headers=self.auth, headers=self.auth,
json=data, json=data,
@ -74,8 +76,9 @@ class LNPayWallet(Wallet):
return InvoiceResponse(ok, checking_id, payment_request, error_message) return InvoiceResponse(ok, checking_id, payment_request, error_message)
def pay_invoice(self, bolt11: str) -> PaymentResponse: async def pay_invoice(self, bolt11: str) -> PaymentResponse:
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.endpoint}/wallet/{self.wallet_key}/withdraw", f"{self.endpoint}/wallet/{self.wallet_key}/withdraw",
headers=self.auth, headers=self.auth,
json={"payment_request": bolt11}, json={"payment_request": bolt11},
@ -97,11 +100,12 @@ class LNPayWallet(Wallet):
preimage = data["lnTx"]["payment_preimage"] preimage = data["lnTx"]["payment_preimage"]
return PaymentResponse(True, checking_id, fee_msat, preimage, None) return PaymentResponse(True, checking_id, fee_msat, preimage, None)
def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
return self.get_payment_status(checking_id) return await self.get_payment_status(checking_id)
def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:
r = httpx.get( async with httpx.AsyncClient() as client:
r = await client.get(
url=f"{self.endpoint}/lntx/{checking_id}?fields=settled", url=f"{self.endpoint}/lntx/{checking_id}?fields=settled",
headers=self.auth, headers=self.auth,
) )

View file

@ -27,8 +27,9 @@ class LntxbotWallet(Wallet):
) )
self.auth = {"Authorization": f"Basic {key}"} self.auth = {"Authorization": f"Basic {key}"}
def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
r = httpx.get( async with httpx.AsyncClient() as client:
r = await client.get(
f"{self.endpoint}/balance", f"{self.endpoint}/balance",
headers=self.auth, headers=self.auth,
timeout=40, timeout=40,
@ -45,7 +46,7 @@ class LntxbotWallet(Wallet):
return StatusResponse(None, data["BTC"]["AvailableBalance"] * 1000) return StatusResponse(None, data["BTC"]["AvailableBalance"] * 1000)
def create_invoice( async def create_invoice(
self, self,
amount: int, amount: int,
memo: Optional[str] = None, memo: Optional[str] = None,
@ -57,7 +58,8 @@ class LntxbotWallet(Wallet):
else: else:
data["memo"] = memo or "" data["memo"] = memo or ""
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.endpoint}/addinvoice", f"{self.endpoint}/addinvoice",
headers=self.auth, headers=self.auth,
json=data, json=data,
@ -77,8 +79,9 @@ class LntxbotWallet(Wallet):
data = r.json() data = r.json()
return InvoiceResponse(True, data["payment_hash"], data["pay_req"], None) return InvoiceResponse(True, data["payment_hash"], data["pay_req"], None)
def pay_invoice(self, bolt11: str) -> PaymentResponse: async def pay_invoice(self, bolt11: str) -> PaymentResponse:
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.endpoint}/payinvoice", f"{self.endpoint}/payinvoice",
headers=self.auth, headers=self.auth,
json={"invoice": bolt11}, json={"invoice": bolt11},
@ -101,8 +104,9 @@ class LntxbotWallet(Wallet):
preimage = data["payment_preimage"] preimage = data["payment_preimage"]
return PaymentResponse(True, checking_id, fee_msat, preimage, None) return PaymentResponse(True, checking_id, fee_msat, preimage, None)
def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.endpoint}/invoicestatus/{checking_id}?wait=false", f"{self.endpoint}/invoicestatus/{checking_id}?wait=false",
headers=self.auth, headers=self.auth,
) )
@ -116,8 +120,9 @@ class LntxbotWallet(Wallet):
return PaymentStatus(True) return PaymentStatus(True)
def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
url=f"{self.endpoint}/paymentstatus/{checking_id}", url=f"{self.endpoint}/paymentstatus/{checking_id}",
headers=self.auth, headers=self.auth,
) )

View file

@ -1,4 +1,3 @@
import json
import trio # type: ignore import trio # type: ignore
import hmac import hmac
import httpx import httpx
@ -31,9 +30,10 @@ class OpenNodeWallet(Wallet):
) )
self.auth = {"Authorization": key} self.auth = {"Authorization": key}
def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
try: try:
r = httpx.get( async with httpx.AsyncClient() as client:
r = await client.get(
f"{self.endpoint}/v1/account/balance", f"{self.endpoint}/v1/account/balance",
headers=self.auth, headers=self.auth,
timeout=40, timeout=40,
@ -47,7 +47,7 @@ class OpenNodeWallet(Wallet):
return StatusResponse(None, data["balance"]["BTC"] / 100_000_000_000) return StatusResponse(None, data["balance"]["BTC"] / 100_000_000_000)
def create_invoice( async def create_invoice(
self, self,
amount: int, amount: int,
memo: Optional[str] = None, memo: Optional[str] = None,
@ -56,7 +56,8 @@ class OpenNodeWallet(Wallet):
if description_hash: if description_hash:
raise Unsupported("description_hash") raise Unsupported("description_hash")
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.endpoint}/v1/charges", f"{self.endpoint}/v1/charges",
headers=self.auth, headers=self.auth,
json={ json={
@ -76,8 +77,9 @@ class OpenNodeWallet(Wallet):
payment_request = data["lightning_invoice"]["payreq"] payment_request = data["lightning_invoice"]["payreq"]
return InvoiceResponse(True, checking_id, payment_request, None) return InvoiceResponse(True, checking_id, payment_request, None)
def pay_invoice(self, bolt11: str) -> PaymentResponse: async def pay_invoice(self, bolt11: str) -> PaymentResponse:
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.endpoint}/v2/withdrawals", f"{self.endpoint}/v2/withdrawals",
headers=self.auth, headers=self.auth,
json={"type": "ln", "address": bolt11}, json={"type": "ln", "address": bolt11},
@ -93,16 +95,22 @@ class OpenNodeWallet(Wallet):
fee_msat = data["fee"] * 1000 fee_msat = data["fee"] * 1000
return PaymentResponse(True, checking_id, fee_msat, None, None) return PaymentResponse(True, checking_id, fee_msat, None, None)
def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
r = httpx.get(f"{self.endpoint}/v1/charge/{checking_id}", headers=self.auth) async with httpx.AsyncClient() as client:
r = await client.get(
f"{self.endpoint}/v1/charge/{checking_id}", headers=self.auth
)
if r.is_error: if r.is_error:
return PaymentStatus(None) return PaymentStatus(None)
statuses = {"processing": None, "paid": True, "unpaid": False} statuses = {"processing": None, "paid": True, "unpaid": False}
return PaymentStatus(statuses[r.json()["data"]["status"]]) return PaymentStatus(statuses[r.json()["data"]["status"]])
def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:
r = httpx.get(f"{self.endpoint}/v1/withdrawal/{checking_id}", headers=self.auth) async with httpx.AsyncClient() as client:
r = await client.get(
f"{self.endpoint}/v1/withdrawal/{checking_id}", headers=self.auth
)
if r.is_error: if r.is_error:
return PaymentStatus(None) return PaymentStatus(None)

View file

@ -28,7 +28,7 @@ class SparkWallet(Wallet):
self.token = getenv("SPARK_TOKEN") self.token = getenv("SPARK_TOKEN")
def __getattr__(self, key): def __getattr__(self, key):
def call(*args, **kwargs): async def call(*args, **kwargs):
if args and kwargs: if args and kwargs:
raise TypeError( raise TypeError(
f"must supply either named arguments or a list of arguments, not both: {args} {kwargs}" f"must supply either named arguments or a list of arguments, not both: {args} {kwargs}"
@ -40,12 +40,14 @@ class SparkWallet(Wallet):
else: else:
params = {} params = {}
r = httpx.post( async with httpx.AsyncClient() as client:
r = await client.post(
self.url + "/rpc", self.url + "/rpc",
headers={"X-Access": self.token}, headers={"X-Access": self.token},
json={"method": key, "params": params}, json={"method": key, "params": params},
timeout=40, timeout=40,
) )
try: try:
data = r.json() data = r.json()
except: except:
@ -61,9 +63,9 @@ class SparkWallet(Wallet):
return call return call
def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
try: try:
funds = self.listfunds() funds = await self.listfunds()
except (httpx.ConnectError, httpx.RequestError): except (httpx.ConnectError, httpx.RequestError):
return StatusResponse("Couldn't connect to Spark server", 0) return StatusResponse("Couldn't connect to Spark server", 0)
except (SparkError, UnknownError) as e: except (SparkError, UnknownError) as e:
@ -74,7 +76,7 @@ class SparkWallet(Wallet):
sum([ch["channel_sat"] * 1000 for ch in funds["channels"]]), sum([ch["channel_sat"] * 1000 for ch in funds["channels"]]),
) )
def create_invoice( async def create_invoice(
self, self,
amount: int, amount: int,
memo: Optional[str] = None, memo: Optional[str] = None,
@ -85,13 +87,13 @@ class SparkWallet(Wallet):
try: try:
if description_hash: if description_hash:
r = self.invoicewithdescriptionhash( r = await self.invoicewithdescriptionhash(
msatoshi=amount * 1000, msatoshi=amount * 1000,
label=label, label=label,
description_hash=description_hash.hex(), description_hash=description_hash.hex(),
) )
else: else:
r = self.invoice( r = await self.invoice(
msatoshi=amount * 1000, msatoshi=amount * 1000,
label=label, label=label,
description=memo or "", description=memo or "",
@ -103,9 +105,9 @@ class SparkWallet(Wallet):
return InvoiceResponse(ok, checking_id, payment_request, error_message) return InvoiceResponse(ok, checking_id, payment_request, error_message)
def pay_invoice(self, bolt11: str) -> PaymentResponse: async def pay_invoice(self, bolt11: str) -> PaymentResponse:
try: try:
r = self.pay(bolt11) r = await self.pay(bolt11)
except (SparkError, UnknownError) as exc: except (SparkError, UnknownError) as exc:
return PaymentResponse(False, None, 0, None, str(exc)) return PaymentResponse(False, None, 0, None, str(exc))
@ -113,15 +115,15 @@ class SparkWallet(Wallet):
preimage = r["payment_preimage"] preimage = r["payment_preimage"]
return PaymentResponse(True, r["payment_hash"], fee_msat, preimage, None) return PaymentResponse(True, r["payment_hash"], fee_msat, preimage, None)
def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
r = self.listinvoices(label=checking_id) r = await self.listinvoices(label=checking_id)
if not r or not r.get("invoices"): if not r or not r.get("invoices"):
return PaymentStatus(None) return PaymentStatus(None)
if r["invoices"][0]["status"] == "unpaid": if r["invoices"][0]["status"] == "unpaid":
return PaymentStatus(False) return PaymentStatus(False)
return PaymentStatus(True) return PaymentStatus(True)
def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:
# check if it's 32 bytes hex # check if it's 32 bytes hex
if len(checking_id) != 64: if len(checking_id) != 64:
return PaymentStatus(None) return PaymentStatus(None)
@ -131,7 +133,7 @@ class SparkWallet(Wallet):
return PaymentStatus(None) return PaymentStatus(None)
# ask sparko # ask sparko
r = self.listpays(payment_hash=checking_id) r = await self.listpays(payment_hash=checking_id)
if not r["pays"]: if not r["pays"]:
return PaymentStatus(False) return PaymentStatus(False)
if r["pays"][0]["payment_hash"] == checking_id: if r["pays"][0]["payment_hash"] == checking_id:

View file

@ -11,7 +11,7 @@ from .base import (
class VoidWallet(Wallet): class VoidWallet(Wallet):
def create_invoice( async def create_invoice(
self, self,
amount: int, amount: int,
memo: Optional[str] = None, memo: Optional[str] = None,
@ -19,19 +19,19 @@ class VoidWallet(Wallet):
) -> InvoiceResponse: ) -> InvoiceResponse:
raise Unsupported("") raise Unsupported("")
def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
return StatusResponse( return StatusResponse(
"This backend does nothing, it is here just as a placeholder, you must configure an actual backend before being able to do anything useful with LNbits.", "This backend does nothing, it is here just as a placeholder, you must configure an actual backend before being able to do anything useful with LNbits.",
0, 0,
) )
def pay_invoice(self, bolt11: str) -> PaymentResponse: async def pay_invoice(self, bolt11: str) -> PaymentResponse:
raise Unsupported("") raise Unsupported("")
def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
raise Unsupported("") raise Unsupported("")
def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:
raise Unsupported("") raise Unsupported("")
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: