refactor: dev-friendly payment status name (#2322)

* refactor: dev-friendly payment status name
* refactor: change `PaymentStatus(True, ...)` to `PaymentSuccessStatus(...)`
This commit is contained in:
Vlad Stan 2024-03-13 17:17:33 +02:00 committed by GitHub
parent 65b8868c36
commit 352fd23c0b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 120 additions and 74 deletions

View file

@ -18,7 +18,7 @@ from lnbits.helpers import url_for
from lnbits.lnurl import encode as lnurl_encode
from lnbits.settings import settings
from lnbits.wallets import get_wallet_class
from lnbits.wallets.base import PaymentStatus
from lnbits.wallets.base import PaymentPendingStatus, PaymentStatus
class BaseWallet(BaseModel):
@ -258,7 +258,7 @@ class Payment(FromRowModel):
conn: Optional[Connection] = None,
) -> PaymentStatus:
if self.is_uncheckable:
return PaymentStatus(None)
return PaymentPendingStatus()
logger.debug(
f"Checking {'outgoing' if self.is_out else 'incoming'} "

View file

@ -31,7 +31,12 @@ from lnbits.settings import (
)
from lnbits.utils.exchange_rates import fiat_amount_as_satoshis, satoshis_amount_as_fiat
from lnbits.wallets import FAKE_WALLET, get_wallet_class, set_wallet_class
from lnbits.wallets.base import PaymentResponse, PaymentStatus
from lnbits.wallets.base import (
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
PaymentSuccessStatus,
)
from .crud import (
check_internal,
@ -577,10 +582,10 @@ async def check_transaction_status(
wallet_id, payment_hash, conn=conn
)
if not payment:
return PaymentStatus(None)
return PaymentPendingStatus()
if not payment.pending:
# note: before, we still checked the status of the payment again
return PaymentStatus(True, fee_msat=payment.fee)
return PaymentSuccessStatus(fee_msat=payment.fee)
status: PaymentStatus = await payment.check_status()
return status

View file

@ -9,6 +9,7 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
StatusResponse,
@ -111,7 +112,7 @@ class AlbyWallet(Wallet):
r = await self.client.get(f"/invoices/{checking_id}")
if r.is_error:
return PaymentStatus(None)
return PaymentPendingStatus()
data = r.json()

View file

@ -52,6 +52,18 @@ class PaymentStatus(NamedTuple):
return "unknown (should never happen)"
class PaymentSuccessStatus(PaymentStatus):
paid = True
class PaymentFailedStatus(PaymentStatus):
paid = False
class PaymentPendingStatus(PaymentStatus):
paid = None
class Wallet(ABC):
async def cleanup(self):
pass

View file

@ -10,6 +10,7 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
StatusResponse,
@ -139,7 +140,7 @@ class ClicheWallet(Wallet):
if data.get("error") is not None and data["error"].get("message"):
logger.error(data["error"]["message"])
return PaymentStatus(None)
return PaymentPendingStatus()
statuses = {"pending": None, "complete": True, "failed": False}
return PaymentStatus(statuses[data["result"]["status"]])
@ -152,7 +153,7 @@ class ClicheWallet(Wallet):
if data.get("error") is not None and data["error"].get("message"):
logger.error(data["error"]["message"])
return PaymentStatus(None)
return PaymentPendingStatus()
payment = data["result"]
statuses = {"pending": None, "complete": True, "failed": False}
return PaymentStatus(

View file

@ -12,8 +12,11 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentFailedStatus,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
PaymentSuccessStatus,
StatusResponse,
Unsupported,
Wallet,
@ -149,30 +152,33 @@ class CoreLightningWallet(Wallet):
try:
r: dict = self.ln.listinvoices(payment_hash=checking_id) # type: ignore
except RpcError:
return PaymentStatus(None)
return PaymentPendingStatus()
if not r["invoices"]:
return PaymentStatus(None)
return PaymentPendingStatus()
invoice_resp = r["invoices"][-1]
if invoice_resp["payment_hash"] == checking_id:
if invoice_resp["status"] == "paid":
return PaymentStatus(True)
return PaymentSuccessStatus()
elif invoice_resp["status"] == "unpaid":
return PaymentStatus(None)
return PaymentPendingStatus()
elif invoice_resp["status"] == "expired":
return PaymentStatus(False)
return PaymentFailedStatus()
else:
logger.warning(f"supplied an invalid checking_id: {checking_id}")
return PaymentStatus(None)
return PaymentPendingStatus()
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
try:
r: dict = self.ln.listpays(payment_hash=checking_id) # type: ignore
except Exception:
return PaymentStatus(None)
if "pays" not in r or not r["pays"]:
return PaymentStatus(None)
return PaymentPendingStatus()
if "pays" not in r:
return PaymentPendingStatus()
if not r["pays"]:
# no payment with this payment_hash is found
return PaymentFailedStatus()
payment_resp = r["pays"][-1]
@ -183,14 +189,16 @@ class CoreLightningWallet(Wallet):
payment_resp["amount_sent_msat"] - payment_resp["amount_msat"]
)
return PaymentStatus(True, fee_msat, payment_resp["preimage"])
return PaymentSuccessStatus(
fee_msat=fee_msat, preimage=payment_resp["preimage"]
)
elif status == "failed":
return PaymentStatus(False)
return PaymentFailedStatus()
else:
return PaymentStatus(None)
return PaymentPendingStatus()
else:
logger.warning(f"supplied an invalid checking_id: {checking_id}")
return PaymentStatus(None)
return PaymentPendingStatus()
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
while True:

View file

@ -12,6 +12,7 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
StatusResponse,
@ -184,7 +185,7 @@ class CoreLightningRestWallet(Wallet):
return PaymentStatus(self.statuses.get(data["invoices"][0]["status"]))
except Exception as e:
logger.error(f"Error getting invoice status: {e}")
return PaymentStatus(None)
return PaymentPendingStatus()
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
r = await self.client.get(
@ -211,7 +212,7 @@ class CoreLightningRestWallet(Wallet):
return PaymentStatus(self.statuses.get(pay["status"]), fee_msat, preimage)
except Exception as e:
logger.error(f"Error getting payment status: {e}")
return PaymentStatus(None)
return PaymentPendingStatus()
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
while True:

View file

@ -13,6 +13,7 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
StatusResponse,
@ -180,7 +181,7 @@ class EclairWallet(Wallet):
}
return PaymentStatus(statuses.get(data["status"]["type"]))
except Exception:
return PaymentStatus(None)
return PaymentPendingStatus()
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
try:
@ -211,7 +212,7 @@ class EclairWallet(Wallet):
statuses.get(data["status"]["type"]), fee_msat, preimage
)
except Exception:
return PaymentStatus(None)
return PaymentPendingStatus()
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
while True:

View file

@ -19,6 +19,7 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
StatusResponse,
@ -121,7 +122,7 @@ class FakeWallet(Wallet):
return PaymentStatus(paid)
async def get_payment_status(self, _: str) -> PaymentStatus:
return PaymentStatus(None)
return PaymentPendingStatus()
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
while True:

View file

@ -9,8 +9,10 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
PaymentSuccessStatus,
StatusResponse,
Wallet,
)
@ -120,27 +122,27 @@ class LNbitsWallet(Wallet):
url=f"/api/v1/payments/{checking_id}",
)
if r.is_error:
return PaymentStatus(None)
return PaymentPendingStatus()
return PaymentStatus(r.json()["paid"])
except Exception:
return PaymentStatus(None)
return PaymentPendingStatus()
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
try:
r = await self.client.get(url=f"/api/v1/payments/{checking_id}")
r.raise_for_status()
except Exception:
return PaymentStatus(None)
r = await self.client.get(url=f"/api/v1/payments/{checking_id}")
if r.is_error:
return PaymentPendingStatus()
data = r.json()
if "paid" not in data or not data["paid"]:
return PaymentStatus(None)
return PaymentPendingStatus()
if "details" not in data:
return PaymentStatus(None)
return PaymentPendingStatus()
return PaymentStatus(True, data["details"]["fee"], data["preimage"])
return PaymentSuccessStatus(
fee_msat=data["details"]["fee"], preimage=data["preimage"]
)
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
url = f"{self.endpoint}/api/v1/payments/sse"

View file

@ -16,8 +16,10 @@ from lnbits.utils.crypto import AESCipher
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
PaymentSuccessStatus,
StatusResponse,
Wallet,
)
@ -203,15 +205,15 @@ class LndWallet(Wallet):
except ValueError:
# this may happen if we switch between backend wallets
# that use different checking_id formats
return PaymentStatus(None)
return PaymentPendingStatus()
try:
resp = await self.rpc.LookupInvoice(ln.PaymentHash(r_hash=r_hash))
except grpc.RpcError:
return PaymentStatus(None)
return PaymentPendingStatus()
if resp.settled:
return PaymentStatus(True)
return PaymentSuccessStatus()
return PaymentStatus(None)
return PaymentPendingStatus()
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
"""
@ -224,7 +226,7 @@ class LndWallet(Wallet):
except ValueError:
# this may happen if we switch between backend wallets
# that use different checking_id formats
return PaymentStatus(None)
return PaymentPendingStatus()
resp = self.routerpc.TrackPaymentV2(
router.TrackPaymentRequest(payment_hash=r_hash)
@ -247,16 +249,15 @@ class LndWallet(Wallet):
try:
async for payment in resp:
if len(payment.htlcs) and statuses[payment.status]:
return PaymentStatus(
True,
-payment.htlcs[-1].route.total_fees_msat,
bytes_to_hex(payment.htlcs[-1].preimage),
return PaymentSuccessStatus(
fee_msat=-payment.htlcs[-1].route.total_fees_msat,
preimage=bytes_to_hex(payment.htlcs[-1].preimage),
)
return PaymentStatus(statuses[payment.status])
except Exception: # most likely the payment wasn't found
return PaymentStatus(None)
return PaymentPendingStatus()
return PaymentStatus(None)
return PaymentPendingStatus()
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
while True:

View file

@ -13,8 +13,11 @@ from lnbits.utils.crypto import AESCipher
from .base import (
InvoiceResponse,
PaymentFailedStatus,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
PaymentSuccessStatus,
StatusResponse,
Wallet,
)
@ -168,9 +171,9 @@ class LndRestWallet(Wallet):
if r.is_error or not r.json().get("settled"):
# this must also work when checking_id is not a hex recognizable by lnd
# it will return an error and no "settled" attribute on the object
return PaymentStatus(None)
return PaymentPendingStatus()
return PaymentStatus(True)
return PaymentSuccessStatus()
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
"""
@ -182,7 +185,7 @@ class LndRestWallet(Wallet):
"ascii"
)
except ValueError:
return PaymentStatus(None)
return PaymentPendingStatus()
url = f"/v2/router/track/{checking_id}"
@ -210,8 +213,8 @@ class LndRestWallet(Wallet):
and line["error"].get("message")
== "payment isn't initiated"
):
return PaymentStatus(False)
return PaymentStatus(None)
return PaymentFailedStatus()
return PaymentPendingStatus()
payment = line.get("result")
if payment is not None and payment.get("status"):
return PaymentStatus(
@ -220,11 +223,11 @@ class LndRestWallet(Wallet):
preimage=payment.get("payment_preimage"),
)
else:
return PaymentStatus(None)
return PaymentPendingStatus()
except Exception:
continue
return PaymentStatus(None)
return PaymentPendingStatus()
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
while True:

View file

@ -9,6 +9,7 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
StatusResponse,
@ -134,7 +135,7 @@ class LNPayWallet(Wallet):
)
if r.is_error:
return PaymentStatus(None)
return PaymentPendingStatus()
data = r.json()
preimage = data["payment_preimage"]

View file

@ -11,6 +11,7 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
StatusResponse,
@ -132,7 +133,7 @@ class LnTipsWallet(Wallet):
data = r.json()
return PaymentStatus(data["paid"])
except Exception:
return PaymentStatus(None)
return PaymentPendingStatus()
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
try:
@ -147,7 +148,7 @@ class LnTipsWallet(Wallet):
paid_to_status = {False: None, True: True}
return PaymentStatus(paid_to_status[data.get("paid")])
except Exception:
return PaymentStatus(None)
return PaymentPendingStatus()
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
last_connected = None

View file

@ -8,6 +8,7 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
StatusResponse,
@ -116,7 +117,7 @@ class OpenNodeWallet(Wallet):
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
r = await self.client.get(f"/v1/charge/{checking_id}")
if r.is_error:
return PaymentStatus(None)
return PaymentPendingStatus()
data = r.json()["data"]
statuses = {"processing": None, "paid": True, "unpaid": None}
return PaymentStatus(statuses[data.get("status")])
@ -125,7 +126,7 @@ class OpenNodeWallet(Wallet):
r = await self.client.get(f"/v1/withdrawal/{checking_id}")
if r.is_error:
return PaymentStatus(None)
return PaymentPendingStatus()
data = r.json()["data"]
statuses = {

View file

@ -11,8 +11,11 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentFailedStatus,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
PaymentSuccessStatus,
StatusResponse,
Wallet,
)
@ -196,33 +199,33 @@ class SparkWallet(Wallet):
try:
r = await self.listinvoices(label=checking_id)
except (SparkError, UnknownError):
return PaymentStatus(None)
return PaymentPendingStatus()
if not r or not r.get("invoices"):
return PaymentStatus(None)
return PaymentPendingStatus()
if r["invoices"][0]["status"] == "paid":
return PaymentStatus(True)
return PaymentSuccessStatus()
else:
return PaymentStatus(False)
return PaymentFailedStatus()
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
# check if it's 32 bytes hex
if len(checking_id) != 64:
return PaymentStatus(None)
return PaymentPendingStatus()
try:
int(checking_id, 16)
except ValueError:
return PaymentStatus(None)
return PaymentPendingStatus()
# ask sparko
try:
r = await self.listpays(payment_hash=checking_id)
except (SparkError, UnknownError):
return PaymentStatus(None)
return PaymentPendingStatus()
if not r["pays"]:
return PaymentStatus(False)
return PaymentFailedStatus()
if r["pays"][0]["payment_hash"] == checking_id:
status = r["pays"][0]["status"]
if status == "complete":
@ -230,10 +233,12 @@ class SparkWallet(Wallet):
int(r["pays"][0]["amount_sent_msat"][0:-4])
- int(r["pays"][0]["amount_msat"][0:-4])
)
return PaymentStatus(True, fee_msat, r["pays"][0]["preimage"])
return PaymentSuccessStatus(
fee_msat=fee_msat, preimage=r["pays"][0]["preimage"]
)
if status == "failed":
return PaymentStatus(False)
return PaymentStatus(None)
return PaymentFailedStatus()
return PaymentPendingStatus()
raise KeyError("supplied an invalid checking_id")
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:

View file

@ -4,6 +4,7 @@ from loguru import logger
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
StatusResponse,
@ -31,10 +32,10 @@ class VoidWallet(Wallet):
)
async def get_invoice_status(self, *_, **__) -> PaymentStatus:
return PaymentStatus(None)
return PaymentPendingStatus()
async def get_payment_status(self, *_, **__) -> PaymentStatus:
return PaymentStatus(None)
return PaymentPendingStatus()
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
yield ""

View file

@ -9,6 +9,7 @@ from lnbits.settings import settings
from .base import (
InvoiceResponse,
PaymentPendingStatus,
PaymentResponse,
PaymentStatus,
StatusResponse,
@ -121,7 +122,7 @@ class ZBDWallet(Wallet):
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
r = await self.client.get(f"charges/{checking_id}")
if r.is_error:
return PaymentStatus(None)
return PaymentPendingStatus()
data = r.json()["data"]
statuses = {
@ -136,7 +137,7 @@ class ZBDWallet(Wallet):
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
r = await self.client.get(f"payments/{checking_id}")
if r.is_error:
return PaymentStatus(None)
return PaymentPendingStatus()
data = r.json()["data"]