From 68b0adfe6607f5ccf4dc59486c2addc99651078a Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Sun, 30 Aug 2020 23:48:46 -0300 Subject: [PATCH] fix: description_hash as an optional param to create_invoice. fixes https://github.com/lnbits/lnbits/issues/74 --- Makefile | 2 +- lnbits/core/services.py | 2 +- lnbits/wallets/base.py | 4 +++- lnbits/wallets/clightning.py | 6 ++++-- lnbits/wallets/lnbits.py | 17 +++++++++++------ lnbits/wallets/lndgrpc.py | 21 ++++++++++----------- lnbits/wallets/lndrest.py | 27 ++++++++++++++------------- lnbits/wallets/lnpay.py | 17 +++++++++++------ lnbits/wallets/lntxbot.py | 17 +++++++++++------ lnbits/wallets/opennode.py | 5 ++++- lnbits/wallets/spark.py | 9 +++++++-- 11 files changed, 77 insertions(+), 50 deletions(-) diff --git a/Makefile b/Makefile index 39029dc..b96d1ed 100644 --- a/Makefile +++ b/Makefile @@ -6,5 +6,5 @@ prettier: $(shell find lnbits -name "*.js" -name ".html") mypy: $(shell find lnbits -name "*.py") mypy lnbits -mypy: $(shell find lnbits -name "*.py") +black: $(shell find lnbits -name "*.py") black lnbits diff --git a/lnbits/core/services.py b/lnbits/core/services.py index f36ee54..717cfc1 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -7,7 +7,7 @@ from lnbits.settings import WALLET from .crud import get_wallet, create_payment, delete_payment -def create_invoice(*, wallet_id: str, amount: int, memo: str, description_hash: bytes) -> Tuple[str, str]: +def create_invoice(*, wallet_id: str, amount: int, memo: str, description_hash: bytes = None) -> Tuple[str, str]: try: ok, checking_id, payment_request, error_message = WALLET.create_invoice( diff --git a/lnbits/wallets/base.py b/lnbits/wallets/base.py index 2547d58..06c3979 100644 --- a/lnbits/wallets/base.py +++ b/lnbits/wallets/base.py @@ -26,7 +26,9 @@ class PaymentStatus(NamedTuple): class Wallet(ABC): @abstractmethod - def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: + def create_invoice( + self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None + ) -> InvoiceResponse: pass @abstractmethod diff --git a/lnbits/wallets/clightning.py b/lnbits/wallets/clightning.py index a0d750b..a8e4b1f 100644 --- a/lnbits/wallets/clightning.py +++ b/lnbits/wallets/clightning.py @@ -6,7 +6,7 @@ except ImportError: # pragma: nocover import random from os import getenv - +from typing import Optional from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet, Unsupported @@ -17,7 +17,9 @@ class CLightningWallet(Wallet): self.l1 = LightningRpc(getenv("CLIGHTNING_RPC")) - def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: + def create_invoice( + self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None + ) -> InvoiceResponse: if description_hash: raise Unsupported("description_hash") diff --git a/lnbits/wallets/lnbits.py b/lnbits/wallets/lnbits.py index 4c3bc01..8da7de7 100644 --- a/lnbits/wallets/lnbits.py +++ b/lnbits/wallets/lnbits.py @@ -1,4 +1,5 @@ from os import getenv +from typing import Optional, Dict from requests import get, post from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet @@ -12,12 +13,16 @@ class LNbitsWallet(Wallet): self.auth_admin = {"X-Api-Key": getenv("LNBITS_ADMIN_KEY")} self.auth_invoice = {"X-Api-Key": getenv("LNBITS_INVOICE_KEY")} - def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: - r = post( - url=f"{self.endpoint}/api/v1/payments", - headers=self.auth_invoice, - json={"out": False, "amount": amount, "memo": memo, "description_hash": description_hash.hex(),}, - ) + def create_invoice( + self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None + ) -> InvoiceResponse: + data: Dict = {"out": False, "amount": amount} + if description_hash: + data["description_hash"] = description_hash.hex() + else: + data["memo"] = memo or "" + + r = post(url=f"{self.endpoint}/api/v1/payments", headers=self.auth_invoice, json=data,) ok, checking_id, payment_request, error_message = r.ok, None, None, None if r.ok: diff --git a/lnbits/wallets/lndgrpc.py b/lnbits/wallets/lndgrpc.py index 63df176..f1bf82b 100644 --- a/lnbits/wallets/lndgrpc.py +++ b/lnbits/wallets/lndgrpc.py @@ -4,8 +4,8 @@ except ImportError: # pragma: nocover lnd_grpc = None import base64 - from os import getenv +from typing import Optional, Dict from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet @@ -23,7 +23,9 @@ class LndWallet(Wallet): self.auth_read = getenv("LND_READ_MACAROON") self.auth_cert = getenv("LND_CERT") - def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: + def create_invoice( + self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None + ) -> InvoiceResponse: lnd_rpc = lnd_grpc.Client( lnd_dir=None, macaroon_path=self.auth_invoice, @@ -33,20 +35,17 @@ class LndWallet(Wallet): grpc_port=self.port, ) - lndResponse = lnd_rpc.add_invoice( - memo=memo, - description_hash=base64.b64encode(description_hash).decode("ascii"), - value=amount, - expiry=600, - private=True, - ) + params: Dict = {"value": amount, "expiry": 600, "private": True} + if description_hash: + params["description_hash"] = description_hash # as bytes directly + else: + params["memo"] = memo or "" + lndResponse = lnd_rpc.add_invoice(**params) decoded_hash = base64.b64encode(lndResponse.r_hash).decode("utf-8").replace("/", "_") - print(lndResponse.r_hash) ok, checking_id, payment_request, error_message = True, decoded_hash, str(lndResponse.payment_request), None return InvoiceResponse(ok, checking_id, payment_request, error_message) def pay_invoice(self, bolt11: str) -> PaymentResponse: - lnd_rpc = lnd_grpc.Client( lnd_dir=None, macaroon_path=self.auth_admin, diff --git a/lnbits/wallets/lndrest.py b/lnbits/wallets/lndrest.py index 1e7187b..d47b9f6 100644 --- a/lnbits/wallets/lndrest.py +++ b/lnbits/wallets/lndrest.py @@ -1,4 +1,5 @@ from os import getenv +from typing import Optional, Dict import base64 from requests import get, post from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet @@ -17,19 +18,19 @@ class LndRestWallet(Wallet): self.auth_read = {"Grpc-Metadata-macaroon": getenv("LND_REST_READ_MACAROON")} self.auth_cert = getenv("LND_REST_CERT") - def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: - r = post( - url=f"{self.endpoint}/v1/invoices", - headers=self.auth_invoice, - verify=self.auth_cert, - json={ - "value": amount, - "memo": memo, - "description_hash": base64.b64encode(description_hash).decode("ascii"), - "private": True, - }, - ) - print(self.auth_invoice) + def create_invoice( + self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None + ) -> InvoiceResponse: + data: Dict = { + "value": amount, + "private": True, + } + if description_hash: + data["description_hash"] = base64.b64encode(description_hash).decode("ascii") + else: + data["memo"] = memo or "" + + r = post(url=f"{self.endpoint}/v1/invoices", headers=self.auth_invoice, verify=self.auth_cert, json=data,) ok, checking_id, payment_request, error_message = r.ok, None, None, None diff --git a/lnbits/wallets/lnpay.py b/lnbits/wallets/lnpay.py index e77817e..271ceb4 100644 --- a/lnbits/wallets/lnpay.py +++ b/lnbits/wallets/lnpay.py @@ -1,4 +1,5 @@ from os import getenv +from typing import Optional, Dict from requests import get, post from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet @@ -15,12 +16,16 @@ class LNPayWallet(Wallet): self.auth_read = getenv("LNPAY_READ_KEY") self.auth_api = {"X-Api-Key": getenv("LNPAY_API_KEY")} - def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: - r = post( - url=f"{self.endpoint}/user/wallet/{self.auth_invoice}/invoice", - headers=self.auth_api, - json={"num_satoshis": f"{amount}", "memo": memo, "description_hash": description_hash.hex(),}, - ) + def create_invoice( + self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None + ) -> InvoiceResponse: + data: Dict = {"num_satoshis": f"{amount}"} + if description_hash: + data["description_hash"] = description_hash.hex() + else: + data["memo"] = memo or "" + + r = post(url=f"{self.endpoint}/user/wallet/{self.auth_invoice}/invoice", headers=self.auth_api, json=data,) ok, checking_id, payment_request, error_message = r.status_code == 201, None, None, r.text if ok: diff --git a/lnbits/wallets/lntxbot.py b/lnbits/wallets/lntxbot.py index 0f73fa1..64d38d0 100644 --- a/lnbits/wallets/lntxbot.py +++ b/lnbits/wallets/lntxbot.py @@ -1,4 +1,5 @@ from os import getenv +from typing import Optional, Dict from requests import post from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet @@ -13,12 +14,16 @@ class LntxbotWallet(Wallet): self.auth_admin = {"Authorization": f"Basic {getenv('LNTXBOT_ADMIN_KEY')}"} self.auth_invoice = {"Authorization": f"Basic {getenv('LNTXBOT_INVOICE_KEY')}"} - def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: - r = post( - url=f"{self.endpoint}/addinvoice", - headers=self.auth_invoice, - json={"amt": str(amount), "memo": memo, "description_hash": description_hash.hex()}, - ) + def create_invoice( + self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None + ) -> InvoiceResponse: + data: Dict = {"amt": str(amount)} + if description_hash: + data["description_hash"] = description_hash.hex() + else: + data["memo"] = memo or "" + + r = post(url=f"{self.endpoint}/addinvoice", headers=self.auth_invoice, json=data,) ok, checking_id, payment_request, error_message = r.ok, None, None, None if r.ok: diff --git a/lnbits/wallets/opennode.py b/lnbits/wallets/opennode.py index 8a8f096..49307b7 100644 --- a/lnbits/wallets/opennode.py +++ b/lnbits/wallets/opennode.py @@ -1,4 +1,5 @@ from os import getenv +from typing import Optional from requests import get, post from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet, Unsupported @@ -13,7 +14,9 @@ class OpenNodeWallet(Wallet): self.auth_admin = {"Authorization": getenv("OPENNODE_ADMIN_KEY")} self.auth_invoice = {"Authorization": getenv("OPENNODE_INVOICE_KEY")} - def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: + def create_invoice( + self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None + ) -> InvoiceResponse: if description_hash: raise Unsupported("description_hash") diff --git a/lnbits/wallets/spark.py b/lnbits/wallets/spark.py index f647e89..6ad18fa 100644 --- a/lnbits/wallets/spark.py +++ b/lnbits/wallets/spark.py @@ -1,6 +1,7 @@ import random import requests from os import getenv +from typing import Optional from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet @@ -38,7 +39,9 @@ class SparkWallet(Wallet): return call - def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: + def create_invoice( + self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None + ) -> InvoiceResponse: label = "lbs{}".format(random.random()) checking_id = label @@ -48,7 +51,9 @@ class SparkWallet(Wallet): msatoshi=amount * 1000, label=label, description_hash=description_hash.hex(), ) else: - r = self.invoice(msatoshi=amount * 1000, label=label, description=memo, exposeprivatechannels=True) + r = self.invoice( + msatoshi=amount * 1000, label=label, description=memo or "", exposeprivatechannels=True + ) ok, payment_request, error_message = True, r["bolt11"], "" except (SparkError, UnknownError) as e: ok, payment_request, error_message = False, None, str(e)