fix: description_hash as an optional param to create_invoice.

fixes https://github.com/lnbits/lnbits/issues/74
This commit is contained in:
fiatjaf 2020-08-30 23:48:46 -03:00
parent 660d56d400
commit 68b0adfe66
11 changed files with 77 additions and 50 deletions

View file

@ -6,5 +6,5 @@ prettier: $(shell find lnbits -name "*.js" -name ".html")
mypy: $(shell find lnbits -name "*.py") mypy: $(shell find lnbits -name "*.py")
mypy lnbits mypy lnbits
mypy: $(shell find lnbits -name "*.py") black: $(shell find lnbits -name "*.py")
black lnbits black lnbits

View file

@ -7,7 +7,7 @@ from lnbits.settings import WALLET
from .crud import get_wallet, create_payment, delete_payment 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: try:
ok, checking_id, payment_request, error_message = WALLET.create_invoice( ok, checking_id, payment_request, error_message = WALLET.create_invoice(

View file

@ -26,7 +26,9 @@ class PaymentStatus(NamedTuple):
class Wallet(ABC): class Wallet(ABC):
@abstractmethod @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 pass
@abstractmethod @abstractmethod

View file

@ -6,7 +6,7 @@ except ImportError: # pragma: nocover
import random import random
from os import getenv from os import getenv
from typing import Optional
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet, Unsupported from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet, Unsupported
@ -17,7 +17,9 @@ class CLightningWallet(Wallet):
self.l1 = LightningRpc(getenv("CLIGHTNING_RPC")) 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: if description_hash:
raise Unsupported("description_hash") raise Unsupported("description_hash")

View file

@ -1,4 +1,5 @@
from os import getenv from os import getenv
from typing import Optional, Dict
from requests import get, post from requests import get, post
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet 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_admin = {"X-Api-Key": getenv("LNBITS_ADMIN_KEY")}
self.auth_invoice = {"X-Api-Key": getenv("LNBITS_INVOICE_KEY")} self.auth_invoice = {"X-Api-Key": getenv("LNBITS_INVOICE_KEY")}
def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: def create_invoice(
r = post( self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None
url=f"{self.endpoint}/api/v1/payments", ) -> InvoiceResponse:
headers=self.auth_invoice, data: Dict = {"out": False, "amount": amount}
json={"out": False, "amount": amount, "memo": memo, "description_hash": description_hash.hex(),}, 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 ok, checking_id, payment_request, error_message = r.ok, None, None, None
if r.ok: if r.ok:

View file

@ -4,8 +4,8 @@ except ImportError: # pragma: nocover
lnd_grpc = None lnd_grpc = None
import base64 import base64
from os import getenv from os import getenv
from typing import Optional, Dict
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet
@ -23,7 +23,9 @@ class LndWallet(Wallet):
self.auth_read = getenv("LND_READ_MACAROON") self.auth_read = getenv("LND_READ_MACAROON")
self.auth_cert = getenv("LND_CERT") 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_rpc = lnd_grpc.Client(
lnd_dir=None, lnd_dir=None,
macaroon_path=self.auth_invoice, macaroon_path=self.auth_invoice,
@ -33,20 +35,17 @@ class LndWallet(Wallet):
grpc_port=self.port, grpc_port=self.port,
) )
lndResponse = lnd_rpc.add_invoice( params: Dict = {"value": amount, "expiry": 600, "private": True}
memo=memo, if description_hash:
description_hash=base64.b64encode(description_hash).decode("ascii"), params["description_hash"] = description_hash # as bytes directly
value=amount, else:
expiry=600, params["memo"] = memo or ""
private=True, lndResponse = lnd_rpc.add_invoice(**params)
)
decoded_hash = base64.b64encode(lndResponse.r_hash).decode("utf-8").replace("/", "_") 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 ok, checking_id, payment_request, error_message = True, decoded_hash, str(lndResponse.payment_request), None
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: def pay_invoice(self, bolt11: str) -> PaymentResponse:
lnd_rpc = lnd_grpc.Client( lnd_rpc = lnd_grpc.Client(
lnd_dir=None, lnd_dir=None,
macaroon_path=self.auth_admin, macaroon_path=self.auth_admin,

View file

@ -1,4 +1,5 @@
from os import getenv from os import getenv
from typing import Optional, Dict
import base64 import base64
from requests import get, post from requests import get, post
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet 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_read = {"Grpc-Metadata-macaroon": getenv("LND_REST_READ_MACAROON")}
self.auth_cert = getenv("LND_REST_CERT") self.auth_cert = getenv("LND_REST_CERT")
def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: def create_invoice(
r = post( self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None
url=f"{self.endpoint}/v1/invoices", ) -> InvoiceResponse:
headers=self.auth_invoice, data: Dict = {
verify=self.auth_cert,
json={
"value": amount, "value": amount,
"memo": memo,
"description_hash": base64.b64encode(description_hash).decode("ascii"),
"private": True, "private": True,
}, }
) if description_hash:
print(self.auth_invoice) 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 ok, checking_id, payment_request, error_message = r.ok, None, None, None

View file

@ -1,4 +1,5 @@
from os import getenv from os import getenv
from typing import Optional, Dict
from requests import get, post from requests import get, post
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet
@ -15,12 +16,16 @@ class LNPayWallet(Wallet):
self.auth_read = getenv("LNPAY_READ_KEY") self.auth_read = getenv("LNPAY_READ_KEY")
self.auth_api = {"X-Api-Key": getenv("LNPAY_API_KEY")} self.auth_api = {"X-Api-Key": getenv("LNPAY_API_KEY")}
def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: def create_invoice(
r = post( self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None
url=f"{self.endpoint}/user/wallet/{self.auth_invoice}/invoice", ) -> InvoiceResponse:
headers=self.auth_api, data: Dict = {"num_satoshis": f"{amount}"}
json={"num_satoshis": f"{amount}", "memo": memo, "description_hash": description_hash.hex(),}, 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 ok, checking_id, payment_request, error_message = r.status_code == 201, None, None, r.text
if ok: if ok:

View file

@ -1,4 +1,5 @@
from os import getenv from os import getenv
from typing import Optional, Dict
from requests import post from requests import post
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet 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_admin = {"Authorization": f"Basic {getenv('LNTXBOT_ADMIN_KEY')}"}
self.auth_invoice = {"Authorization": f"Basic {getenv('LNTXBOT_INVOICE_KEY')}"} self.auth_invoice = {"Authorization": f"Basic {getenv('LNTXBOT_INVOICE_KEY')}"}
def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse: def create_invoice(
r = post( self, amount: int, memo: Optional[str] = None, description_hash: Optional[bytes] = None
url=f"{self.endpoint}/addinvoice", ) -> InvoiceResponse:
headers=self.auth_invoice, data: Dict = {"amt": str(amount)}
json={"amt": str(amount), "memo": memo, "description_hash": description_hash.hex()}, 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 ok, checking_id, payment_request, error_message = r.ok, None, None, None
if r.ok: if r.ok:

View file

@ -1,4 +1,5 @@
from os import getenv from os import getenv
from typing import Optional
from requests import get, post from requests import get, post
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet, Unsupported 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_admin = {"Authorization": getenv("OPENNODE_ADMIN_KEY")}
self.auth_invoice = {"Authorization": getenv("OPENNODE_INVOICE_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: if description_hash:
raise Unsupported("description_hash") raise Unsupported("description_hash")

View file

@ -1,6 +1,7 @@
import random import random
import requests import requests
from os import getenv from os import getenv
from typing import Optional
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet
@ -38,7 +39,9 @@ class SparkWallet(Wallet):
return call 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()) label = "lbs{}".format(random.random())
checking_id = label checking_id = label
@ -48,7 +51,9 @@ class SparkWallet(Wallet):
msatoshi=amount * 1000, label=label, description_hash=description_hash.hex(), msatoshi=amount * 1000, label=label, description_hash=description_hash.hex(),
) )
else: 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"], "" ok, payment_request, error_message = True, r["bolt11"], ""
except (SparkError, UnknownError) as e: except (SparkError, UnknownError) as e:
ok, payment_request, error_message = False, None, str(e) ok, payment_request, error_message = False, None, str(e)