feat: add Breez *Liquid* SDK funding source (#2681)
Co-authored-by: Pavol Rusnak <pavol@rusnak.io>
Co-authored-by: dni ⚡ <office@dnilabs.com>
Co-authored-by: Vlad Stan <stan.v.vlad@gmail.com>
This commit is contained in:
parent
09b91f9f79
commit
0529ee2835
13 changed files with 385 additions and 6 deletions
|
|
@ -153,6 +153,12 @@ BREEZ_GREENLIGHT_DEVICE_KEY="/path/to/breezsdk/device.pem" # or BASE64/HEXSTRIN
|
||||||
BREEZ_GREENLIGHT_DEVICE_CERT="/path/to/breezsdk/device.crt" # or BASE64/HEXSTRING
|
BREEZ_GREENLIGHT_DEVICE_CERT="/path/to/breezsdk/device.crt" # or BASE64/HEXSTRING
|
||||||
# BREEZ_USE_TRAMPOLINE=true
|
# BREEZ_USE_TRAMPOLINE=true
|
||||||
|
|
||||||
|
# BreezLiquidSdkWallet
|
||||||
|
# get your own api key here https://breez.technology/request-api-key/#contact-us-form-sdk
|
||||||
|
# or keep the api key empty to use the LNbits key for referrals (API key is not a secret)
|
||||||
|
# BREEZ_LIQUID_API_KEY=""
|
||||||
|
BREEZ_LIQUID_SEED="MNEMONIC SEED PHRASE"
|
||||||
|
# BREEZ_LIQUID_FEE_OFFSET_SAT=50
|
||||||
|
|
||||||
# Google OAuth Config
|
# Google OAuth Config
|
||||||
# Make sure that the authorized redirect URIs contain https://{domain}/api/v1/auth/google/token
|
# Make sure that the authorized redirect URIs contain https://{domain}/api/v1/auth/google/token
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,18 @@ A Greenlight invite code or Greenlight partner certificate/key can be used to re
|
||||||
- `BREEZ_GREENLIGHT_DEVICE_KEY`: /path/to/breezsdk/device.pem or Base64/Hex
|
- `BREEZ_GREENLIGHT_DEVICE_KEY`: /path/to/breezsdk/device.pem or Base64/Hex
|
||||||
- `BREEZ_GREENLIGHT_DEVICE_CERT`: /path/to/breezsdk/device.crt or Base64/Hex
|
- `BREEZ_GREENLIGHT_DEVICE_CERT`: /path/to/breezsdk/device.crt or Base64/Hex
|
||||||
|
|
||||||
|
### Breez Liquid SDK
|
||||||
|
|
||||||
|
This funding source leverages the [Breez SDK - Liquid](https://sdk-doc-liquid.breez.technology/) to manage all Lightning payments via submarine swaps on the Liquid network. To get started, simply provide a mnemonic seed phrase. The easiest way to generate one is by using a liquid wallet, such as [Blockstream Green](https://blockstream.com/green/). Once generated, you can copy the seed to your environment variable or enter it in the admin UI.
|
||||||
|
|
||||||
|
- `LNBITS_BACKEND_WALLET_CLASS`: **BreezLiquidSdkWallet**
|
||||||
|
- `BREEZ_LIQUID_SEED`: ...
|
||||||
|
|
||||||
|
Each submarine swap incurs service and on-chain fees. To account for these, you may need to increase the reserve fee in the admin UI by navigating to **Settings -> Funding**, or by setting the following environment variables:
|
||||||
|
|
||||||
|
- `LNBITS_RESERVE_FEE_MIN`: ...
|
||||||
|
- `LNBITS_RESERVE_FEE_PERCENT`: ...
|
||||||
|
|
||||||
### Cliche Wallet
|
### Cliche Wallet
|
||||||
|
|
||||||
- `CLICHE_ENDPOINT`: ws://127.0.0.1:12000
|
- `CLICHE_ENDPOINT`: ws://127.0.0.1:12000
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ async def create_payment(
|
||||||
preimage=data.preimage,
|
preimage=data.preimage,
|
||||||
expiry=data.expiry,
|
expiry=data.expiry,
|
||||||
webhook=data.webhook,
|
webhook=data.webhook,
|
||||||
fee=data.fee,
|
fee=-abs(data.fee),
|
||||||
tag=extra.get("tag", None),
|
tag=extra.get("tag", None),
|
||||||
extra=extra,
|
extra=extra,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -300,6 +300,7 @@ async def create_invoice(
|
||||||
memo=memo,
|
memo=memo,
|
||||||
extra=extra,
|
extra=extra,
|
||||||
webhook=webhook,
|
webhook=webhook,
|
||||||
|
fee=payment_response.fee_msat or 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
payment = await create_payment(
|
payment = await create_payment(
|
||||||
|
|
|
||||||
|
|
@ -305,7 +305,7 @@ class FeeSettings(LNbitsSettings):
|
||||||
return 0
|
return 0
|
||||||
reserve_min = self.lnbits_reserve_fee_min
|
reserve_min = self.lnbits_reserve_fee_min
|
||||||
reserve_percent = self.lnbits_reserve_fee_percent
|
reserve_percent = self.lnbits_reserve_fee_percent
|
||||||
return max(int(reserve_min), int(amount_msat * reserve_percent / 100.0))
|
return max(int(reserve_min), int(abs(amount_msat) * reserve_percent / 100.0))
|
||||||
|
|
||||||
|
|
||||||
class ExchangeProvidersSettings(LNbitsSettings):
|
class ExchangeProvidersSettings(LNbitsSettings):
|
||||||
|
|
@ -549,6 +549,12 @@ class BreezSdkFundingSource(LNbitsSettings):
|
||||||
breez_use_trampoline: bool = Field(default=True)
|
breez_use_trampoline: bool = Field(default=True)
|
||||||
|
|
||||||
|
|
||||||
|
class BreezLiquidSdkFundingSource(LNbitsSettings):
|
||||||
|
breez_liquid_api_key: str | None = Field(default=None)
|
||||||
|
breez_liquid_seed: str | None = Field(default=None)
|
||||||
|
breez_liquid_fee_offset_sat: int = Field(default=50)
|
||||||
|
|
||||||
|
|
||||||
class BoltzFundingSource(LNbitsSettings):
|
class BoltzFundingSource(LNbitsSettings):
|
||||||
boltz_client_endpoint: str | None = Field(default="127.0.0.1:9002")
|
boltz_client_endpoint: str | None = Field(default="127.0.0.1:9002")
|
||||||
boltz_client_macaroon: str | None = Field(default=None)
|
boltz_client_macaroon: str | None = Field(default=None)
|
||||||
|
|
@ -618,6 +624,7 @@ class FundingSourcesSettings(
|
||||||
NWCFundingSource,
|
NWCFundingSource,
|
||||||
BreezSdkFundingSource,
|
BreezSdkFundingSource,
|
||||||
StrikeFundingSource,
|
StrikeFundingSource,
|
||||||
|
BreezLiquidSdkFundingSource,
|
||||||
):
|
):
|
||||||
lnbits_backend_wallet_class: str = Field(default="VoidWallet")
|
lnbits_backend_wallet_class: str = Field(default="VoidWallet")
|
||||||
# How long to wait for the payment to be confirmed before returning a pending status
|
# How long to wait for the payment to be confirmed before returning a pending status
|
||||||
|
|
@ -924,6 +931,7 @@ class SuperUserSettings(LNbitsSettings):
|
||||||
"BoltzWallet",
|
"BoltzWallet",
|
||||||
"BlinkWallet",
|
"BlinkWallet",
|
||||||
"BreezSdkWallet",
|
"BreezSdkWallet",
|
||||||
|
"BreezLiquidSdkWallet",
|
||||||
"CoreLightningRestWallet",
|
"CoreLightningRestWallet",
|
||||||
"CoreLightningWallet",
|
"CoreLightningWallet",
|
||||||
"EclairWallet",
|
"EclairWallet",
|
||||||
|
|
|
||||||
2
lnbits/static/bundle-components.min.js
vendored
2
lnbits/static/bundle-components.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -219,6 +219,16 @@ window.app.component('lnbits-funding-sources', {
|
||||||
strike_api_endpoint: 'API Endpoint',
|
strike_api_endpoint: 'API Endpoint',
|
||||||
strike_api_key: 'API Key'
|
strike_api_key: 'API Key'
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'BreezLiquidSdkWallet',
|
||||||
|
'Breez Liquid SDK',
|
||||||
|
{
|
||||||
|
breez_liquid_api_key: 'Breez API Key (can be empty)',
|
||||||
|
breez_liquid_seed: 'Liquid seed phrase',
|
||||||
|
breez_liquid_fee_offset_sat:
|
||||||
|
'Offset amount in sats to increase fee limit'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
lnbits/wallets/.breez
Normal file
1
lnbits/wallets/.breez
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
MIIBYzCCARWgAwIBAgIHPjlTc1IbAzAFBgMrZXAwEDEOMAwGA1UEAxMFQnJlZXowHhcNMjUwNzAyMDkxODMzWhcNMzUwNjMwMDkxODMzWjAfMQ8wDQYDVQQKEwZsbmJpdHMxDDAKBgNVBAMTA2RuaTAqMAUGAytlcAMhANCD9cvfIDwcoiDKKYdT9BunHLS2/OuKzV8NS0SzqV13o38wfTAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU2jmj7l5rSw0yVb/vlWAYkK/YBwkwHwYDVR0jBBgwFoAU3qrWklbzjed0khb8TLYgsmsomGswHQYDVR0RBBYwFIESb2ZmaWNlQGRuaWxhYnMuY29tMAUGAytlcANBAMGS8jEfZbfNpv6mVrg328NXnjA/nG6TuGA0aAw0NyDz499aeu/0TURjF8FzmxzmdNOiffUZ6akPWCZUKFYuGgA=
|
||||||
|
|
@ -10,6 +10,7 @@ from .alby import AlbyWallet
|
||||||
from .blink import BlinkWallet
|
from .blink import BlinkWallet
|
||||||
from .boltz import BoltzWallet
|
from .boltz import BoltzWallet
|
||||||
from .breez import BreezSdkWallet
|
from .breez import BreezSdkWallet
|
||||||
|
from .breez_liquid import BreezLiquidSdkWallet
|
||||||
from .cliche import ClicheWallet
|
from .cliche import ClicheWallet
|
||||||
from .corelightning import CoreLightningWallet
|
from .corelightning import CoreLightningWallet
|
||||||
|
|
||||||
|
|
@ -57,6 +58,7 @@ __all__ = [
|
||||||
"AlbyWallet",
|
"AlbyWallet",
|
||||||
"BlinkWallet",
|
"BlinkWallet",
|
||||||
"BoltzWallet",
|
"BoltzWallet",
|
||||||
|
"BreezLiquidSdkWallet",
|
||||||
"BreezSdkWallet",
|
"BreezSdkWallet",
|
||||||
"CLightningWallet",
|
"CLightningWallet",
|
||||||
"ClicheWallet",
|
"ClicheWallet",
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ class InvoiceResponse(NamedTuple):
|
||||||
payment_request: str | None = None
|
payment_request: str | None = None
|
||||||
error_message: str | None = None
|
error_message: str | None = None
|
||||||
preimage: str | None = None
|
preimage: str | None = None
|
||||||
|
fee_msat: int | None = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def success(self) -> bool:
|
def success(self) -> bool:
|
||||||
|
|
|
||||||
296
lnbits/wallets/breez_liquid.py
Normal file
296
lnbits/wallets/breez_liquid.py
Normal file
|
|
@ -0,0 +1,296 @@
|
||||||
|
# Based on breez.py
|
||||||
|
|
||||||
|
try:
|
||||||
|
import breez_sdk_liquid as breez_sdk # type: ignore
|
||||||
|
|
||||||
|
BREEZ_SDK_INSTALLED = True
|
||||||
|
except ImportError:
|
||||||
|
BREEZ_SDK_INSTALLED = False
|
||||||
|
|
||||||
|
if not BREEZ_SDK_INSTALLED:
|
||||||
|
|
||||||
|
class BreezLiquidSdkWallet: # pyright: ignore
|
||||||
|
def __init__(self):
|
||||||
|
raise RuntimeError(
|
||||||
|
"Breez Liquid SDK is not installed. "
|
||||||
|
"Ask admin to run `poetry add -E breez` to install it."
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
import asyncio
|
||||||
|
from asyncio import Queue
|
||||||
|
from collections.abc import AsyncGenerator
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import breez_sdk_liquid as breez_sdk # type: ignore
|
||||||
|
from bolt11 import decode as bolt11_decode
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from lnbits.settings import settings
|
||||||
|
|
||||||
|
from .base import (
|
||||||
|
InvoiceResponse,
|
||||||
|
PaymentFailedStatus,
|
||||||
|
PaymentPendingStatus,
|
||||||
|
PaymentResponse,
|
||||||
|
PaymentStatus,
|
||||||
|
PaymentSuccessStatus,
|
||||||
|
StatusResponse,
|
||||||
|
Wallet,
|
||||||
|
)
|
||||||
|
|
||||||
|
breez_incoming_queue: Queue[breez_sdk.PaymentDetails.LIGHTNING] = Queue()
|
||||||
|
breez_outgoing_queue: dict[str, Queue[breez_sdk.PaymentDetails.LIGHTNING]] = {}
|
||||||
|
|
||||||
|
class PaymentsListener(breez_sdk.EventListener):
|
||||||
|
def on_event(self, e: breez_sdk.SdkEvent) -> None:
|
||||||
|
logger.debug(f"received breez sdk event: {e}")
|
||||||
|
# TODO: when this issue is fixed:
|
||||||
|
# https://github.com/breez/breez-sdk-liquid/issues/961
|
||||||
|
# use breez_sdk.SdkEvent.PAYMENT_WAITING_CONFIRMATION
|
||||||
|
if not isinstance(
|
||||||
|
e, breez_sdk.SdkEvent.PAYMENT_SUCCEEDED
|
||||||
|
) or not isinstance(e.details.details, breez_sdk.PaymentDetails.LIGHTNING):
|
||||||
|
return
|
||||||
|
|
||||||
|
payment = e.details
|
||||||
|
payment_details = e.details.details
|
||||||
|
|
||||||
|
if payment.payment_type is breez_sdk.PaymentType.RECEIVE:
|
||||||
|
breez_incoming_queue.put_nowait(payment_details)
|
||||||
|
elif (
|
||||||
|
payment.payment_type is breez_sdk.PaymentType.SEND
|
||||||
|
and payment_details.payment_hash in breez_outgoing_queue
|
||||||
|
):
|
||||||
|
breez_outgoing_queue[payment_details.payment_hash].put_nowait(
|
||||||
|
payment_details
|
||||||
|
)
|
||||||
|
|
||||||
|
class BreezLiquidSdkWallet(Wallet): # type: ignore[no-redef]
|
||||||
|
def __init__(self):
|
||||||
|
if not settings.breez_liquid_seed:
|
||||||
|
raise ValueError(
|
||||||
|
"cannot initialize BreezLiquidSdkWallet: missing breez_liquid_seed"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not settings.breez_liquid_api_key:
|
||||||
|
with open(Path("lnbits/wallets", ".breez")) as f:
|
||||||
|
settings.breez_liquid_api_key = f.read().strip()
|
||||||
|
|
||||||
|
self.config = breez_sdk.default_config(
|
||||||
|
breez_sdk.LiquidNetwork.MAINNET,
|
||||||
|
breez_api_key=settings.breez_liquid_api_key,
|
||||||
|
)
|
||||||
|
|
||||||
|
breez_sdk_working_dir = Path(
|
||||||
|
settings.lnbits_data_folder, "breez-liquid-sdk"
|
||||||
|
)
|
||||||
|
breez_sdk_working_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
self.config.working_dir = breez_sdk_working_dir.absolute().as_posix()
|
||||||
|
|
||||||
|
try:
|
||||||
|
mnemonic = settings.breez_liquid_seed
|
||||||
|
connect_request = breez_sdk.ConnectRequest(
|
||||||
|
config=self.config, mnemonic=mnemonic
|
||||||
|
)
|
||||||
|
self.sdk_services = breez_sdk.connect(connect_request)
|
||||||
|
self.sdk_services.add_event_listener(PaymentsListener())
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning(exc)
|
||||||
|
raise ValueError(
|
||||||
|
f"cannot initialize BreezLiquidSdkWallet: {exc!s}"
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
async def cleanup(self):
|
||||||
|
self.sdk_services.disconnect()
|
||||||
|
|
||||||
|
async def status(self) -> StatusResponse:
|
||||||
|
try:
|
||||||
|
info: breez_sdk.GetInfoResponse = self.sdk_services.get_info()
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning(exc)
|
||||||
|
return StatusResponse(f"Failed to connect to breez, got: '{exc}...'", 0)
|
||||||
|
return StatusResponse(None, int(info.wallet_info.balance_sat * 1000))
|
||||||
|
|
||||||
|
async def create_invoice(
|
||||||
|
self,
|
||||||
|
amount: int,
|
||||||
|
memo: Optional[str] = None,
|
||||||
|
description_hash: Optional[bytes] = None,
|
||||||
|
unhashed_description: Optional[bytes] = None,
|
||||||
|
**_,
|
||||||
|
) -> InvoiceResponse:
|
||||||
|
try:
|
||||||
|
# issue with breez sdk, receive_amount is of type BITCOIN
|
||||||
|
# not ReceiveAmount after initialisation
|
||||||
|
receive_amount = breez_sdk.ReceiveAmount.BITCOIN(amount)
|
||||||
|
req = self.sdk_services.prepare_receive_payment(
|
||||||
|
breez_sdk.PrepareReceiveRequest(
|
||||||
|
payment_method=breez_sdk.PaymentMethod.BOLT11_INVOICE,
|
||||||
|
amount=receive_amount, # type: ignore
|
||||||
|
)
|
||||||
|
)
|
||||||
|
receive_fees_sats = req.fees_sat
|
||||||
|
|
||||||
|
description = memo or (
|
||||||
|
unhashed_description.decode() if unhashed_description else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
res = self.sdk_services.receive_payment(
|
||||||
|
breez_sdk.ReceivePaymentRequest(
|
||||||
|
prepare_response=req,
|
||||||
|
description=description,
|
||||||
|
use_description_hash=description_hash is not None,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
bolt11 = res.destination
|
||||||
|
invoice_data = bolt11_decode(bolt11)
|
||||||
|
payment_hash = invoice_data.payment_hash
|
||||||
|
|
||||||
|
return InvoiceResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=payment_hash,
|
||||||
|
payment_request=bolt11,
|
||||||
|
fee_msat=receive_fees_sats * 1000,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(e)
|
||||||
|
return InvoiceResponse(ok=False, error_message=str(e))
|
||||||
|
|
||||||
|
async def pay_invoice(
|
||||||
|
self, bolt11: str, fee_limit_msat: int
|
||||||
|
) -> PaymentResponse:
|
||||||
|
invoice_data = bolt11_decode(bolt11)
|
||||||
|
|
||||||
|
try:
|
||||||
|
prepare_req = breez_sdk.PrepareSendRequest(destination=bolt11)
|
||||||
|
req = self.sdk_services.prepare_send_payment(prepare_req)
|
||||||
|
|
||||||
|
fee_limit_sat = settings.breez_liquid_fee_offset_sat + int(
|
||||||
|
fee_limit_msat / 1000
|
||||||
|
)
|
||||||
|
|
||||||
|
if req.fees_sat and req.fees_sat > fee_limit_sat:
|
||||||
|
return PaymentResponse(
|
||||||
|
ok=False,
|
||||||
|
error_message=(
|
||||||
|
f"fee of {req.fees_sat} sat exceeds limit of "
|
||||||
|
f"{fee_limit_sat} sat"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
send_response = self.sdk_services.send_payment(
|
||||||
|
breez_sdk.SendPaymentRequest(prepare_response=req)
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning(exc)
|
||||||
|
return PaymentResponse(error_message=f"Exception while payment: {exc}")
|
||||||
|
|
||||||
|
payment: breez_sdk.Payment = send_response.payment
|
||||||
|
logger.debug(f"pay invoice res: {payment}")
|
||||||
|
checking_id = invoice_data.payment_hash
|
||||||
|
|
||||||
|
fees = req.fees_sat * 1000 if req.fees_sat and req.fees_sat > 0 else 0
|
||||||
|
|
||||||
|
if payment.status != breez_sdk.PaymentState.COMPLETE:
|
||||||
|
return await self._wait_for_outgoing_payment(checking_id, fees, 5)
|
||||||
|
|
||||||
|
if not isinstance(payment.details, breez_sdk.PaymentDetails.LIGHTNING):
|
||||||
|
return PaymentResponse(
|
||||||
|
error_message="lightning payment details are not available"
|
||||||
|
)
|
||||||
|
|
||||||
|
return PaymentResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=checking_id,
|
||||||
|
fee_msat=payment.fees_sat * 1000,
|
||||||
|
preimage=payment.details.preimage,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
try:
|
||||||
|
req = breez_sdk.GetPaymentRequest.PAYMENT_HASH(checking_id)
|
||||||
|
payment = self.sdk_services.get_payment(req=req) # type: ignore
|
||||||
|
if payment is None:
|
||||||
|
return PaymentPendingStatus()
|
||||||
|
if payment.payment_type != breez_sdk.PaymentType.RECEIVE:
|
||||||
|
logger.warning(f"unexpected payment type: {payment.status}")
|
||||||
|
return PaymentPendingStatus()
|
||||||
|
if payment.status == breez_sdk.PaymentState.FAILED:
|
||||||
|
return PaymentFailedStatus()
|
||||||
|
if payment.status == breez_sdk.PaymentState.COMPLETE:
|
||||||
|
return PaymentSuccessStatus(
|
||||||
|
paid=True, fee_msat=int(payment.fees_sat * 1000)
|
||||||
|
)
|
||||||
|
return PaymentPendingStatus()
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning(exc)
|
||||||
|
return PaymentPendingStatus()
|
||||||
|
|
||||||
|
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
|
||||||
|
try:
|
||||||
|
req = breez_sdk.GetPaymentRequest.PAYMENT_HASH(checking_id)
|
||||||
|
payment = self.sdk_services.get_payment(req=req) # type: ignore
|
||||||
|
if payment is None:
|
||||||
|
return PaymentPendingStatus()
|
||||||
|
if payment.payment_type != breez_sdk.PaymentType.SEND:
|
||||||
|
logger.warning(f"unexpected payment type: {payment.status}")
|
||||||
|
return PaymentPendingStatus()
|
||||||
|
if payment.status == breez_sdk.PaymentState.COMPLETE:
|
||||||
|
if not isinstance(
|
||||||
|
payment.details, breez_sdk.PaymentDetails.LIGHTNING
|
||||||
|
):
|
||||||
|
logger.warning("payment details are not of type LIGHTNING")
|
||||||
|
return PaymentPendingStatus()
|
||||||
|
return PaymentSuccessStatus(
|
||||||
|
fee_msat=int(payment.fees_sat * 1000),
|
||||||
|
preimage=payment.details.preimage,
|
||||||
|
)
|
||||||
|
if payment.status == breez_sdk.PaymentState.FAILED:
|
||||||
|
return PaymentFailedStatus()
|
||||||
|
return PaymentPendingStatus()
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning(exc)
|
||||||
|
return PaymentPendingStatus()
|
||||||
|
|
||||||
|
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
||||||
|
while settings.lnbits_running:
|
||||||
|
details = await breez_incoming_queue.get()
|
||||||
|
logger.debug(f"breez invoice paid event: {details}")
|
||||||
|
if not details.invoice:
|
||||||
|
logger.warning(
|
||||||
|
"Paid invoices stream expected bolt11 invoice, got None"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
invoice_data = bolt11_decode(details.invoice)
|
||||||
|
yield invoice_data.payment_hash
|
||||||
|
|
||||||
|
async def _wait_for_outgoing_payment(
|
||||||
|
self, checking_id: str, fees: int, timeout: int
|
||||||
|
) -> PaymentResponse:
|
||||||
|
try:
|
||||||
|
breez_outgoing_queue[checking_id] = Queue()
|
||||||
|
payment_details = await asyncio.wait_for(
|
||||||
|
breez_outgoing_queue[checking_id].get(), timeout
|
||||||
|
)
|
||||||
|
return PaymentResponse(
|
||||||
|
ok=True,
|
||||||
|
preimage=payment_details.preimage,
|
||||||
|
checking_id=checking_id,
|
||||||
|
fee_msat=fees,
|
||||||
|
)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
logger.debug(
|
||||||
|
f"payment '{checking_id}' is still pending after {timeout} seconds"
|
||||||
|
)
|
||||||
|
return PaymentResponse(
|
||||||
|
checking_id=checking_id,
|
||||||
|
fee_msat=fees,
|
||||||
|
error_message="payment is pending",
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
breez_outgoing_queue.pop(checking_id, None)
|
||||||
45
poetry.lock
generated
45
poetry.lock
generated
|
|
@ -656,6 +656,47 @@ files = [
|
||||||
{file = "breez_sdk-0.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:e51689ed2f2c2d49bdb53f0ee26d0dc2109a50f15b8f2129a250db275eb994bf"},
|
{file = "breez_sdk-0.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:e51689ed2f2c2d49bdb53f0ee26d0dc2109a50f15b8f2129a250db275eb994bf"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "breez-sdk-liquid"
|
||||||
|
version = "0.9.1"
|
||||||
|
description = "Python language bindings for the Breez Liquid SDK"
|
||||||
|
optional = true
|
||||||
|
python-versions = "*"
|
||||||
|
groups = ["main"]
|
||||||
|
markers = "extra == \"breez\""
|
||||||
|
files = [
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:414a7c04dbf869435fe234b3b9987699c15dc2f8d4660d9ca1a51af608331b45"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp310-cp310-manylinux_2_31_aarch64.whl", hash = "sha256:7f461b6b10ddfe9cfb58119e590e5f67da4d7c93fc580a84a0116ce9fd21dffa"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:c27efe35539e4092dddbe5315f5cefffccbdd699017ed8733611d11eb52f4ce0"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp310-cp310-win32.whl", hash = "sha256:375f6322c2552d15d6ba68302a85fdc345a7671eeda8fea92c013a16c5e96505"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:f28d107099fb7caaac4051d5950a4f11bf823e11b56e797976c5fa2a7280d597"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:acefa49896bdb4ca06d351faacbf075646d574dda5539033df11310ec5a94446"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp311-cp311-manylinux_2_31_aarch64.whl", hash = "sha256:d0e54fd5c8ce542dc2061d8a1ef46e6a1d430dbaea5eab369bb91ae2c4a1be7b"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp311-cp311-manylinux_2_31_x86_64.whl", hash = "sha256:a5d1bfd4d3286d57c110d925332416b0903dda076dadede02c4b7db67576f0bf"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp311-cp311-win32.whl", hash = "sha256:3ce2152f0a2ba65f4425fd22efb8e1dafb419e5fcf3b93dfe06fc061b1d1c0c6"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:8cdb4f247bccc0f4b9bbfff4451faa78d7b17e76a9dc918804880b600f1d4249"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:c463191a89a829afcae19c94f7683dac415667755d68c212afc60d8f2b21ba63"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp312-cp312-manylinux_2_31_aarch64.whl", hash = "sha256:52efaeae2c278b498b37de1090e80f73987ee943743e69a363877ed93cd7a31e"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp312-cp312-manylinux_2_31_x86_64.whl", hash = "sha256:68aebea98990319c677bcbd7d1de258627b85063a29720879986694b9d393adb"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp312-cp312-win32.whl", hash = "sha256:f53e4a1973dfd41df3ac3ecb42cf72acb71f49d5727a8acab25668b51a953bb2"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:6adb1f3f3ccd4b743a11dcc0b307db604c3424f42e2547f94fa939f0afb9bb85"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:f94432a75bc848e597fb9859a77bab6c703d5e423d470519f37c402fc3c5d79e"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp313-cp313-manylinux_2_31_aarch64.whl", hash = "sha256:8d6838e69620162c038d513f95ffade870e112ae5c6a0d713eaa2a3a31d6f212"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp313-cp313-manylinux_2_31_x86_64.whl", hash = "sha256:d6b9a8601cef5875447e10c75ca3e1579dd1e881ec57cabe9787616b8a6de263"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp313-cp313-win32.whl", hash = "sha256:d76fc905003ac5a0cfd2132df90ba6343b40b9948164a0be06a68f15b28789a2"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:d6b0fc1d77b7855d9a72799d65cdaaa0bd07a3999d6d4d27050d8ef174ce0fd3"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d0d560657c29d7e3b054ad4be07955fc41b63d4b93a2b51b29bb85d1d52341af"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp38-cp38-manylinux_2_31_aarch64.whl", hash = "sha256:2531f788eb15bb00f4b3b505ac5b8ee3de23161dd4f65768a4aa3255ea04d68e"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp38-cp38-manylinux_2_31_x86_64.whl", hash = "sha256:f9c9f6255999cf403bc07a9deed99f8c1625a0405ae9231e3dbecb3b6af0fdc7"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp38-cp38-win32.whl", hash = "sha256:5232b25b7e8583100ec54423e7568a305cac7778736adc9f8c735798110350c7"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:67d2b894b70ba9011fc98e04ed1ade2ff18f0413b6f2a0994747e71418d004e4"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:bd77d2ce43a2c0ad77a7f22226e373034ff57677338b38e4ebe3b77eb34fa224"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp39-cp39-manylinux_2_31_aarch64.whl", hash = "sha256:14092d9d65f1b0a9009e64630614e7b8b936e9d382d0f6415f023f0b192f6b45"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp39-cp39-manylinux_2_31_x86_64.whl", hash = "sha256:5faa4d5e9a2b47899783aa0c44ac2274d32f74a7f469506af14520deabaabf9f"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp39-cp39-win32.whl", hash = "sha256:b5b2c4bae13655d108475f4f22efdc2b07283f72d99b9c6f99166d9e41e62942"},
|
||||||
|
{file = "breez_sdk_liquid-0.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:f3ad7c65582558031451538c8a03caa3486a2d2c8906f2fbbccce84e9357d1ea"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2025.6.15"
|
version = "2025.6.15"
|
||||||
|
|
@ -4373,10 +4414,10 @@ multidict = ">=4.0"
|
||||||
propcache = ">=0.2.1"
|
propcache = ">=0.2.1"
|
||||||
|
|
||||||
[extras]
|
[extras]
|
||||||
breez = ["breez-sdk"]
|
breez = ["breez-sdk", "breez-sdk-liquid"]
|
||||||
liquid = ["wallycore"]
|
liquid = ["wallycore"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.1"
|
lock-version = "2.1"
|
||||||
python-versions = "~3.12 | ~3.11 | ~3.10"
|
python-versions = "~3.12 | ~3.11 | ~3.10"
|
||||||
content-hash = "434e37e5aeb0eeb1a22e12fd1914b45f27195162ef4ebc1055071fd4718d85fc"
|
content-hash = "53f582a8079540033939ccd1bbd93b8ec1e8190ee26be0c0b8d64d57edb5cdac"
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ python-crontab = "3.2.0"
|
||||||
wallycore = {version = "1.4.0", optional = true}
|
wallycore = {version = "1.4.0", optional = true}
|
||||||
# needed for breez funding source
|
# needed for breez funding source
|
||||||
breez-sdk = {version = "0.8.0", optional = true}
|
breez-sdk = {version = "0.8.0", optional = true}
|
||||||
|
breez-sdk-liquid = {version = "0.9.1", optional = true}
|
||||||
|
|
||||||
jsonpath-ng = "^1.7.0"
|
jsonpath-ng = "^1.7.0"
|
||||||
pynostr = "^0.6.2"
|
pynostr = "^0.6.2"
|
||||||
|
|
@ -65,7 +66,7 @@ filetype = "^1.2.0"
|
||||||
nostr-sdk = "^0.42.1"
|
nostr-sdk = "^0.42.1"
|
||||||
|
|
||||||
[tool.poetry.extras]
|
[tool.poetry.extras]
|
||||||
breez = ["breez-sdk"]
|
breez = ["breez-sdk", "breez-sdk-liquid"]
|
||||||
liquid = ["wallycore"]
|
liquid = ["wallycore"]
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue