diff --git a/.env.example b/.env.example index eedf248..9a47cd7 100644 --- a/.env.example +++ b/.env.example @@ -29,34 +29,28 @@ CLIGHTNING_RPC="/home/bob/.lightning/bitcoin/lightning-rpc" # LnbitsWallet LNBITS_ENDPOINT=http://127.0.0.1:5000 -LNBITS_INVOICE_KEY=LNBITS_INVOICE_KEY -LNBITS_ADMIN_KEY=LNBITS_ADMIN_KEY +LNBITS_KEY=LNBITS_ADMIN_KEY # LndWallet LND_GRPC_ENDPOINT=127.0.0.1 LND_GRPC_PORT=11009 LND_GRPC_CERT="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/tls.cert" -LND_GRPC_ADMIN_MACAROON="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/admin.macaroon" -LND_GRPC_INVOICE_MACAROON="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/invoice.macaroon" +LND_GRPC_MACAROON="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/admin.macaroon" # LndRestWallet LND_REST_ENDPOINT=https://127.0.0.1:8080/ LND_REST_CERT="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/tls.cert" -LND_REST_ADMIN_MACAROON="HEXSTRING" -LND_REST_INVOICE_MACAROON="HEXSTRING" +LND_REST_MACAROON="HEXSTRING" # LNPayWallet LNPAY_API_ENDPOINT=https://lnpay.co/v1/ LNPAY_API_KEY=LNPAY_API_KEY -LNPAY_ADMIN_KEY=LNPAY_ADMIN_KEY -LNPAY_INVOICE_KEY=LNPAY_INVOICE_KEY +LNPAY_WALLET_KEY=LNPAY_ADMIN_KEY # LntxbotWallet LNTXBOT_API_ENDPOINT=https://lntxbot.bigsun.xyz/ -LNTXBOT_ADMIN_KEY=LNTXBOT_ADMIN_KEY -LNTXBOT_INVOICE_KEY=LNTXBOT_INVOICE_KEY +LNTXBOT_KEY=LNTXBOT_ADMIN_KEY # OpenNodeWallet OPENNODE_API_ENDPOINT=https://api.opennode.com/ -OPENNODE_ADMIN_KEY=OPENNODE_ADMIN_KEY -OPENNODE_INVOICE_KEY=OPENNODE_INVOICE_KEY +OPENNODE_KEY=OPENNODE_ADMIN_KEY diff --git a/Pipfile b/Pipfile index ca5cfe0..0dbc626 100644 --- a/Pipfile +++ b/Pipfile @@ -13,7 +13,6 @@ ecdsa = "*" environs = "*" lnurl = "*" pyscss = "*" -requests = "*" shortuuid = "*" quart = "*" quart-cors = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 2358d8a..0146f90 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "76a3823f58d720ea680fdcd246f2a8b5fa16ce0a87a650e5e9fff5559dca7309" + "sha256": "193ef930ac0906127fd292b2fc7ba5b4d786227b6795d182dad9b57448fca75e" }, "pipfile-spec": 6, "requires": { @@ -106,13 +106,6 @@ ], "version": "==2020.6.20" }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, "click": { "hashes": [ "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", @@ -139,10 +132,10 @@ }, "h11": { "hashes": [ - "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1", - "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1" + "sha256:3c6c61d69c6f13d41f1b80ab0322f1872702a3ba26e12aa864c928f6a43fbaab", + "sha256:ab6c335e1b6ef34b205d5ca3e228c9299cc7218b049819ec84a388c2525e5d87" ], - "version": "==0.9.0" + "version": "==0.11.0" }, "h2": { "hashes": [ @@ -162,30 +155,30 @@ }, "httpcore": { "hashes": [ - "sha256:72cfaa461dbdc262943ff4c9abf5b195391a03cdcc152e636adb4239b15e77e1", - "sha256:a35dddd1f4cc34ff37788337ef507c0ad0276241ece6daf663ac9e77c0b87232" + "sha256:18c4afcbfe884b635e59739105aed1692e132bc5d31597109f3c1c97e4ec1cac", + "sha256:2526a38f31ac5967d38b7f593b5d8c4bd3fa82c21400402f866ba3312946acbf" ], "markers": "python_version >= '3.6'", - "version": "==0.11.1" + "version": "==0.12.0" }, "httpx": { "hashes": [ - "sha256:02326f2d3c61133db31e4b88dd3432479b434e52a68d813eab6db930f13611ea", - "sha256:254b371e3880a8e2387bf9ead6949bac797bd557fda26eba19a6153a0c06bd2b" + "sha256:126424c279c842738805974687e0518a94c7ae8d140cd65b9c4f77ac46ffa537", + "sha256:9cffb8ba31fac6536f2c8cde30df859013f59e4bcc5b8d43901cb3654a8e0a5b" ], "index": "pypi", - "version": "==0.15.5" + "version": "==0.16.1" }, "hypercorn": { "extras": [ "trio" ], "hashes": [ - "sha256:6540faeba9dd44f7e74c7cc1beae3a438a7efb5f77323d1199457da46d32c2c2", - "sha256:b5c479023757e279f954b46a4ec9dd85e58a2bcbf4d959d5601cbced593e711d" + "sha256:81c69dd84a87b8e8b3ebf06ef5dd92836a8238f0ac65ded3d86befb8ba9acfeb", + "sha256:e3f317d6d64d15ce589f49e4f5057947259fa35332d169e62cb060e9997189e4" ], "index": "pypi", - "version": "==0.11.0" + "version": "==0.11.1" }, "hyperframe": { "hashes": [ @@ -356,14 +349,6 @@ "index": "pypi", "version": "==0.5.1" }, - "requests": { - "hashes": [ - "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", - "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898" - ], - "index": "pypi", - "version": "==2.24.0" - }, "rfc3986": { "extras": [ "idna2008" @@ -437,14 +422,6 @@ "index": "pypi", "version": "==3.7.4.3" }, - "urllib3": { - "hashes": [ - "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a", - "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.25.10" - }, "werkzeug": { "hashes": [ "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43", @@ -657,12 +634,17 @@ "hashes": [ "sha256:088afc8c63e7bd187a3c70a94b9e50ab3f17e1d3f52a32750b5b77dbe99ef5ef", "sha256:1fe0a41437bbd06063aa184c34804efa886bcc128222e9916310c92cd54c3b4c", + "sha256:3d20024a70b97b4f9546696cbf2fd30bae5f42229fbddf8661261b1eaff0deb7", "sha256:41bb65f54bba392643557e617316d0d899ed5b4946dccee1cb6696152b29844b", "sha256:4318d56bccfe7d43e5addb272406ade7a2274da4b70eb15922a071c58ab0108c", "sha256:4707f3695b34335afdfb09be3802c87fa0bc27030471dbc082f815f23688bc63", + "sha256:49f23ebd5ac073765ecbcf046edc10d63dcab2f4ae2bce160982cb30df0c0302", "sha256:5533a959a1748a5c042a6da71fe9267a908e21eded7a4f373efd23a2cbdb0ecc", + "sha256:5d892a4f1c999834eaa3c32bc9e8b976c5825116cde553928c4c8e7e48ebda67", "sha256:5f18875ac23d9aa2f060838e8b79093e8bb2313dbaaa9f54c6d8e52a5df097be", "sha256:60b0e9e6dc45683e569ec37c55ac20c582973841927a85f2d8a7d20ee80216ab", + "sha256:816064fc915796ea1f26966163f6845de5af78923dfcecf6551e095f00983650", + "sha256:84cada8effefe9a9f53f9b0d2ba9b7b6f5edf8d2155f9fdbe34616e06ececf81", "sha256:84e9407db1b2eb368b7ecc283121b5e592c9aaedbe8c78b1a2f1102eb2e21d19", "sha256:8d69cef61fa50c8133382e61fd97439de1ae623fe943578e477e76a9d9471637", "sha256:9a02d0ae31d35e1ec12a4ea4d4cca990800f66a917d0fb997b20fbc13f5321fc", @@ -670,6 +652,7 @@ "sha256:a6f32aea4260dfe0e55dc9733ea162ea38f0ea86aa7d0f77b15beac5bf7b369d", "sha256:ae91972f8ac958039920ef6e8769277c084971a142ce2b660691793ae44aae6b", "sha256:c570f6fa14b9c4c8a4924aaad354652366577b4f98213cf76305067144f7b100", + "sha256:c9443124c67b1515e4fe0bb0aa18df640965e1030f468a2a5dc2589b26d130ad", "sha256:d23a18037313714fb3bb5a94434d3151ee4300bae631894b1ac08111abeaa4a3", "sha256:eaf548d117b6737df379fdd53bdde4f08870e66d7ea653e230477f071f861121", "sha256:ebbe29186a3d9b0c591e71b7393f1ae08c83cb2d8e517d2a822b8f7ec99dfd8b", diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index bd19830..2f85c7f 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -1,5 +1,6 @@ import trio # type: ignore import json +import traceback from quart import g, jsonify, request, make_response from http import HTTPStatus from binascii import unhexlify @@ -87,10 +88,10 @@ async def api_payments_pay_invoice(): return jsonify({"message": str(e)}), HTTPStatus.BAD_REQUEST except PermissionError as e: return jsonify({"message": str(e)}), HTTPStatus.FORBIDDEN - except Exception as e: - print(e) + except Exception as exc: + traceback.print_exc(7) g.db.rollback() - return jsonify({"message": str(e)}), HTTPStatus.INTERNAL_SERVER_ERROR + return jsonify({"message": str(exc)}), HTTPStatus.INTERNAL_SERVER_ERROR return ( jsonify( diff --git a/lnbits/extensions/amilk/views_api.py b/lnbits/extensions/amilk/views_api.py index c61a4fc..2ad85c3 100644 --- a/lnbits/extensions/amilk/views_api.py +++ b/lnbits/extensions/amilk/views_api.py @@ -1,4 +1,4 @@ -import requests +import httpx from quart import g, jsonify, request, abort from http import HTTPStatus from lnurl import LnurlWithdrawResponse, handle as handle_lnurl @@ -38,12 +38,12 @@ async def api_amilkit(amilk_id): wallet_id=milk.wallet, amount=withdraw_res.max_sats, memo=memo, extra={"tag": "amilk"} ) - r = requests.get( + r = httpx.get( withdraw_res.callback.base, params={**withdraw_res.callback.query_params, **{"k1": withdraw_res.k1, "pr": payment_request}}, ) - if not r.ok: + if r.is_error: abort(HTTPStatus.INTERNAL_SERVER_ERROR, "Could not process withdraw LNURL.") for i in range(10): diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py index ff182d9..a7ef582 100644 --- a/lnbits/extensions/diagonalley/crud.py +++ b/lnbits/extensions/diagonalley/crud.py @@ -1,7 +1,7 @@ from base64 import urlsafe_b64encode from uuid import uuid4 from typing import List, Optional, Union -import requests +import httpx from lnbits.db import open_ext_db from lnbits.settings import WALLET from .models import Products, Orders, Indexers @@ -120,7 +120,7 @@ def get_diagonalleys_indexer(indexer_id: str) -> Optional[Indexers]: with open_ext_db("diagonalley") as db: roww = db.fetchone("SELECT * FROM indexers WHERE id = ?", (indexer_id,)) try: - x = requests.get(roww["indexeraddress"] + "/" + roww["ratingkey"]) + x = httpx.get(roww["indexeraddress"] + "/" + roww["ratingkey"]) if x.status_code == 200: print(x) print("poo") @@ -158,7 +158,7 @@ def get_diagonalleys_indexers(wallet_ids: Union[str, List[str]]) -> List[Indexer for r in rows: try: - x = requests.get(r["indexeraddress"] + "/" + r["ratingkey"]) + x = httpx.get(r["indexeraddress"] + "/" + r["ratingkey"]) if x.status_code == 200: with open_ext_db("diagonalley") as db: db.execute( diff --git a/lnbits/extensions/example/views_api.py b/lnbits/extensions/example/views_api.py index e3296f9..095ddce 100644 --- a/lnbits/extensions/example/views_api.py +++ b/lnbits/extensions/example/views_api.py @@ -3,7 +3,9 @@ # add your dependencies here # import json -# import requests +# import httpx +# (use httpx just like requests, except instead of response.ok there's only the +# response.is_error that is its inverse) from quart import jsonify from http import HTTPStatus diff --git a/lnbits/wallets/clightning.py b/lnbits/wallets/clightning.py index 852db35..5444d8d 100644 --- a/lnbits/wallets/clightning.py +++ b/lnbits/wallets/clightning.py @@ -73,7 +73,7 @@ class CLightningWallet(Wallet): raise KeyError("supplied an invalid checking_id") def get_payment_status(self, checking_id: str) -> PaymentStatus: - r = self.ln.listpays(payment_hash=checking_id) + r = self.ln.call("listpays", {"payment_hash": checking_id}) if not r["pays"]: return PaymentStatus(False) if r["pays"][0]["payment_hash"] == checking_id: diff --git a/lnbits/wallets/lnbits.py b/lnbits/wallets/lnbits.py index 4a470fe..f014bf4 100644 --- a/lnbits/wallets/lnbits.py +++ b/lnbits/wallets/lnbits.py @@ -1,7 +1,7 @@ import trio # type: ignore +import httpx from os import getenv from typing import Optional, Dict, AsyncGenerator -from requests import get, post from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet @@ -11,8 +11,9 @@ class LNbitsWallet(Wallet): def __init__(self): self.endpoint = getenv("LNBITS_ENDPOINT") - self.auth_admin = {"X-Api-Key": getenv("LNBITS_ADMIN_KEY")} - self.auth_invoice = {"X-Api-Key": getenv("LNBITS_INVOICE_KEY")} + + key = getenv("LNBITS_KEY") or getenv("LNBITS_ADMIN_KEY") or getenv("LNBITS_INVOICE_KEY") + self.key = {"X-Api-Key": key} def create_invoice( self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None @@ -23,45 +24,45 @@ class LNbitsWallet(Wallet): else: data["memo"] = memo or "" - r = post( + r = httpx.post( url=f"{self.endpoint}/api/v1/payments", - headers=self.auth_invoice, + headers=self.key, json=data, ) - ok, checking_id, payment_request, error_message = r.ok, None, None, None + ok, checking_id, payment_request, error_message = not r.is_error, None, None, None - if r.ok: + if r.is_error: + error_message = r.json()["message"] + else: data = r.json() checking_id, payment_request = data["checking_id"], data["payment_request"] - else: - error_message = r.json()["message"] return InvoiceResponse(ok, checking_id, payment_request, error_message) def pay_invoice(self, bolt11: str) -> PaymentResponse: - r = post(url=f"{self.endpoint}/api/v1/payments", headers=self.auth_admin, json={"out": True, "bolt11": bolt11}) - ok, checking_id, fee_msat, error_message = True, None, 0, None + r = httpx.post(url=f"{self.endpoint}/api/v1/payments", headers=self.key, json={"out": True, "bolt11": bolt11}) + ok, checking_id, fee_msat, error_message = not r.is_error, None, 0, None - if r.ok: + if r.is_error: + error_message = r.json()["message"] + else: data = r.json() checking_id = data["checking_id"] - else: - error_message = r.json()["message"] return PaymentResponse(ok, checking_id, fee_msat, error_message) def get_invoice_status(self, checking_id: str) -> PaymentStatus: - r = get(url=f"{self.endpoint}/api/v1/payments/{checking_id}", headers=self.auth_invoice) + r = httpx.get(url=f"{self.endpoint}/api/v1/payments/{checking_id}", headers=self.key) - if not r.ok: + if r.is_error: return PaymentStatus(None) return PaymentStatus(r.json()["paid"]) def get_payment_status(self, checking_id: str) -> PaymentStatus: - r = get(url=f"{self.endpoint}/api/v1/payments/{checking_id}", headers=self.auth_invoice) + r = httpx.get(url=f"{self.endpoint}/api/v1/payments/{checking_id}", headers=self.key) - if not r.ok: + if r.is_error: return PaymentStatus(None) return PaymentStatus(r.json()["paid"]) diff --git a/lnbits/wallets/lndgrpc.py b/lnbits/wallets/lndgrpc.py index 1a084b6..5c25f99 100644 --- a/lnbits/wallets/lndgrpc.py +++ b/lnbits/wallets/lndgrpc.py @@ -46,22 +46,28 @@ class LndWallet(Wallet): self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint self.port = int(getenv("LND_GRPC_PORT")) self.cert_path = getenv("LND_GRPC_CERT") or getenv("LND_CERT") - self.auth_admin = getenv("LND_GRPC_ADMIN_MACAROON") or getenv("LND_ADMIN_MACAROON") - self.auth_invoices = getenv("LND_GRPC_INVOICE_MACAROON") or getenv("LND_INVOICE_MACAROON") + + self.macaroon_path = ( + getenv("LND_GRPC_MACAROON") + or getenv("LND_GRPC_ADMIN_MACAROON") + or getenv("LND_ADMIN_MACAROON") + or getenv("LND_GRPC_INVOICE_MACAROON") + or getenv("LND_INVOICE_MACAROON") + ) network = getenv("LND_GRPC_NETWORK", "mainnet") self.admin_rpc = lndgrpc.LNDClient( f"{self.endpoint}:{self.port}", cert_filepath=self.cert_path, network=network, - macaroon_filepath=self.auth_admin, + macaroon_filepath=self.macaroon_path, ) self.invoices_rpc = lndgrpc.LNDClient( f"{self.endpoint}:{self.port}", cert_filepath=self.cert_path, network=network, - macaroon_filepath=self.auth_invoices, + macaroon_filepath=self.macaroon_path, ) def create_invoice( @@ -129,7 +135,7 @@ class LndWallet(Wallet): ln.Invoice, ), ) - macaroon = load_macaroon(self.auth_admin) + macaroon = load_macaroon(self.macaroon_path) async for inv in subscribe_invoices( ln.InvoiceSubscription(), diff --git a/lnbits/wallets/lndrest.py b/lnbits/wallets/lndrest.py index 7ff8e8c..309cfe3 100644 --- a/lnbits/wallets/lndrest.py +++ b/lnbits/wallets/lndrest.py @@ -11,19 +11,20 @@ class LndRestWallet(Wallet): """https://api.lightning.community/rest/index.html#lnd-rest-api-reference""" def __init__(self): - endpoint = getenv("LND_REST_ENDPOINT") endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint endpoint = "https://" + endpoint if not endpoint.startswith("http") else endpoint self.endpoint = endpoint - self.auth_admin = { - "Grpc-Metadata-macaroon": getenv("LND_ADMIN_MACAROON") or getenv("LND_REST_ADMIN_MACAROON"), - } - self.auth_invoice = { - "Grpc-Metadata-macaroon": getenv("LND_INVOICE_MACAROON") or getenv("LND_REST_INVOICE_MACAROON") - } - self.auth_cert = getenv("LND_REST_CERT") + macaroon = ( + getenv("LND_MACAROON") + or getenv("LND_ADMIN_MACAROON") + or getenv("LND_REST_ADMIN_MACAROON") + or getenv("LND_INVOICE_MACAROON") + or getenv("LND_REST_INVOICE_MACAROON") + ) + self.auth = {"Grpc-Metadata-macaroon": macaroon} + self.cert = getenv("LND_REST_CERT") def create_invoice( self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None @@ -39,8 +40,8 @@ class LndRestWallet(Wallet): r = httpx.post( url=f"{self.endpoint}/v1/invoices", - headers=self.auth_invoice, - verify=self.auth_cert, + headers=self.auth, + verify=self.cert, json=data, ) @@ -62,8 +63,8 @@ class LndRestWallet(Wallet): def pay_invoice(self, bolt11: str) -> PaymentResponse: r = httpx.post( url=f"{self.endpoint}/v1/channels/transactions", - headers=self.auth_admin, - verify=self.auth_cert, + headers=self.auth, + verify=self.cert, json={"payment_request": bolt11}, ) @@ -84,8 +85,8 @@ class LndRestWallet(Wallet): checking_id = checking_id.replace("_", "/") r = httpx.get( url=f"{self.endpoint}/v1/invoice/{checking_id}", - headers=self.auth_invoice, - verify=self.auth_cert, + headers=self.auth, + verify=self.cert, ) if r.is_error or not r.json().get("settled"): @@ -98,8 +99,8 @@ class LndRestWallet(Wallet): def get_payment_status(self, checking_id: str) -> PaymentStatus: r = httpx.get( url=f"{self.endpoint}/v1/payments", - headers=self.auth_admin, - verify=self.auth_cert, + headers=self.auth, + verify=self.cert, params={"include_incomplete": "True", "max_payments": "20"}, ) @@ -118,7 +119,7 @@ class LndRestWallet(Wallet): async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: url = self.endpoint + "/v1/invoices/subscribe" - async with httpx.AsyncClient(timeout=None, headers=self.auth_admin, verify=self.auth_cert) as client: + async with httpx.AsyncClient(timeout=None, headers=self.auth, verify=self.cert) as client: async with client.stream("GET", url) as r: async for line in r.aiter_lines(): try: diff --git a/lnbits/wallets/lnpay.py b/lnbits/wallets/lnpay.py index 782615b..8543219 100644 --- a/lnbits/wallets/lnpay.py +++ b/lnbits/wallets/lnpay.py @@ -15,8 +15,8 @@ class LNPayWallet(Wallet): def __init__(self): endpoint = getenv("LNPAY_API_ENDPOINT", "https://lnpay.co/v1") self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint - self.auth_admin = getenv("LNPAY_ADMIN_KEY") - self.auth_api = {"X-Api-Key": getenv("LNPAY_API_KEY")} + self.wallet_key = getenv("LNPAY_WALLET_KEY") or getenv("LNPAY_ADMIN_KEY") + self.auth = {"X-Api-Key": getenv("LNPAY_API_KEY")} def create_invoice( self, @@ -31,8 +31,8 @@ class LNPayWallet(Wallet): data["memo"] = memo or "" r = httpx.post( - url=f"{self.endpoint}/user/wallet/{self.auth_admin}/invoice", - headers=self.auth_api, + url=f"{self.endpoint}/user/wallet/{self.wallet_key}/invoice", + headers=self.auth, json=data, ) ok, checking_id, payment_request, error_message = ( @@ -50,8 +50,8 @@ class LNPayWallet(Wallet): def pay_invoice(self, bolt11: str) -> PaymentResponse: r = httpx.post( - url=f"{self.endpoint}/user/wallet/{self.auth_admin}/withdraw", - headers=self.auth_api, + url=f"{self.endpoint}/user/wallet/{self.wallet_key}/withdraw", + headers=self.auth, json={"payment_request": bolt11}, ) ok, checking_id, fee_msat, error_message = r.status_code == 201, None, 0, None @@ -67,7 +67,7 @@ class LNPayWallet(Wallet): def get_payment_status(self, checking_id: str) -> PaymentStatus: r = httpx.get( url=f"{self.endpoint}/user/lntx/{checking_id}?fields=settled", - headers=self.auth_api, + headers=self.auth, ) if r.is_error: @@ -91,7 +91,7 @@ class LNPayWallet(Wallet): async with httpx.AsyncClient() as client: r = await client.get( f"{self.endpoint}/user/lntx/{lntx_id}?fields=settled", - headers=self.auth_api, + headers=self.auth, ) data = r.json() if data["settled"]: diff --git a/lnbits/wallets/lntxbot.py b/lnbits/wallets/lntxbot.py index 1bbcd4d..9ad7efa 100644 --- a/lnbits/wallets/lntxbot.py +++ b/lnbits/wallets/lntxbot.py @@ -1,7 +1,7 @@ import trio # type: ignore +import httpx from os import getenv from typing import Optional, Dict, AsyncGenerator -from requests import post from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet @@ -12,8 +12,9 @@ class LntxbotWallet(Wallet): def __init__(self): endpoint = getenv("LNTXBOT_API_ENDPOINT") self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint - self.auth_admin = {"Authorization": f"Basic {getenv('LNTXBOT_ADMIN_KEY')}"} - self.auth_invoice = {"Authorization": f"Basic {getenv('LNTXBOT_INVOICE_KEY')}"} + + key = getenv("LNTXBOT_KEY") or getenv("LNTXBOT_ADMIN_KEY") or getenv("LNTXBOT_INVOICE_KEY") + self.auth = {"Authorization": f"Basic {key}"} def create_invoice( self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None @@ -24,44 +25,47 @@ class LntxbotWallet(Wallet): else: data["memo"] = memo or "" - r = post( + r = httpx.post( url=f"{self.endpoint}/addinvoice", - headers=self.auth_invoice, + headers=self.auth, json=data, ) - ok, checking_id, payment_request, error_message = r.ok, None, None, None - - if r.ok: - data = r.json() - checking_id, payment_request = data["payment_hash"], data["pay_req"] - if "error" in data and data["error"]: - ok = False + if r.is_error: + try: + data = r.json() error_message = data["message"] + except: + error_message = r.text + pass - return InvoiceResponse(ok, checking_id, payment_request, error_message) + return InvoiceResponse(False, None, None, error_message) + + data = r.json() + return InvoiceResponse(True, data["payment_hash"], data["pay_req"], None) def pay_invoice(self, bolt11: str) -> PaymentResponse: - r = post(url=f"{self.endpoint}/payinvoice", headers=self.auth_admin, json={"invoice": bolt11}) - ok, checking_id, fee_msat, error_message = r.ok, None, 0, None + r = httpx.post(url=f"{self.endpoint}/payinvoice", headers=self.auth, json={"invoice": bolt11}) - if r.ok: - data = r.json() + if r.is_error: + try: + data = r.json() + error_message = data["message"] + except: + error_message = r.text + pass - if "payment_hash" in data: - checking_id, fee_msat = data["decoded"]["payment_hash"], data["fee_msat"] - elif "error" in data and data["error"]: - ok, error_message = False, data["message"] + return PaymentResponse(False, None, 0, error_message) - return PaymentResponse(ok, checking_id, fee_msat, error_message) + data = r.json() + return PaymentResponse(True, data["decoded"]["payment_hash"], data["fee_msat"], None) def get_invoice_status(self, checking_id: str) -> PaymentStatus: - r = post(url=f"{self.endpoint}/invoicestatus/{checking_id}?wait=false", headers=self.auth_invoice) - - if not r.ok or "error" in r.json(): - return PaymentStatus(None) + r = httpx.post(url=f"{self.endpoint}/invoicestatus/{checking_id}?wait=false", headers=self.auth) data = r.json() + if r.is_error or "error" in data: + return PaymentStatus(None) if "preimage" not in data: return PaymentStatus(False) @@ -69,13 +73,14 @@ class LntxbotWallet(Wallet): return PaymentStatus(True) def get_payment_status(self, checking_id: str) -> PaymentStatus: - r = post(url=f"{self.endpoint}/paymentstatus/{checking_id}", headers=self.auth_invoice) + r = httpx.post(url=f"{self.endpoint}/paymentstatus/{checking_id}", headers=self.auth) - if not r.ok or "error" in r.json(): + data = r.json() + if r.is_error or "error" in data: return PaymentStatus(None) statuses = {"complete": True, "failed": False, "pending": None, "unknown": None} - return PaymentStatus(statuses[r.json().get("status", "unknown")]) + return PaymentStatus(statuses[data.get("status", "unknown")]) async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: print("lntxbot does not support paid invoices stream yet") diff --git a/lnbits/wallets/opennode.py b/lnbits/wallets/opennode.py index 497afd2..3568f9e 100644 --- a/lnbits/wallets/opennode.py +++ b/lnbits/wallets/opennode.py @@ -16,8 +16,9 @@ class OpenNodeWallet(Wallet): def __init__(self): endpoint = getenv("OPENNODE_API_ENDPOINT") self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint - self.auth_admin = {"Authorization": getenv("OPENNODE_ADMIN_KEY")} - self.auth_invoice = {"Authorization": getenv("OPENNODE_INVOICE_KEY")} + + key = getenv("OPENNODE_KEY") or getenv("OPENNODE_ADMIN_KEY") or getenv("OPENNODE_INVOICE_KEY") + self.auth = {"Authorization": key} def create_invoice( self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None @@ -45,9 +46,7 @@ class OpenNodeWallet(Wallet): return InvoiceResponse(True, checking_id, payment_request, None) def pay_invoice(self, bolt11: str) -> PaymentResponse: - r = httpx.post( - f"{self.endpoint}/v2/withdrawals", headers=self.auth_admin, json={"type": "ln", "address": bolt11} - ) + r = httpx.post(f"{self.endpoint}/v2/withdrawals", headers=self.auth, json={"type": "ln", "address": bolt11}) if r.is_error: error_message = r.json()["message"] @@ -68,7 +67,7 @@ class OpenNodeWallet(Wallet): return PaymentStatus(statuses[r.json()["data"]["status"]]) def get_payment_status(self, checking_id: str) -> PaymentStatus: - r = httpx.get(f"{self.endpoint}/v1/withdrawal/{checking_id}", headers=self.auth_admin) + r = httpx.get(f"{self.endpoint}/v1/withdrawal/{checking_id}", headers=self.auth) if r.is_error: return PaymentStatus(None) diff --git a/requirements.txt b/requirements.txt index 30136a0..711a624 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,16 +7,15 @@ blinker==1.4 brotli==1.0.9 cerberus==1.3.2 certifi==2020.6.20 -chardet==3.0.4 click==7.1.2 ecdsa==0.16.0 environs==8.0.0 -h11==0.9.0 +h11==0.11.0 h2==4.0.0 hpack==4.0.0 -httpcore==0.11.1 -httpx==0.15.5 -hypercorn==0.11.0 +httpcore==0.12.0 +httpx==0.16.1 +hypercorn==0.11.1 hyperframe==6.0.0 idna==2.10 itsdangerous==1.1.0 @@ -33,7 +32,6 @@ quart==0.13.1 quart-compress==0.2.1 quart-cors==0.3.0 quart-trio==0.5.1 -requests==2.24.0 rfc3986==1.4.0 secure==0.2.1 shortuuid==1.0.1 @@ -43,6 +41,5 @@ sortedcontainers==2.2.2 toml==0.10.1 trio==0.17.0 typing-extensions==3.7.4.3 -urllib3==1.25.10 werkzeug==1.0.1 wsproto==0.15.0