refactor: fundingsource Invoice-, PaymentResponses (#3089)
This commit is contained in:
parent
94d5f37723
commit
ffecd03c4b
17 changed files with 287 additions and 215 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
from typing import AsyncGenerator, Dict, Optional
|
from typing import AsyncGenerator, Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
@ -72,10 +72,10 @@ class AlbyWallet(Wallet):
|
||||||
memo: Optional[str] = None,
|
memo: Optional[str] = None,
|
||||||
description_hash: Optional[bytes] = None,
|
description_hash: Optional[bytes] = None,
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**kwargs,
|
**_,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
# https://api.getalby.com/invoices
|
# https://api.getalby.com/invoices
|
||||||
data: Dict = {"amount": f"{amount}"}
|
data: dict = {"amount": f"{amount}"}
|
||||||
if description_hash:
|
if description_hash:
|
||||||
data["description_hash"] = description_hash.hex()
|
data["description_hash"] = description_hash.hex()
|
||||||
elif unhashed_description:
|
elif unhashed_description:
|
||||||
|
|
@ -95,25 +95,29 @@ class AlbyWallet(Wallet):
|
||||||
|
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
error_message = data["message"] if "message" in data else r.text
|
error_message = data["message"] if "message" in data else r.text
|
||||||
return InvoiceResponse(False, None, None, error_message)
|
return InvoiceResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
checking_id = data["payment_hash"]
|
checking_id = data["payment_hash"]
|
||||||
payment_request = data["payment_request"]
|
payment_request = data["payment_request"]
|
||||||
return InvoiceResponse(True, checking_id, payment_request, None)
|
return InvoiceResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=checking_id,
|
||||||
|
payment_request=payment_request,
|
||||||
|
)
|
||||||
except KeyError as exc:
|
except KeyError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'missing required fields'"
|
ok=False, error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except json.JSONDecodeError as exc:
|
except json.JSONDecodeError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'invalid json response'"
|
ok=False, error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"Unable to connect to {self.endpoint}."
|
ok=False, error_message=f"Unable to connect to {self.endpoint}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
|
|
@ -129,30 +133,31 @@ class AlbyWallet(Wallet):
|
||||||
|
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
error_message = data["message"] if "message" in data else r.text
|
error_message = data["message"] if "message" in data else r.text
|
||||||
return PaymentResponse(None, None, None, None, error_message)
|
return PaymentResponse(error_message=error_message)
|
||||||
|
|
||||||
checking_id = data["payment_hash"]
|
checking_id = data["payment_hash"]
|
||||||
# todo: confirm with bitkarrot that having the minus is fine
|
# todo: confirm with bitkarrot that having the minus is fine
|
||||||
# other funding sources return a positive fee value
|
# other funding sources return a positive fee value
|
||||||
fee_msat = -data["fee"]
|
fee_msat = -data["fee"]
|
||||||
preimage = data["payment_preimage"]
|
preimage = data["payment_preimage"]
|
||||||
|
return PaymentResponse(
|
||||||
return PaymentResponse(True, checking_id, fee_msat, preimage, None)
|
ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage
|
||||||
|
)
|
||||||
except KeyError as exc:
|
except KeyError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'missing required fields'"
|
error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except json.JSONDecodeError as exc:
|
except json.JSONDecodeError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'invalid json response'"
|
error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.info(f"Failed to pay invoice {bolt11}")
|
logger.info(f"Failed to pay invoice {bolt11}")
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, f"Unable to connect to {self.endpoint}."
|
error_message=f"Unable to connect to {self.endpoint}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ class BlinkWallet(Wallet):
|
||||||
)
|
)
|
||||||
if len(errors) > 0:
|
if len(errors) > 0:
|
||||||
error_message = errors[0].get("message")
|
error_message = errors[0].get("message")
|
||||||
return InvoiceResponse(False, None, None, error_message)
|
return InvoiceResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
payment_request = (
|
payment_request = (
|
||||||
response.get("data", {})
|
response.get("data", {})
|
||||||
|
|
@ -150,15 +150,18 @@ class BlinkWallet(Wallet):
|
||||||
.get("paymentHash", None)
|
.get("paymentHash", None)
|
||||||
)
|
)
|
||||||
|
|
||||||
return InvoiceResponse(True, checking_id, payment_request, None)
|
# TODO: add preimage to response
|
||||||
|
return InvoiceResponse(
|
||||||
|
ok=True, checking_id=checking_id, payment_request=payment_request
|
||||||
|
)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'invalid json response'"
|
ok=False, error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"Unable to connect to {self.endpoint}."
|
ok=False, error_message=f"Unable to connect to {self.endpoint}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def pay_invoice(
|
async def pay_invoice(
|
||||||
|
|
@ -185,19 +188,21 @@ class BlinkWallet(Wallet):
|
||||||
)
|
)
|
||||||
if len(errors) > 0:
|
if len(errors) > 0:
|
||||||
error_message = errors[0].get("message")
|
error_message = errors[0].get("message")
|
||||||
return PaymentResponse(False, None, None, None, error_message)
|
return PaymentResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
checking_id = bolt11.decode(bolt11_invoice).payment_hash
|
checking_id = bolt11.decode(bolt11_invoice).payment_hash
|
||||||
|
|
||||||
payment_status = await self.get_payment_status(checking_id)
|
payment_status = await self.get_payment_status(checking_id)
|
||||||
fee_msat = payment_status.fee_msat
|
fee_msat = payment_status.fee_msat
|
||||||
preimage = payment_status.preimage
|
preimage = payment_status.preimage
|
||||||
return PaymentResponse(True, checking_id, fee_msat, preimage, None)
|
return PaymentResponse(
|
||||||
|
ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.info(f"Failed to pay invoice {bolt11_invoice}")
|
logger.info(f"Failed to pay invoice {bolt11_invoice}")
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, f"Unable to connect to {self.endpoint}."
|
error_message=f"Unable to connect to {self.endpoint}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
|
|
||||||
|
|
@ -182,15 +182,16 @@ else:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: add preimage
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
True,
|
ok=True,
|
||||||
breez_invoice.ln_invoice.payment_hash,
|
checking_id=breez_invoice.ln_invoice.payment_hash,
|
||||||
breez_invoice.ln_invoice.bolt11,
|
payment_request=breez_invoice.ln_invoice.bolt11,
|
||||||
None,
|
# preimage=breez_invoice.ln_invoice.payment_preimage,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(e)
|
logger.warning(e)
|
||||||
return InvoiceResponse(False, None, None, str(e))
|
return InvoiceResponse(ok=False, error_message=str(e))
|
||||||
|
|
||||||
async def pay_invoice(
|
async def pay_invoice(
|
||||||
self, bolt11: str, fee_limit_msat: int
|
self, bolt11: str, fee_limit_msat: int
|
||||||
|
|
@ -217,22 +218,19 @@ else:
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.info(ex)
|
logger.info(ex)
|
||||||
# assume that payment failed?
|
# assume that payment failed?
|
||||||
return PaymentResponse(
|
return PaymentResponse(ok=False, error_message=f"payment failed: {exc}")
|
||||||
False, None, None, None, f"payment failed: {exc}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if payment.status != breez_sdk.PaymentStatus.COMPLETE:
|
if payment.status != breez_sdk.PaymentStatus.COMPLETE:
|
||||||
return PaymentResponse(False, None, None, None, "payment is pending")
|
return PaymentResponse(ok=False, error_message="payment is pending")
|
||||||
|
|
||||||
# let's use the payment_hash as the checking_id
|
# let's use the payment_hash as the checking_id
|
||||||
checking_id = invoice.payment_hash
|
checking_id = invoice.payment_hash
|
||||||
|
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
True,
|
ok=True,
|
||||||
checking_id,
|
checking_id=checking_id,
|
||||||
payment.fee_msat,
|
fee_msat=payment.fee_msat,
|
||||||
payment.details.data.payment_preimage,
|
preimage=payment.details.data.payment_preimage,
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ class ClicheWallet(Wallet):
|
||||||
memo: Optional[str] = None,
|
memo: Optional[str] = None,
|
||||||
description_hash: Optional[bytes] = None,
|
description_hash: Optional[bytes] = None,
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**kwargs,
|
**_,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
if unhashed_description or description_hash:
|
if unhashed_description or description_hash:
|
||||||
description_hash_str = (
|
description_hash_str = (
|
||||||
|
|
@ -79,12 +79,13 @@ class ClicheWallet(Wallet):
|
||||||
data = json.loads(r)
|
data = json.loads(r)
|
||||||
checking_id = None
|
checking_id = None
|
||||||
payment_request = None
|
payment_request = None
|
||||||
error_message = None
|
|
||||||
|
|
||||||
if data.get("error") is not None and data["error"].get("message"):
|
if data.get("error") is not None and data["error"].get("message"):
|
||||||
logger.error(data["error"]["message"])
|
logger.error(data["error"]["message"])
|
||||||
error_message = data["error"]["message"]
|
error_message = data["error"]["message"]
|
||||||
return InvoiceResponse(False, checking_id, payment_request, error_message)
|
return InvoiceResponse(
|
||||||
|
ok=False, checking_id=checking_id, error_message=error_message
|
||||||
|
)
|
||||||
|
|
||||||
if data.get("result") is not None:
|
if data.get("result") is not None:
|
||||||
checking_id, payment_request = (
|
checking_id, payment_request = (
|
||||||
|
|
@ -92,15 +93,18 @@ class ClicheWallet(Wallet):
|
||||||
data["result"]["invoice"],
|
data["result"]["invoice"],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return InvoiceResponse(False, None, None, "Could not get payment hash")
|
return InvoiceResponse(ok=False, error_message="Could not get payment hash")
|
||||||
|
|
||||||
return InvoiceResponse(True, checking_id, payment_request, error_message)
|
return InvoiceResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=checking_id,
|
||||||
|
payment_request=payment_request,
|
||||||
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
ws = create_connection(self.endpoint)
|
ws = create_connection(self.endpoint)
|
||||||
ws.send(f"pay-invoice --invoice {bolt11}")
|
ws.send(f"pay-invoice --invoice {bolt11}")
|
||||||
checking_id, fee_msat, preimage, error_message, payment_ok = (
|
checking_id, fee_msat, preimage, payment_ok = (
|
||||||
None,
|
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
|
@ -109,8 +113,7 @@ class ClicheWallet(Wallet):
|
||||||
for _ in range(2):
|
for _ in range(2):
|
||||||
r = ws.recv()
|
r = ws.recv()
|
||||||
data = json.loads(r)
|
data = json.loads(r)
|
||||||
checking_id, fee_msat, preimage, error_message, payment_ok = (
|
checking_id, fee_msat, preimage, payment_ok = (
|
||||||
None,
|
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
|
@ -119,7 +122,7 @@ class ClicheWallet(Wallet):
|
||||||
|
|
||||||
if data.get("error") is not None:
|
if data.get("error") is not None:
|
||||||
error_message = data["error"].get("message")
|
error_message = data["error"].get("message")
|
||||||
return PaymentResponse(False, None, None, None, error_message)
|
return PaymentResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
if data.get("method") == "payment_succeeded":
|
if data.get("method") == "payment_succeeded":
|
||||||
payment_ok = True
|
payment_ok = True
|
||||||
|
|
@ -129,10 +132,10 @@ class ClicheWallet(Wallet):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if data.get("result") is None:
|
if data.get("result") is None:
|
||||||
return PaymentResponse(None)
|
return PaymentResponse(error_message="result is None")
|
||||||
|
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
payment_ok, checking_id, fee_msat, preimage, error_message
|
ok=payment_ok, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
|
|
||||||
|
|
@ -115,35 +115,38 @@ class CoreLightningWallet(Wallet):
|
||||||
|
|
||||||
if r.get("code") and r.get("code") < 0: # type: ignore
|
if r.get("code") and r.get("code") < 0: # type: ignore
|
||||||
raise Exception(r.get("message"))
|
raise Exception(r.get("message"))
|
||||||
|
return InvoiceResponse(
|
||||||
return InvoiceResponse(True, r["payment_hash"], r["bolt11"], None)
|
ok=True,
|
||||||
|
checking_id=r["payment_hash"],
|
||||||
|
payment_request=r["bolt11"],
|
||||||
|
)
|
||||||
except RpcError as exc:
|
except RpcError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
error_message = f"RPC '{exc.method}' failed with '{exc.error}'."
|
error_message = f"RPC '{exc.method}' failed with '{exc.error}'."
|
||||||
return InvoiceResponse(False, None, None, error_message)
|
return InvoiceResponse(ok=False, error_message=error_message)
|
||||||
except KeyError as exc:
|
except KeyError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'missing required fields'"
|
ok=False, error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(e)
|
logger.warning(e)
|
||||||
return InvoiceResponse(False, None, None, str(e))
|
return InvoiceResponse(ok=False, error_message=str(e))
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
try:
|
try:
|
||||||
invoice = bolt11_decode(bolt11)
|
invoice = bolt11_decode(bolt11)
|
||||||
except Bolt11Exception as exc:
|
except Bolt11Exception as exc:
|
||||||
return PaymentResponse(False, None, None, None, str(exc))
|
return PaymentResponse(ok=False, error_message=str(exc))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
previous_payment = await self.get_payment_status(invoice.payment_hash)
|
previous_payment = await self.get_payment_status(invoice.payment_hash)
|
||||||
if previous_payment.paid:
|
if previous_payment.paid:
|
||||||
return PaymentResponse(False, None, None, None, "invoice already paid")
|
return PaymentResponse(ok=False, error_message="invoice already paid")
|
||||||
|
|
||||||
if not invoice.amount_msat or invoice.amount_msat <= 0:
|
if not invoice.amount_msat or invoice.amount_msat <= 0:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
False, None, None, None, "CLN 0 amount invoice not supported"
|
ok=False, error_message="CLN 0 amount invoice not supported"
|
||||||
)
|
)
|
||||||
|
|
||||||
# maxfee overrides both maxfeepercent and exemptfee defaults (and
|
# maxfee overrides both maxfeepercent and exemptfee defaults (and
|
||||||
|
|
@ -170,23 +173,23 @@ class CoreLightningWallet(Wallet):
|
||||||
if error_code in self.pay_failure_error_codes:
|
if error_code in self.pay_failure_error_codes:
|
||||||
error_message = exc.error.get("message", error_code) # type: ignore
|
error_message = exc.error.get("message", error_code) # type: ignore
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
False, None, None, None, f"Payment failed: {error_message}"
|
ok=False, error_message=f"Payment failed: {error_message}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
error_message = f"Payment failed: {exc.error}"
|
error_message = f"Payment failed: {exc.error}"
|
||||||
return PaymentResponse(None, None, None, None, error_message)
|
return PaymentResponse(error_message=error_message)
|
||||||
except Exception:
|
except Exception:
|
||||||
error_message = f"RPC '{exc.method}' failed with '{exc.error}'."
|
error_message = f"RPC '{exc.method}' failed with '{exc.error}'."
|
||||||
return PaymentResponse(None, None, None, None, error_message)
|
return PaymentResponse(error_message=error_message)
|
||||||
except KeyError as exc:
|
except KeyError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'missing required fields'"
|
error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.info(f"Failed to pay invoice {bolt11}")
|
logger.info(f"Failed to pay invoice {bolt11}")
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(None, None, None, None, f"Payment failed: '{exc}'.")
|
return PaymentResponse(error_message=f"Payment failed: '{exc}'.")
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
from typing import AsyncGenerator, Dict, Optional
|
from typing import AsyncGenerator, Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from bolt11 import Bolt11Exception
|
from bolt11 import Bolt11Exception
|
||||||
|
|
@ -109,7 +109,7 @@ class CoreLightningRestWallet(Wallet):
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
label = kwargs.get("label", f"lbl{random.random()}")
|
label = kwargs.get("label", f"lbl{random.random()}")
|
||||||
data: Dict = {
|
data: dict = {
|
||||||
"amount": amount * 1000,
|
"amount": amount * 1000,
|
||||||
"description": memo,
|
"description": memo,
|
||||||
"label": label,
|
"label": label,
|
||||||
|
|
@ -139,41 +139,47 @@ class CoreLightningRestWallet(Wallet):
|
||||||
data = r.json()
|
data = r.json()
|
||||||
|
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
return InvoiceResponse(False, None, None, "no data")
|
return InvoiceResponse(ok=False, error_message="no data")
|
||||||
|
|
||||||
if "error" in data:
|
if "error" in data:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"""Server error: '{data["error"]}'"""
|
ok=False, error_message=f"""Server error: '{data["error"]}'"""
|
||||||
)
|
)
|
||||||
|
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
return InvoiceResponse(False, None, None, f"Server error: '{r.text}'")
|
return InvoiceResponse(
|
||||||
|
ok=False, error_message=f"Server error: '{r.text}'"
|
||||||
|
)
|
||||||
|
|
||||||
if "payment_hash" not in data or "bolt11" not in data:
|
if "payment_hash" not in data or "bolt11" not in data:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'missing required fields'"
|
ok=False, error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
|
|
||||||
return InvoiceResponse(True, data["payment_hash"], data["bolt11"], None)
|
return InvoiceResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=data["payment_hash"],
|
||||||
|
payment_request=data["bolt11"],
|
||||||
|
)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'invalid json response'"
|
ok=False, error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"Unable to connect to {self.url}."
|
ok=False, error_message=f"Unable to connect to {self.url}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
try:
|
try:
|
||||||
invoice = decode(bolt11)
|
invoice = decode(bolt11)
|
||||||
except Bolt11Exception as exc:
|
except Bolt11Exception as exc:
|
||||||
return PaymentResponse(False, None, None, None, str(exc))
|
return PaymentResponse(ok=False, error_message=str(exc))
|
||||||
|
|
||||||
if not invoice.amount_msat or invoice.amount_msat <= 0:
|
if not invoice.amount_msat or invoice.amount_msat <= 0:
|
||||||
error_message = "0 amount invoices are not allowed"
|
error_message = "0 amount invoices are not allowed"
|
||||||
return PaymentResponse(False, None, None, None, error_message)
|
return PaymentResponse(ok=False, error_message=error_message)
|
||||||
try:
|
try:
|
||||||
r = await self.client.post(
|
r = await self.client.post(
|
||||||
f"{self.url}/v1/pay",
|
f"{self.url}/v1/pay",
|
||||||
|
|
@ -190,18 +196,16 @@ class CoreLightningRestWallet(Wallet):
|
||||||
status = self.statuses.get(data["status"])
|
status = self.statuses.get(data["status"])
|
||||||
if "payment_preimage" not in data:
|
if "payment_preimage" not in data:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
status,
|
ok=status, error_message=data.get("error") or "unknown error"
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
data.get("error"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
checking_id = data["payment_hash"]
|
checking_id = data["payment_hash"]
|
||||||
preimage = data["payment_preimage"]
|
preimage = data["payment_preimage"]
|
||||||
fee_msat = data["msatoshi_sent"] - data["msatoshi"]
|
fee_msat = data["msatoshi_sent"] - data["msatoshi"]
|
||||||
|
|
||||||
return PaymentResponse(status, checking_id, fee_msat, preimage, None)
|
return PaymentResponse(
|
||||||
|
ok=status, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage
|
||||||
|
)
|
||||||
except httpx.HTTPStatusError as exc:
|
except httpx.HTTPStatusError as exc:
|
||||||
try:
|
try:
|
||||||
logger.debug(exc)
|
logger.debug(exc)
|
||||||
|
|
@ -209,28 +213,26 @@ class CoreLightningRestWallet(Wallet):
|
||||||
error_code = int(data["error"]["code"])
|
error_code = int(data["error"]["code"])
|
||||||
if error_code in self.pay_failure_error_codes:
|
if error_code in self.pay_failure_error_codes:
|
||||||
error_message = f"Payment failed: {data['error']['message']}"
|
error_message = f"Payment failed: {data['error']['message']}"
|
||||||
return PaymentResponse(False, None, None, None, error_message)
|
return PaymentResponse(ok=False, error_message=error_message)
|
||||||
error_message = f"REST failed with {data['error']['message']}."
|
error_message = f"REST failed with {data['error']['message']}."
|
||||||
return PaymentResponse(None, None, None, None, error_message)
|
return PaymentResponse(error_message=error_message)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
error_message = f"Unable to connect to {self.url}."
|
error_message = f"Unable to connect to {self.url}."
|
||||||
return PaymentResponse(None, None, None, None, error_message)
|
return PaymentResponse(error_message=error_message)
|
||||||
|
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'invalid json response'"
|
error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except KeyError as exc:
|
except KeyError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'missing required fields'"
|
error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.info(f"Failed to pay invoice {bolt11}")
|
logger.info(f"Failed to pay invoice {bolt11}")
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(error_message=f"Unable to connect to {self.url}.")
|
||||||
None, None, None, None, f"Unable to connect to {self.url}."
|
|
||||||
)
|
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
r = await self.client.get(
|
r = await self.client.get(
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from typing import Any, AsyncGenerator, Dict, Optional
|
from typing import Any, AsyncGenerator, Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
@ -85,7 +85,7 @@ class EclairWallet(Wallet):
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
data: Dict[str, Any] = {
|
data: dict[str, Any] = {
|
||||||
"amountMsat": amount * 1000,
|
"amountMsat": amount * 1000,
|
||||||
}
|
}
|
||||||
if kwargs.get("expiry"):
|
if kwargs.get("expiry"):
|
||||||
|
|
@ -105,30 +105,35 @@ class EclairWallet(Wallet):
|
||||||
data = r.json()
|
data = r.json()
|
||||||
|
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
return InvoiceResponse(False, None, None, "no data")
|
return InvoiceResponse(ok=False, error_message="no data")
|
||||||
|
|
||||||
if "error" in data:
|
if "error" in data:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"""Server error: '{data["error"]}'"""
|
ok=False, error_message=f"""Server error: '{data["error"]}'"""
|
||||||
)
|
)
|
||||||
|
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
return InvoiceResponse(False, None, None, f"Server error: '{r.text}'")
|
return InvoiceResponse(
|
||||||
|
ok=False, error_message=f"Server error: '{r.text}'"
|
||||||
return InvoiceResponse(True, data["paymentHash"], data["serialized"], None)
|
)
|
||||||
|
return InvoiceResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=data["paymentHash"],
|
||||||
|
payment_request=data["serialized"],
|
||||||
|
)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'invalid json response'"
|
ok=False, error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except KeyError as exc:
|
except KeyError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'missing required fields'"
|
ok=False, error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"Unable to connect to {self.url}."
|
ok=False, error_message=f"Unable to connect to {self.url}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
|
|
@ -142,35 +147,36 @@ class EclairWallet(Wallet):
|
||||||
data = r.json()
|
data = r.json()
|
||||||
|
|
||||||
if "error" in data:
|
if "error" in data:
|
||||||
return PaymentResponse(None, None, None, None, data["error"])
|
return PaymentResponse(error_message=data["error"])
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
return PaymentResponse(None, None, None, None, r.text)
|
return PaymentResponse(error_message=r.text)
|
||||||
|
|
||||||
if data["type"] == "payment-failed":
|
if data["type"] == "payment-failed":
|
||||||
return PaymentResponse(False, None, None, None, "payment failed")
|
return PaymentResponse(ok=False, error_message="payment failed")
|
||||||
|
|
||||||
checking_id = data["paymentHash"]
|
checking_id = data["paymentHash"]
|
||||||
preimage = data["paymentPreimage"]
|
preimage = data["paymentPreimage"]
|
||||||
|
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'invalid json response'"
|
error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'missing required fields'"
|
error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.info(f"Failed to pay invoice {bolt11}")
|
logger.info(f"Failed to pay invoice {bolt11}")
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(error_message=f"Unable to connect to {self.url}.")
|
||||||
None, None, None, None, f"Unable to connect to {self.url}."
|
|
||||||
)
|
|
||||||
|
|
||||||
payment_status: PaymentStatus = await self.get_payment_status(checking_id)
|
payment_status: PaymentStatus = await self.get_payment_status(checking_id)
|
||||||
success = True if payment_status.success else None
|
success = True if payment_status.success else None
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
success, checking_id, payment_status.fee_msat, preimage, None
|
ok=success,
|
||||||
|
checking_id=checking_id,
|
||||||
|
fee_msat=payment_status.fee_msat,
|
||||||
|
preimage=preimage,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
|
|
||||||
|
|
@ -92,23 +92,25 @@ class LNbitsWallet(Wallet):
|
||||||
if r.is_error or not payment_str:
|
if r.is_error or not payment_str:
|
||||||
error_message = data["detail"] if "detail" in data else r.text
|
error_message = data["detail"] if "detail" in data else r.text
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"Server error: '{error_message}'"
|
ok=False, error_message=f"Server error: '{error_message}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
return InvoiceResponse(True, data["checking_id"], payment_str, None)
|
return InvoiceResponse(
|
||||||
|
ok=True, checking_id=data["checking_id"], payment_request=payment_str
|
||||||
|
)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'invalid json response'"
|
ok=False, error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except KeyError as exc:
|
except KeyError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'missing required fields'"
|
ok=False, error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"Unable to connect to {self.endpoint}."
|
ok=False, error_message=f"Unable to connect to {self.endpoint}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
|
|
@ -129,7 +131,10 @@ class LNbitsWallet(Wallet):
|
||||||
|
|
||||||
success = True if payment.success else None
|
success = True if payment.success else None
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
success, checking_id, payment.fee_msat, payment.preimage
|
ok=success,
|
||||||
|
checking_id=checking_id,
|
||||||
|
fee_msat=payment.fee_msat,
|
||||||
|
preimage=payment.preimage,
|
||||||
)
|
)
|
||||||
|
|
||||||
except httpx.HTTPStatusError as exc:
|
except httpx.HTTPStatusError as exc:
|
||||||
|
|
@ -138,25 +143,25 @@ class LNbitsWallet(Wallet):
|
||||||
data = exc.response.json()
|
data = exc.response.json()
|
||||||
error_message = f"Payment {data['status']}: {data['detail']}."
|
error_message = f"Payment {data['status']}: {data['detail']}."
|
||||||
if data["status"] == "failed":
|
if data["status"] == "failed":
|
||||||
return PaymentResponse(False, None, None, None, error_message)
|
return PaymentResponse(ok=False, error_message=error_message)
|
||||||
return PaymentResponse(None, None, None, None, error_message)
|
return PaymentResponse(error_message=error_message)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
error_message = f"Unable to connect to {self.endpoint}."
|
error_message = f"Unable to connect to {self.endpoint}."
|
||||||
return PaymentResponse(None, None, None, None, error_message)
|
return PaymentResponse(error_message=error_message)
|
||||||
|
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'invalid json response'"
|
error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'missing required fields'"
|
error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.info(f"Failed to pay invoice {bolt11}")
|
logger.info(f"Failed to pay invoice {bolt11}")
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, f"Unable to connect to {self.endpoint}."
|
error_message=f"Unable to connect to {self.endpoint}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
|
|
||||||
|
|
@ -149,11 +149,13 @@ class LndWallet(Wallet):
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
error_message = str(exc)
|
error_message = str(exc)
|
||||||
return InvoiceResponse(False, None, None, error_message)
|
return InvoiceResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
checking_id = bytes_to_hex(resp.r_hash)
|
checking_id = bytes_to_hex(resp.r_hash)
|
||||||
payment_request = str(resp.payment_request)
|
payment_request = str(resp.payment_request)
|
||||||
return InvoiceResponse(True, checking_id, payment_request, None)
|
return InvoiceResponse(
|
||||||
|
ok=True, checking_id=checking_id, payment_request=payment_request
|
||||||
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
# fee_limit_fixed = ln.FeeLimit(fixed=fee_limit_msat // 1000)
|
# fee_limit_fixed = ln.FeeLimit(fixed=fee_limit_msat // 1000)
|
||||||
|
|
@ -167,7 +169,7 @@ class LndWallet(Wallet):
|
||||||
resp = await self.routerpc.SendPaymentV2(req).read()
|
resp = await self.routerpc.SendPaymentV2(req).read()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(None, None, None, None, str(exc))
|
return PaymentResponse(error_message=str(exc))
|
||||||
|
|
||||||
# PaymentStatus from https://github.com/lightningnetwork/lnd/blob/master/channeldb/payments.go#L178
|
# PaymentStatus from https://github.com/lightningnetwork/lnd/blob/master/channeldb/payments.go#L178
|
||||||
statuses = {
|
statuses = {
|
||||||
|
|
@ -199,7 +201,11 @@ class LndWallet(Wallet):
|
||||||
error_message = failure_reasons[resp.failure_reason]
|
error_message = failure_reasons[resp.failure_reason]
|
||||||
|
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
statuses[resp.status], checking_id, fee_msat, preimage, error_message
|
ok=statuses[resp.status],
|
||||||
|
checking_id=checking_id,
|
||||||
|
fee_msat=fee_msat,
|
||||||
|
preimage=preimage,
|
||||||
|
error_message=error_message,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
|
|
||||||
|
|
@ -132,34 +132,40 @@ class LndRestWallet(Wallet):
|
||||||
data = r.json()
|
data = r.json()
|
||||||
|
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
return InvoiceResponse(False, None, None, "no data")
|
return InvoiceResponse(ok=False, error_message="no data")
|
||||||
|
|
||||||
if "error" in data:
|
if "error" in data:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"""Server error: '{data["error"]}'"""
|
ok=False, error_message=f"""Server error: '{data["error"]}'"""
|
||||||
)
|
)
|
||||||
|
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
return InvoiceResponse(False, None, None, f"Server error: '{r.text}'")
|
return InvoiceResponse(
|
||||||
|
ok=False, error_message=f"Server error: '{r.text}'"
|
||||||
|
)
|
||||||
|
|
||||||
if "payment_request" not in data or "r_hash" not in data:
|
if "payment_request" not in data or "r_hash" not in data:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'missing required fields'"
|
ok=False, error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
|
|
||||||
payment_request = data["payment_request"]
|
payment_request = data["payment_request"]
|
||||||
payment_hash = base64.b64decode(data["r_hash"]).hex()
|
payment_hash = base64.b64decode(data["r_hash"]).hex()
|
||||||
checking_id = payment_hash
|
checking_id = payment_hash
|
||||||
|
return InvoiceResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=checking_id,
|
||||||
|
payment_request=payment_request,
|
||||||
|
)
|
||||||
|
|
||||||
return InvoiceResponse(True, checking_id, payment_request, None)
|
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'invalid json response'"
|
ok=False, error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"Unable to connect to {self.endpoint}."
|
ok=False, error_message=f"Unable to connect to {self.endpoint}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
|
|
@ -185,25 +191,27 @@ class LndRestWallet(Wallet):
|
||||||
payment_error = data.get("payment_error")
|
payment_error = data.get("payment_error")
|
||||||
if payment_error:
|
if payment_error:
|
||||||
logger.warning(f"LndRestWallet payment_error: {payment_error}.")
|
logger.warning(f"LndRestWallet payment_error: {payment_error}.")
|
||||||
return PaymentResponse(False, None, None, None, payment_error)
|
return PaymentResponse(ok=False, error_message=payment_error)
|
||||||
|
|
||||||
checking_id = base64.b64decode(data["payment_hash"]).hex()
|
checking_id = base64.b64decode(data["payment_hash"]).hex()
|
||||||
fee_msat = int(data["payment_route"]["total_fees_msat"])
|
fee_msat = int(data["payment_route"]["total_fees_msat"])
|
||||||
preimage = base64.b64decode(data["payment_preimage"]).hex()
|
preimage = base64.b64decode(data["payment_preimage"]).hex()
|
||||||
return PaymentResponse(True, checking_id, fee_msat, preimage, None)
|
return PaymentResponse(
|
||||||
|
ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage
|
||||||
|
)
|
||||||
except KeyError as exc:
|
except KeyError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'missing required fields'"
|
error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'invalid json response'"
|
error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(f"LndRestWallet pay_invoice POST error: {exc}.")
|
logger.warning(f"LndRestWallet pay_invoice POST error: {exc}.")
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, f"Unable to connect to {self.endpoint}."
|
error_message=f"Unable to connect to {self.endpoint}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
|
|
||||||
|
|
@ -91,20 +91,17 @@ class LNPayWallet(Wallet):
|
||||||
json=data,
|
json=data,
|
||||||
timeout=60,
|
timeout=60,
|
||||||
)
|
)
|
||||||
ok, checking_id, payment_request, error_message = (
|
if r.status_code == 201:
|
||||||
r.status_code == 201,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
r.text,
|
|
||||||
)
|
|
||||||
|
|
||||||
if ok:
|
|
||||||
data = r.json()
|
data = r.json()
|
||||||
checking_id, payment_request = data["id"], data["payment_request"]
|
self.pending_invoices.append(data["id"])
|
||||||
|
return InvoiceResponse(
|
||||||
self.pending_invoices.append(checking_id)
|
ok=True,
|
||||||
|
payment_request=data["payment_request"],
|
||||||
return InvoiceResponse(ok, checking_id, payment_request, error_message)
|
)
|
||||||
|
return InvoiceResponse(
|
||||||
|
ok=False,
|
||||||
|
error_message=r.text,
|
||||||
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
r = await self.client.post(
|
r = await self.client.post(
|
||||||
|
|
@ -116,17 +113,17 @@ class LNPayWallet(Wallet):
|
||||||
try:
|
try:
|
||||||
data = r.json()
|
data = r.json()
|
||||||
except Exception:
|
except Exception:
|
||||||
return PaymentResponse(
|
return PaymentResponse(ok=False, error_message="Got invalid JSON.")
|
||||||
False, None, 0, None, f"Got invalid JSON: {r.text[:200]}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
return PaymentResponse(False, None, None, None, data["message"])
|
return PaymentResponse(ok=False, error_message=data["message"])
|
||||||
|
|
||||||
checking_id = data["lnTx"]["id"]
|
checking_id = data["lnTx"]["id"]
|
||||||
fee_msat = 0
|
fee_msat = 0
|
||||||
preimage = data["lnTx"]["payment_preimage"]
|
preimage = data["lnTx"]["payment_preimage"]
|
||||||
return PaymentResponse(True, checking_id, fee_msat, preimage, None)
|
return PaymentResponse(
|
||||||
|
ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage
|
||||||
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
return await self.get_payment_status(checking_id)
|
return await self.get_payment_status(checking_id)
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ class LnTipsWallet(Wallet):
|
||||||
memo: Optional[str] = None,
|
memo: Optional[str] = None,
|
||||||
description_hash: Optional[bytes] = None,
|
description_hash: Optional[bytes] = None,
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**kwargs,
|
**_,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
data: Dict = {"amount": amount, "description_hash": "", "memo": memo or ""}
|
data: Dict = {"amount": amount, "description_hash": "", "memo": memo or ""}
|
||||||
if description_hash:
|
if description_hash:
|
||||||
|
|
@ -91,11 +91,13 @@ class LnTipsWallet(Wallet):
|
||||||
except Exception:
|
except Exception:
|
||||||
error_message = r.text
|
error_message = r.text
|
||||||
|
|
||||||
return InvoiceResponse(False, None, None, error_message)
|
return InvoiceResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
data = r.json()
|
data = r.json()
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
True, data["payment_hash"], data["payment_request"], None
|
ok=True,
|
||||||
|
checking_id=data["payment_hash"],
|
||||||
|
payment_request=data["payment_request"],
|
||||||
)
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
|
|
@ -105,7 +107,7 @@ class LnTipsWallet(Wallet):
|
||||||
timeout=None,
|
timeout=None,
|
||||||
)
|
)
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
return PaymentResponse(False, None, 0, None, r.text)
|
return PaymentResponse(ok=False, error_message=r.text)
|
||||||
|
|
||||||
if "error" in r.json():
|
if "error" in r.json():
|
||||||
try:
|
try:
|
||||||
|
|
@ -113,13 +115,15 @@ class LnTipsWallet(Wallet):
|
||||||
error_message = data["error"]
|
error_message = data["error"]
|
||||||
except Exception:
|
except Exception:
|
||||||
error_message = r.text
|
error_message = r.text
|
||||||
return PaymentResponse(False, None, 0, None, error_message)
|
return PaymentResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
data = r.json()["details"]
|
data = r.json()["details"]
|
||||||
checking_id = data["payment_hash"]
|
checking_id = data["payment_hash"]
|
||||||
fee_msat = -data["fee"]
|
fee_msat = -data["fee"]
|
||||||
preimage = data["preimage"]
|
preimage = data["preimage"]
|
||||||
return PaymentResponse(True, checking_id, fee_msat, preimage, None)
|
return PaymentResponse(
|
||||||
|
ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage
|
||||||
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ class NWCWallet(Wallet):
|
||||||
memo: Optional[str] = None,
|
memo: Optional[str] = None,
|
||||||
description_hash: Optional[bytes] = None,
|
description_hash: Optional[bytes] = None,
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**kwargs,
|
**_,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
desc = ""
|
desc = ""
|
||||||
desc_hash = None
|
desc_hash = None
|
||||||
|
|
@ -148,10 +148,8 @@ class NWCWallet(Wallet):
|
||||||
info = await self.conn.get_info()
|
info = await self.conn.get_info()
|
||||||
if "make_invoice" not in info["supported_methods"]:
|
if "make_invoice" not in info["supported_methods"]:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False,
|
ok=False,
|
||||||
None,
|
error_message="make_invoice is not supported by this NWC service.",
|
||||||
None,
|
|
||||||
"make_invoice is not supported by this NWC service.",
|
|
||||||
)
|
)
|
||||||
resp = await self.conn.call(
|
resp = await self.conn.call(
|
||||||
"make_invoice",
|
"make_invoice",
|
||||||
|
|
@ -175,7 +173,9 @@ class NWCWallet(Wallet):
|
||||||
"expired": False,
|
"expired": False,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return InvoiceResponse(True, checking_id, payment_request, None)
|
return InvoiceResponse(
|
||||||
|
ok=True, checking_id=checking_id, payment_request=payment_request
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return InvoiceResponse(ok=False, error_message=str(e))
|
return InvoiceResponse(ok=False, error_message=str(e))
|
||||||
|
|
||||||
|
|
@ -203,7 +203,9 @@ class NWCWallet(Wallet):
|
||||||
|
|
||||||
if "lookup_invoice" not in info["supported_methods"]:
|
if "lookup_invoice" not in info["supported_methods"]:
|
||||||
# if not supported, we assume it succeeded
|
# if not supported, we assume it succeeded
|
||||||
return PaymentResponse(True, payment_hash, None, preimage, None)
|
return PaymentResponse(
|
||||||
|
ok=True, checking_id=payment_hash, preimage=preimage, fee_msat=0
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
payment_data = await self.conn.call(
|
payment_data = await self.conn.call(
|
||||||
|
|
@ -213,15 +215,20 @@ class NWCWallet(Wallet):
|
||||||
"preimage", None
|
"preimage", None
|
||||||
)
|
)
|
||||||
if not settled:
|
if not settled:
|
||||||
return PaymentResponse(None, payment_hash, None, None, None)
|
return PaymentResponse(checking_id=payment_hash)
|
||||||
else:
|
else:
|
||||||
fee_msat = payment_data.get("fees_paid", None)
|
fee_msat = payment_data.get("fees_paid", None)
|
||||||
return PaymentResponse(True, payment_hash, fee_msat, preimage, None)
|
return PaymentResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=payment_hash,
|
||||||
|
fee_msat=fee_msat,
|
||||||
|
preimage=preimage,
|
||||||
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
# Workaround: some nwc service providers might not store the invoice
|
# Workaround: some nwc service providers might not store the invoice
|
||||||
# right away, so this call may raise an exception.
|
# right away, so this call may raise an exception.
|
||||||
# We will assume the payment is pending anyway
|
# We will assume the payment is pending anyway
|
||||||
return PaymentResponse(None, payment_hash, None, None, None)
|
return PaymentResponse(checking_id=payment_hash)
|
||||||
except NWCError as e:
|
except NWCError as e:
|
||||||
logger.error("Error paying invoice: " + str(e))
|
logger.error("Error paying invoice: " + str(e))
|
||||||
failure_codes = [
|
failure_codes = [
|
||||||
|
|
@ -237,13 +244,14 @@ class NWCWallet(Wallet):
|
||||||
]
|
]
|
||||||
failed = e.code in failure_codes
|
failed = e.code in failure_codes
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None if not failed else False,
|
ok=None if not failed else False,
|
||||||
error_message=e.message if failed else None,
|
error_message=e.message if failed else None,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Error paying invoice: " + str(e))
|
msg = "Error paying invoice: " + str(e)
|
||||||
|
logger.error(msg)
|
||||||
# assume pending
|
# assume pending
|
||||||
return PaymentResponse(None)
|
return PaymentResponse(error_message=msg)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
return await self.get_payment_status(checking_id)
|
return await self.get_payment_status(checking_id)
|
||||||
|
|
@ -300,6 +308,7 @@ class NWCConnection:
|
||||||
self.account_private_key = secp256k1.PrivateKey(bytes.fromhex(secret))
|
self.account_private_key = secp256k1.PrivateKey(bytes.fromhex(secret))
|
||||||
self.account_private_key_hex = secret
|
self.account_private_key_hex = secret
|
||||||
self.account_public_key = self.account_private_key.pubkey
|
self.account_public_key = self.account_private_key.pubkey
|
||||||
|
assert self.account_public_key
|
||||||
self.account_public_key_hex = self.account_public_key.serialize().hex()[2:]
|
self.account_public_key_hex = self.account_public_key.serialize().hex()[2:]
|
||||||
|
|
||||||
# Extract service key (used for encryption to identify the nwc service provider)
|
# Extract service key (used for encryption to identify the nwc service provider)
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ class OpenNodeWallet(Wallet):
|
||||||
memo: Optional[str] = None,
|
memo: Optional[str] = None,
|
||||||
description_hash: Optional[bytes] = None,
|
description_hash: Optional[bytes] = None,
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**kwargs,
|
**_,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
if description_hash or unhashed_description:
|
if description_hash or unhashed_description:
|
||||||
raise UnsupportedError("description_hash")
|
raise UnsupportedError("description_hash")
|
||||||
|
|
@ -88,13 +88,15 @@ class OpenNodeWallet(Wallet):
|
||||||
|
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
error_message = r.json()["message"]
|
error_message = r.json()["message"]
|
||||||
return InvoiceResponse(False, None, None, error_message)
|
return InvoiceResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
data = r.json()["data"]
|
data = r.json()["data"]
|
||||||
checking_id = data["id"]
|
checking_id = data["id"]
|
||||||
payment_request = data["lightning_invoice"]["payreq"]
|
payment_request = data["lightning_invoice"]["payreq"]
|
||||||
self.pending_invoices.append(checking_id)
|
self.pending_invoices.append(checking_id)
|
||||||
return InvoiceResponse(True, checking_id, payment_request, None)
|
return InvoiceResponse(
|
||||||
|
ok=True, checking_id=checking_id, payment_request=payment_request
|
||||||
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
r = await self.client.post(
|
r = await self.client.post(
|
||||||
|
|
@ -105,16 +107,15 @@ class OpenNodeWallet(Wallet):
|
||||||
|
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
error_message = r.json()["message"]
|
error_message = r.json()["message"]
|
||||||
return PaymentResponse(False, None, None, None, error_message)
|
return PaymentResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
data = r.json()["data"]
|
data = r.json()["data"]
|
||||||
checking_id = data["id"]
|
checking_id = data["id"]
|
||||||
fee_msat = -data["fee"] * 1000
|
fee_msat = -data["fee"] * 1000
|
||||||
|
# pending
|
||||||
if data["status"] != "paid":
|
if data["status"] != "paid":
|
||||||
return PaymentResponse(None, checking_id, fee_msat, None, "payment failed")
|
return PaymentResponse(ok=None, checking_id=checking_id, fee_msat=fee_msat)
|
||||||
|
return PaymentResponse(ok=True, checking_id=checking_id, fee_msat=fee_msat)
|
||||||
return PaymentResponse(True, checking_id, fee_msat, None, None)
|
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
r = await self.client.get(f"/v1/charge/{checking_id}")
|
r = await self.client.get(f"/v1/charge/{checking_id}")
|
||||||
|
|
|
||||||
|
|
@ -133,25 +133,29 @@ class PhoenixdWallet(Wallet):
|
||||||
if r.is_error or "paymentHash" not in data:
|
if r.is_error or "paymentHash" not in data:
|
||||||
error_message = data["message"]
|
error_message = data["message"]
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"Server error: '{error_message}'"
|
ok=False, error_message=f"Server error: '{error_message}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
checking_id = data["paymentHash"]
|
checking_id = data["paymentHash"]
|
||||||
payment_request = data["serialized"]
|
payment_request = data["serialized"]
|
||||||
return InvoiceResponse(True, checking_id, payment_request, None)
|
return InvoiceResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=checking_id,
|
||||||
|
payment_request=payment_request,
|
||||||
|
)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'invalid json response'"
|
ok=False, error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except KeyError as exc:
|
except KeyError as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, "Server error: 'missing required fields'"
|
ok=False, error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return InvoiceResponse(
|
return InvoiceResponse(
|
||||||
False, None, None, f"Unable to connect to {self.endpoint}."
|
ok=False, error_message=f"Unable to connect to {self.endpoint}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
|
|
@ -168,31 +172,35 @@ class PhoenixdWallet(Wallet):
|
||||||
data = r.json()
|
data = r.json()
|
||||||
|
|
||||||
if "routingFeeSat" not in data and "reason" in data:
|
if "routingFeeSat" not in data and "reason" in data:
|
||||||
return PaymentResponse(None, None, None, None, data["reason"])
|
return PaymentResponse(error_message=data["reason"])
|
||||||
|
|
||||||
if r.is_error or "paymentHash" not in data:
|
if r.is_error or "paymentHash" not in data:
|
||||||
error_message = data["message"] if "message" in data else r.text
|
error_message = data["message"] if "message" in data else r.text
|
||||||
return PaymentResponse(None, None, None, None, error_message)
|
return PaymentResponse(error_message=error_message)
|
||||||
|
|
||||||
checking_id = data["paymentHash"]
|
checking_id = data["paymentHash"]
|
||||||
fee_msat = -int(data["routingFeeSat"]) * 1000
|
fee_msat = -int(data["routingFeeSat"]) * 1000
|
||||||
preimage = data["paymentPreimage"]
|
preimage = data["paymentPreimage"]
|
||||||
|
return PaymentResponse(
|
||||||
return PaymentResponse(True, checking_id, fee_msat, preimage, None)
|
ok=True,
|
||||||
|
checking_id=checking_id,
|
||||||
|
fee_msat=fee_msat,
|
||||||
|
preimage=preimage,
|
||||||
|
)
|
||||||
|
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'invalid json response'"
|
error_message="Server error: 'invalid json response'"
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, "Server error: 'missing required fields'"
|
error_message="Server error: 'missing required fields'"
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.info(f"Failed to pay invoice {bolt11}")
|
logger.info(f"Failed to pay invoice {bolt11}")
|
||||||
logger.warning(exc)
|
logger.warning(exc)
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
None, None, None, None, f"Unable to connect to {self.endpoint}."
|
error_message=f"Unable to connect to {self.endpoint}."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
|
|
||||||
|
|
@ -115,8 +115,6 @@ class SparkWallet(Wallet):
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
label = f"lbs{random.random()}"
|
label = f"lbs{random.random()}"
|
||||||
checking_id = label
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if description_hash:
|
if description_hash:
|
||||||
r = await self.invoicewithdescriptionhash(
|
r = await self.invoicewithdescriptionhash(
|
||||||
|
|
@ -138,11 +136,13 @@ class SparkWallet(Wallet):
|
||||||
exposeprivatechannels=True,
|
exposeprivatechannels=True,
|
||||||
expiry=kwargs.get("expiry"),
|
expiry=kwargs.get("expiry"),
|
||||||
)
|
)
|
||||||
ok, payment_request, error_message = True, r["bolt11"], ""
|
return InvoiceResponse(
|
||||||
|
ok=True,
|
||||||
|
payment_request=r["bolt11"],
|
||||||
|
checking_id=label,
|
||||||
|
)
|
||||||
except (SparkError, UnknownError) as e:
|
except (SparkError, UnknownError) as e:
|
||||||
ok, payment_request, error_message = False, None, str(e)
|
return InvoiceResponse(ok=False, error_message=str(e))
|
||||||
|
|
||||||
return InvoiceResponse(ok, checking_id, payment_request, error_message)
|
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
try:
|
try:
|
||||||
|
|
@ -152,17 +152,22 @@ class SparkWallet(Wallet):
|
||||||
)
|
)
|
||||||
fee_msat = -int(r["msatoshi_sent"] - r["msatoshi"])
|
fee_msat = -int(r["msatoshi_sent"] - r["msatoshi"])
|
||||||
preimage = r["payment_preimage"]
|
preimage = r["payment_preimage"]
|
||||||
return PaymentResponse(True, r["payment_hash"], fee_msat, preimage, None)
|
return PaymentResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=r["payment_hash"],
|
||||||
|
fee_msat=fee_msat,
|
||||||
|
preimage=preimage,
|
||||||
|
)
|
||||||
|
|
||||||
except (SparkError, UnknownError) as exc:
|
except (SparkError, UnknownError) as exc:
|
||||||
listpays = await self.listpays(bolt11)
|
listpays = await self.listpays(bolt11)
|
||||||
if not listpays:
|
if not listpays:
|
||||||
return PaymentResponse(False, None, None, None, str(exc))
|
return PaymentResponse(ok=False, error_message=str(exc))
|
||||||
|
|
||||||
pays = listpays["pays"]
|
pays = listpays["pays"]
|
||||||
|
|
||||||
if len(pays) == 0:
|
if len(pays) == 0:
|
||||||
return PaymentResponse(False, None, None, None, str(exc))
|
return PaymentResponse(ok=False, error_message=str(exc))
|
||||||
|
|
||||||
pay = pays[0]
|
pay = pays[0]
|
||||||
payment_hash = pay["payment_hash"]
|
payment_hash = pay["payment_hash"]
|
||||||
|
|
@ -174,10 +179,10 @@ class SparkWallet(Wallet):
|
||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
if pay["status"] == "failed":
|
if pay["status"] == "failed":
|
||||||
return PaymentResponse(False, None, None, None, str(exc))
|
return PaymentResponse(ok=False, error_message=str(exc))
|
||||||
|
|
||||||
if pay["status"] == "pending":
|
if pay["status"] == "pending":
|
||||||
return PaymentResponse(None, payment_hash, None, None, None)
|
return PaymentResponse(ok=None, checking_id=payment_hash)
|
||||||
|
|
||||||
if pay["status"] == "complete":
|
if pay["status"] == "complete":
|
||||||
r = pay
|
r = pay
|
||||||
|
|
@ -190,10 +195,13 @@ class SparkWallet(Wallet):
|
||||||
fee_msat = -int(r["msatoshi_sent"] - r["msatoshi"])
|
fee_msat = -int(r["msatoshi_sent"] - r["msatoshi"])
|
||||||
preimage = r["payment_preimage"]
|
preimage = r["payment_preimage"]
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
True, r["payment_hash"], fee_msat, preimage, None
|
ok=True,
|
||||||
|
checking_id=r["payment_hash"],
|
||||||
|
fee_msat=fee_msat,
|
||||||
|
preimage=preimage,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return PaymentResponse(False, None, None, None, str(exc))
|
return PaymentResponse(ok=False, error_message=str(exc))
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ import hashlib
|
||||||
from typing import AsyncGenerator, Dict, Optional
|
from typing import AsyncGenerator, Dict, Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
from bolt11 import decode as bolt11_decode
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from lnbits import bolt11
|
|
||||||
from lnbits.settings import settings
|
from lnbits.settings import settings
|
||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
|
|
@ -61,7 +61,7 @@ class ZBDWallet(Wallet):
|
||||||
memo: Optional[str] = None,
|
memo: Optional[str] = None,
|
||||||
description_hash: Optional[bytes] = None,
|
description_hash: Optional[bytes] = None,
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**kwargs,
|
**_,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
# https://api.zebedee.io/v0/charges
|
# https://api.zebedee.io/v0/charges
|
||||||
|
|
||||||
|
|
@ -89,21 +89,23 @@ class ZBDWallet(Wallet):
|
||||||
|
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
error_message = r.json()["message"]
|
error_message = r.json()["message"]
|
||||||
return InvoiceResponse(False, None, None, error_message)
|
return InvoiceResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
data = r.json()["data"]
|
data = r.json()["data"]
|
||||||
checking_id = data["id"] # this is a zbd id
|
checking_id = data["id"] # this is a zbd id
|
||||||
payment_request = data["invoice"]["request"]
|
payment_request = data["invoice"]["request"]
|
||||||
return InvoiceResponse(True, checking_id, payment_request, None)
|
return InvoiceResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=checking_id,
|
||||||
|
payment_request=payment_request,
|
||||||
|
)
|
||||||
|
|
||||||
async def pay_invoice(
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
self, bolt11_invoice: str, fee_limit_msat: int
|
|
||||||
) -> PaymentResponse:
|
|
||||||
# https://api.zebedee.io/v0/payments
|
# https://api.zebedee.io/v0/payments
|
||||||
r = await self.client.post(
|
r = await self.client.post(
|
||||||
"payments",
|
"payments",
|
||||||
json={
|
json={
|
||||||
"invoice": bolt11_invoice,
|
"invoice": bolt11,
|
||||||
"description": "",
|
"description": "",
|
||||||
"amount": "",
|
"amount": "",
|
||||||
"internalId": "",
|
"internalId": "",
|
||||||
|
|
@ -114,15 +116,17 @@ class ZBDWallet(Wallet):
|
||||||
|
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
error_message = r.json()["message"]
|
error_message = r.json()["message"]
|
||||||
return PaymentResponse(False, None, None, None, error_message)
|
return PaymentResponse(ok=False, error_message=error_message)
|
||||||
|
|
||||||
data = r.json()
|
data = r.json()
|
||||||
|
|
||||||
checking_id = bolt11.decode(bolt11_invoice).payment_hash
|
checking_id = bolt11_decode(bolt11).payment_hash
|
||||||
fee_msat = -int(data["data"]["fee"])
|
fee_msat = -int(data["data"]["fee"])
|
||||||
preimage = data["data"]["preimage"]
|
preimage = data["data"]["preimage"]
|
||||||
|
|
||||||
return PaymentResponse(True, checking_id, fee_msat, preimage, None)
|
return PaymentResponse(
|
||||||
|
ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage
|
||||||
|
)
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
r = await self.client.get(f"charges/{checking_id}")
|
r = await self.client.get(f"charges/{checking_id}")
|
||||||
|
|
@ -137,7 +141,7 @@ class ZBDWallet(Wallet):
|
||||||
"expired": False,
|
"expired": False,
|
||||||
"completed": True,
|
"completed": True,
|
||||||
}
|
}
|
||||||
return PaymentStatus(statuses[data.get("status")])
|
return PaymentStatus(paid=statuses[data.get("status")])
|
||||||
|
|
||||||
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
|
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
|
||||||
r = await self.client.get(f"payments/{checking_id}")
|
r = await self.client.get(f"payments/{checking_id}")
|
||||||
|
|
@ -155,7 +159,7 @@ class ZBDWallet(Wallet):
|
||||||
"failed": False,
|
"failed": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
return PaymentStatus(statuses[data.get("status")], fee_msat=None, preimage=None)
|
return PaymentStatus(paid=statuses[data.get("status")])
|
||||||
|
|
||||||
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
||||||
self.queue: asyncio.Queue = asyncio.Queue(0)
|
self.queue: asyncio.Queue = asyncio.Queue(0)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue