Browse Source

support description_hash across all APIs.

aiosqlite
fiatjaf 5 years ago
parent
commit
bc27293315
  1. 13
      lnbits/core/services.py
  2. 13
      lnbits/core/views/api.py
  3. 6
      lnbits/wallets/base.py
  4. 12
      lnbits/wallets/clightning.py
  5. 20
      lnbits/wallets/lnbits.py
  6. 10
      lnbits/wallets/lndgrpc.py
  7. 33
      lnbits/wallets/lndrest.py
  8. 9
      lnbits/wallets/lnpay.py
  9. 9
      lnbits/wallets/lntxbot.py
  10. 7
      lnbits/wallets/opennode.py

13
lnbits/core/services.py

@ -7,9 +7,12 @@ 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) -> Tuple[str, str]: def create_invoice(*, wallet_id: str, amount: int, memo: str, description_hash: bytes) -> Tuple[str, str]:
try: try:
ok, checking_id, payment_request, error_message = WALLET.create_invoice(amount=amount, memo=memo) ok, checking_id, payment_request, error_message = WALLET.create_invoice(
amount=amount, memo=memo, description_hash=description_hash
)
except Exception as e: except Exception as e:
ok, error_message = False, str(e) ok, error_message = False, str(e)
@ -35,11 +38,7 @@ def pay_invoice(*, wallet_id: str, bolt11: str, max_sat: Optional[int] = None) -
fee_reserve = max(1000, int(invoice.amount_msat * 0.01)) fee_reserve = max(1000, int(invoice.amount_msat * 0.01))
create_payment( create_payment(
wallet_id=wallet_id, wallet_id=wallet_id, checking_id=temp_id, amount=-invoice.amount_msat, fee=-fee_reserve, memo=temp_id,
checking_id=temp_id,
amount=-invoice.amount_msat,
fee=-fee_reserve,
memo=temp_id,
) )
wallet = get_wallet(wallet_id) wallet = get_wallet(wallet_id)

13
lnbits/core/views/api.py

@ -1,5 +1,6 @@
from flask import g, jsonify, request from flask import g, jsonify, request
from http import HTTPStatus from http import HTTPStatus
from binascii import unhexlify
from lnbits.core import core_app from lnbits.core import core_app
from lnbits.decorators import api_check_wallet_key, api_validate_post_request from lnbits.decorators import api_check_wallet_key, api_validate_post_request
@ -27,13 +28,21 @@ def api_payments():
@api_validate_post_request( @api_validate_post_request(
schema={ schema={
"amount": {"type": "integer", "min": 1, "required": True}, "amount": {"type": "integer", "min": 1, "required": True},
"memo": {"type": "string", "empty": False, "required": True}, "memo": {"type": "string", "empty": False, "required": False},
"description_hash": {"type": "string", "empty": False, "required": False},
} }
) )
def api_payments_create_invoice(): def api_payments_create_invoice():
if "description_hash" in g.data:
description_hash = unhexlify(g.data["description_hash"])
memo = ""
else:
description_hash = b""
memo = g.data["memo"]
try: try:
checking_id, payment_request = create_invoice( checking_id, payment_request = create_invoice(
wallet_id=g.wallet.id, amount=g.data["amount"], memo=g.data["memo"] wallet_id=g.wallet.id, amount=g.data["amount"], memo=memo, description_hash=description_hash
) )
except Exception as e: except Exception as e:
return jsonify({"message": str(e)}), HTTPStatus.INTERNAL_SERVER_ERROR return jsonify({"message": str(e)}), HTTPStatus.INTERNAL_SERVER_ERROR

6
lnbits/wallets/base.py

@ -26,7 +26,7 @@ class PaymentStatus(NamedTuple):
class Wallet(ABC): class Wallet(ABC):
@abstractmethod @abstractmethod
def create_invoice(self, amount: int, memo: str = "") -> InvoiceResponse: def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse:
pass pass
@abstractmethod @abstractmethod
@ -40,3 +40,7 @@ class Wallet(ABC):
@abstractmethod @abstractmethod
def get_payment_status(self, checking_id: str) -> PaymentStatus: def get_payment_status(self, checking_id: str) -> PaymentStatus:
pass pass
class Unsupported(Exception):
pass

12
lnbits/wallets/clightning.py

@ -7,20 +7,22 @@ import random
from os import getenv from os import getenv
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet, Unsupported
class CLightningWallet(Wallet): class CLightningWallet(Wallet):
def __init__(self): def __init__(self):
if LightningRpc is None: # pragma: nocover if LightningRpc is None: # pragma: nocover
raise ImportError("The `pylightning` library must be installed to use `CLightningWallet`.") raise ImportError("The `pylightning` library must be installed to use `CLightningWallet`.")
self.l1 = LightningRpc(getenv("CLIGHTNING_RPC")) self.l1 = LightningRpc(getenv("CLIGHTNING_RPC"))
def create_invoice(self, amount: int, memo: str = "") -> InvoiceResponse: def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse:
if description_hash:
raise Unsupported("description_hash")
label = "lbl{}".format(random.random()) label = "lbl{}".format(random.random())
r = self.l1.invoice(amount*1000, label, memo, exposeprivatechannels=True) r = self.l1.invoice(amount * 1000, label, memo, exposeprivatechannels=True)
ok, checking_id, payment_request, error_message = True, r["payment_hash"], r["bolt11"], None ok, checking_id, payment_request, error_message = True, r["payment_hash"], r["bolt11"], None
return InvoiceResponse(ok, checking_id, payment_request, error_message) return InvoiceResponse(ok, checking_id, payment_request, error_message)
@ -31,7 +33,7 @@ class CLightningWallet(Wallet):
def get_invoice_status(self, checking_id: str) -> PaymentStatus: def get_invoice_status(self, checking_id: str) -> PaymentStatus:
r = self.l1.listinvoices(checking_id) r = self.l1.listinvoices(checking_id)
if r['invoices'][0]['status'] == 'unpaid': if r["invoices"][0]["status"] == "unpaid":
return PaymentStatus(False) return PaymentStatus(False)
return PaymentStatus(True) return PaymentStatus(True)

20
lnbits/wallets/lnbits.py

@ -1,5 +1,6 @@
from os import getenv from os import getenv
from requests import get, post from requests import get, post
from binascii import hexlify
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet
@ -12,11 +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 = "") -> InvoiceResponse: def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse:
r = post( r = post(
url=f"{self.endpoint}/api/v1/payments", url=f"{self.endpoint}/api/v1/payments",
headers=self.auth_invoice, headers=self.auth_invoice,
json={"out": False, "amount": amount, "memo": memo} json={
"out": False,
"amount": amount,
"memo": memo,
"description_hash": hexlify(description_hash).decode("ascii"),
},
) )
ok, checking_id, payment_request, error_message = r.ok, None, None, None ok, checking_id, payment_request, error_message = r.ok, None, None, None
@ -29,11 +35,7 @@ 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: def pay_invoice(self, bolt11: str) -> PaymentResponse:
r = post( r = post(url=f"{self.endpoint}/api/v1/payments", headers=self.auth_admin, json={"out": True, "bolt11": bolt11})
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 ok, checking_id, fee_msat, error_message = True, None, 0, None
if r.ok: if r.ok:
@ -50,7 +52,7 @@ class LNbitsWallet(Wallet):
if not r.ok: if not r.ok:
return PaymentStatus(None) return PaymentStatus(None)
return PaymentStatus(r.json()['paid']) return PaymentStatus(r.json()["paid"])
def get_payment_status(self, checking_id: str) -> PaymentStatus: 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 = get(url=f"{self.endpoint}/api/v1/payments/{checking_id}", headers=self.auth_invoice)
@ -58,4 +60,4 @@ class LNbitsWallet(Wallet):
if not r.ok: if not r.ok:
return PaymentStatus(None) return PaymentStatus(None)
return PaymentStatus(r.json()['paid']) return PaymentStatus(r.json()["paid"])

10
lnbits/wallets/lndgrpc.py

@ -23,7 +23,7 @@ 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 = "") -> InvoiceResponse: def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> 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,7 +33,13 @@ class LndWallet(Wallet):
grpc_port=self.port, grpc_port=self.port,
) )
lndResponse = lnd_rpc.add_invoice(memo=memo, value=amount, expiry=600, private=True) lndResponse = lnd_rpc.add_invoice(
memo=memo,
description_hash=base64.b64encode(description_hash).decode("ascii"),
value=amount,
expiry=600,
private=True,
)
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) 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

33
lnbits/wallets/lndrest.py

@ -1,5 +1,4 @@
from os import getenv from os import getenv
import os
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
@ -18,13 +17,17 @@ 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(self, amount: int, memo: str = "") -> InvoiceResponse:
r = post( r = post(
url=f"{self.endpoint}/v1/invoices", url=f"{self.endpoint}/v1/invoices",
headers=self.auth_invoice, verify=self.auth_cert, headers=self.auth_invoice,
json={"value": amount, "memo": memo, "private": True}, verify=self.auth_cert,
json={
"value": amount,
"memo": memo,
"description_hash": base64.b64encode(description_hash).decode("ascii"),
"private": True,
},
) )
print(self.auth_invoice) print(self.auth_invoice)
@ -37,17 +40,19 @@ class LndRestWallet(Wallet):
r = get(url=f"{self.endpoint}/v1/payreq/{payment_request}", headers=self.auth_read, verify=self.auth_cert,) r = get(url=f"{self.endpoint}/v1/payreq/{payment_request}", headers=self.auth_read, verify=self.auth_cert,)
print(r) print(r)
if r.ok: if r.ok:
checking_id = r.json()["payment_hash"].replace("/","_") checking_id = r.json()["payment_hash"].replace("/", "_")
print(checking_id) print(checking_id)
error_message = None error_message = None
ok = True ok = True
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:
r = post( r = post(
url=f"{self.endpoint}/v1/channels/transactions", headers=self.auth_admin, verify=self.auth_cert, json={"payment_request": bolt11} url=f"{self.endpoint}/v1/channels/transactions",
headers=self.auth_admin,
verify=self.auth_cert,
json={"payment_request": bolt11},
) )
ok, checking_id, fee_msat, error_message = r.ok, None, 0, None ok, checking_id, fee_msat, error_message = r.ok, None, 0, None
r = get(url=f"{self.endpoint}/v1/payreq/{bolt11}", headers=self.auth_admin, verify=self.auth_cert,) r = get(url=f"{self.endpoint}/v1/payreq/{bolt11}", headers=self.auth_admin, verify=self.auth_cert,)
@ -59,9 +64,8 @@ class LndRestWallet(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: def get_invoice_status(self, checking_id: str) -> PaymentStatus:
checking_id = checking_id.replace("_","/") checking_id = checking_id.replace("_", "/")
print(checking_id) print(checking_id)
r = get(url=f"{self.endpoint}/v1/invoice/{checking_id}", headers=self.auth_invoice, verify=self.auth_cert,) r = get(url=f"{self.endpoint}/v1/invoice/{checking_id}", headers=self.auth_invoice, verify=self.auth_cert,)
print(r.json()["settled"]) print(r.json()["settled"])
@ -71,7 +75,12 @@ class LndRestWallet(Wallet):
return PaymentStatus(r.json()["settled"]) return PaymentStatus(r.json()["settled"])
def get_payment_status(self, checking_id: str) -> PaymentStatus: def get_payment_status(self, checking_id: str) -> PaymentStatus:
r = get(url=f"{self.endpoint}/v1/payments", headers=self.auth_admin, verify=self.auth_cert, params={"include_incomplete": "True", "max_payments": "20"}) r = get(
url=f"{self.endpoint}/v1/payments",
headers=self.auth_admin,
verify=self.auth_cert,
params={"include_incomplete": "True", "max_payments": "20"},
)
if not r.ok: if not r.ok:
return PaymentStatus(None) return PaymentStatus(None)

9
lnbits/wallets/lnpay.py

@ -1,3 +1,4 @@
import base64
from os import getenv from os import getenv
from requests import get, post from requests import get, post
@ -15,11 +16,15 @@ 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 = "") -> InvoiceResponse: def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse:
r = post( r = post(
url=f"{self.endpoint}/user/wallet/{self.auth_invoice}/invoice", url=f"{self.endpoint}/user/wallet/{self.auth_invoice}/invoice",
headers=self.auth_api, headers=self.auth_api,
json={"num_satoshis": f"{amount}", "memo": memo}, json={
"num_satoshis": f"{amount}",
"memo": memo,
"description_hash": base64.b64encode(description_hash).decode("ascii"),
},
) )
ok, checking_id, payment_request, error_message = r.status_code == 201, None, None, None ok, checking_id, payment_request, error_message = r.status_code == 201, None, None, None

9
lnbits/wallets/lntxbot.py

@ -1,5 +1,6 @@
from os import getenv from os import getenv
from requests import post from requests import post
from binascii import hexlify
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet
@ -13,8 +14,12 @@ 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 = "") -> InvoiceResponse: 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}) r = post(
url=f"{self.endpoint}/addinvoice",
headers=self.auth_invoice,
json={"amt": str(amount), "memo": memo, "description_hash": hexlify(description_hash).decode("ascii")},
)
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:

7
lnbits/wallets/opennode.py

@ -1,7 +1,7 @@
from os import getenv from os import getenv
from requests import get, post from requests import get, post
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet, Unsupported
class OpenNodeWallet(Wallet): class OpenNodeWallet(Wallet):
@ -13,7 +13,10 @@ 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 = "") -> InvoiceResponse: def create_invoice(self, amount: int, memo: str = "", description_hash: bytes = b"") -> InvoiceResponse:
if description_hash:
raise Unsupported("description_hash")
r = post( r = post(
url=f"{self.endpoint}/v1/charges", url=f"{self.endpoint}/v1/charges",
headers=self.auth_invoice, headers=self.auth_invoice,

Loading…
Cancel
Save