creating nodeless lib

This commit is contained in:
2025-05-03 17:11:42 +02:00
parent 891427d227
commit 0d239b26f5
4 changed files with 326 additions and 242 deletions

View File

@@ -10,6 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
python3 \ python3 \
python3-venv \ python3-venv \
python3-pip \ python3-pip \
python3-full \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
@@ -17,24 +18,24 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1 && \ RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1 && \
update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1 update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1
# Install Poetry # Create a virtual environment
RUN pip install poetry --break-system-packages RUN python3 -m venv /app/venv
# Install Poetry in the virtual environment
RUN /app/venv/bin/pip install poetry
# Copy project files # Copy project files
COPY pyproject.toml . COPY fly/pyproject.toml .
COPY main.py . COPY fly/main.py .
COPY nodeless.py .
# Copy environment file template
COPY fly/.env.example .env
# Create a README.md file if it doesn't exist to satisfy Poetry # Create a README.md file if it doesn't exist to satisfy Poetry
RUN touch README.md RUN touch README.md
# Copy environment file template # Install dependencies using the virtual environment's pip
COPY .env.example .env RUN /app/venv/bin/poetry install --no-interaction --no-ansi --no-root
# Configure Poetry to not create a virtual environment
RUN poetry config virtualenvs.create false
# Install dependencies without installing the project itself
RUN poetry install --no-interaction --no-ansi --no-root
# Create tmp directory for Breez SDK # Create tmp directory for Breez SDK
RUN mkdir -p ./tmp RUN mkdir -p ./tmp
@@ -44,6 +45,7 @@ EXPOSE 8000
# Set environment variables # Set environment variables
ENV PYTHONUNBUFFERED=1 ENV PYTHONUNBUFFERED=1
ENV PATH="/app/venv/bin:$PATH"
# Run the application # Run the application (now using the venv's Python)
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] CMD ["/app/venv/bin/uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@@ -46,21 +46,15 @@ class BreezClient:
) )
return self._handle_response(response) return self._handle_response(response)
def receive_payment(self, amount, method="LIGHTNING"): def receive_payment(self, amount, method="LIGHTNING", description=None, asset_id=None):
"""
Generate a Lightning/Bitcoin/Liquid invoice to receive payment.
Args:
amount (int): Amount in satoshis to receive
method (str, optional): Payment method (LIGHTNING or LIQUID)
Returns:
dict: JSON response with invoice details
"""
payload = { payload = {
"amount": amount, "amount": amount,
"method": method "method": method
} }
if description is not None:
payload["description"] = description
if asset_id is not None:
payload["asset_id"] = asset_id
response = requests.post( response = requests.post(
f"{self.api_url}/receive_payment", f"{self.api_url}/receive_payment",
json=payload, json=payload,
@@ -68,26 +62,17 @@ class BreezClient:
) )
return self._handle_response(response) return self._handle_response(response)
def send_payment(self, destination, amount=None, drain=False): def send_payment(self, destination, amount_sat=None, amount_asset=None, asset_id=None, drain=False):
"""
Send a payment via Lightning or Liquid.
Args:
destination (str): Payment destination (invoice or address)
amount (int, optional): Amount in satoshis to send
drain (bool, optional): Whether to drain the wallet
Returns:
dict: JSON response with payment details
"""
payload = { payload = {
"destination": destination "destination": destination,
"drain": drain
} }
if amount is not None: if amount_sat is not None:
payload["amount"] = amount payload["amount_sat"] = amount_sat
if drain: if amount_asset is not None:
payload["drain"] = True payload["amount_asset"] = amount_asset
if asset_id is not None:
payload["asset_id"] = asset_id
response = requests.post( response = requests.post(
f"{self.api_url}/send_payment", f"{self.api_url}/send_payment",
json=payload, json=payload,
@@ -105,6 +90,86 @@ class BreezClient:
response = requests.get(f"{self.api_url}/health") response = requests.get(f"{self.api_url}/health")
return self._handle_response(response) return self._handle_response(response)
def send_onchain(self, address, amount_sat=None, drain=False, fee_rate_sat_per_vbyte=None):
"""
Send an onchain (Bitcoin or Liquid) payment.
Args:
address (str): Destination address
amount_sat (int, optional): Amount in satoshis
drain (bool, optional): Drain all funds
fee_rate_sat_per_vbyte (int, optional): Custom fee rate
Returns:
dict: JSON response
"""
payload = {
"address": address,
"drain": drain
}
if amount_sat is not None:
payload["amount_sat"] = amount_sat
if fee_rate_sat_per_vbyte is not None:
payload["fee_rate_sat_per_vbyte"] = fee_rate_sat_per_vbyte
response = requests.post(
f"{self.api_url}/send_onchain",
json=payload,
headers=self.headers
)
return self._handle_response(response)
# LNURL-related endpoints (all under /v1/ln/)
def parse_input(self, input_str):
response = requests.post(
f"{self.api_url}/v1/ln/parse_input",
json={"input": input_str},
headers=self.headers
)
return self._handle_response(response)
def prepare_lnurl_pay(self, data, amount_sat, comment=None, validate_success_action_url=True):
payload = {
"data": data,
"amount_sat": amount_sat,
"comment": comment,
"validate_success_action_url": validate_success_action_url
}
response = requests.post(
f"{self.api_url}/v1/ln/prepare_lnurl_pay",
json=payload,
headers=self.headers
)
return self._handle_response(response)
def lnurl_pay(self, prepare_response):
payload = {"prepare_response": prepare_response}
response = requests.post(
f"{self.api_url}/v1/ln/lnurl_pay",
json=payload,
headers=self.headers
)
return self._handle_response(response)
def lnurl_auth(self, data):
payload = {"data": data}
response = requests.post(
f"{self.api_url}/v1/ln/lnurl_auth",
json=payload,
headers=self.headers
)
return self._handle_response(response)
def lnurl_withdraw(self, data, amount_msat, comment=None):
payload = {
"data": data,
"amount_msat": amount_msat,
"comment": comment
}
response = requests.post(
f"{self.api_url}/v1/ln/lnurl_withdraw",
json=payload,
headers=self.headers
)
return self._handle_response(response)
def _handle_response(self, response): def _handle_response(self, response):
"""Helper method to handle API responses.""" """Helper method to handle API responses."""
try: try:
@@ -123,7 +188,7 @@ class BreezClient:
if __name__ == "__main__": if __name__ == "__main__":
# Configuration # Configuration
API_URL = "http://localhost:8000" # Change to your deployed API URL API_URL = "http://localhost:8000" # Change to your deployed API URL
API_KEY = "" # Set your API key here API_KEY = "kurac" # Set your API key here
# Initialize client # Initialize client
breez = BreezClient(api_url=API_URL, api_key=API_KEY) breez = BreezClient(api_url=API_URL, api_key=API_KEY)
@@ -136,13 +201,28 @@ if __name__ == "__main__":
print("\n🔄 Listing Payments...") print("\n🔄 Listing Payments...")
print(json.dumps(breez.list_payments(), indent=2)) print(json.dumps(breez.list_payments(), indent=2))
# Generate an invoice to receive payment # LNURL Example Usage
#print("\n💰 Generating invoice to receive payment...") # lnurl = "lnurl1dp68gurn8ghj7mrww4exctnrdakj7mrww4exctnrdakj7mrww4exctnrdakj7" # Replace with a real LNURL
#invoice = breez.receive_payment(amount=1000, method="LIGHTNING") # print("\n🔎 Parsing LNURL...")
#print(json.dumps(invoice, indent=2)) # parsed = breez.parse_input(lnurl)
#print(f"Invoice: {invoice.get('destination', 'Error generating invoice')}") # print(json.dumps(parsed, indent=2))
# if parsed.get("type") == "LN_URL_PAY":
# print("\n📝 Preparing LNURL-Pay...")
# prepare = breez.prepare_lnurl_pay(parsed["data"], amount_sat=1000)
# print(json.dumps(prepare, indent=2))
# print("\n🚀 Executing LNURL-Pay...")
# result = breez.lnurl_pay(prepare)
# print(json.dumps(result, indent=2))
# elif parsed.get("type") == "LN_URL_AUTH":
# print("\n🔐 Executing LNURL-Auth...")
# result = breez.lnurl_auth(parsed["data"])
# print(json.dumps(result, indent=2))
# elif parsed.get("type") == "LN_URL_WITHDRAW":
# print("\n💸 Executing LNURL-Withdraw...")
# result = breez.lnurl_withdraw(parsed["data"], amount_msat=1000_000)
# print(json.dumps(result, indent=2))
# Send payment example (commented out for safety) # Onchain payment example (commented out for safety)
#print("\n🚀 Sending Payment...") # print("\n⛓️ Sending Onchain Payment...")
#result = breez.send_payment(destination="", amount=1111) # result = breez.send_onchain(address="bitcoin_address_here", amount_sat=10000)
#print(json.dumps(result, indent=2)) # print(json.dumps(result, indent=2))

View File

@@ -1,73 +1,53 @@
from fastapi import FastAPI, Depends, HTTPException, Header, Query from fastapi import FastAPI, Depends, HTTPException, Header, Query, APIRouter
from fastapi.security.api_key import APIKeyHeader from fastapi.security.api_key import APIKeyHeader
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from typing import Optional, Dict, List, Any, Union from typing import Optional, Dict, List, Any, Union
import os import os
import json
from dotenv import load_dotenv from dotenv import load_dotenv
from enum import Enum from enum import Enum
from breez_sdk_liquid import ( from nodeless import PaymentHandler
LiquidNetwork,
PayAmount,
ConnectRequest,
PrepareSendRequest,
SendPaymentRequest,
PrepareReceiveRequest,
ReceivePaymentRequest,
EventListener,
SdkEvent,
connect,
default_config,
PaymentMethod,
ListPaymentsRequest,
ReceiveAmount
)
# Load environment variables # Load environment variables
load_dotenv() load_dotenv()
# Create FastAPI app
app = FastAPI( app = FastAPI(
title="Breez Nodeless Payments API", title="Breez Nodeless Payments API",
description="A FastAPI implementation of Breez SDK for Lightning/Liquid payments", description="A FastAPI implementation of Breez SDK for Lightning/Liquid payments",
version="1.0.0" version="1.0.0"
) )
# API Key authentication
API_KEY_NAME = "x-api-key" API_KEY_NAME = "x-api-key"
api_key_header = APIKeyHeader(name=API_KEY_NAME, auto_error=False) api_key_header = APIKeyHeader(name=API_KEY_NAME, auto_error=False)
# Configure API key from environment variable
API_KEY = os.getenv("API_SECRET") API_KEY = os.getenv("API_SECRET")
BREEZ_API_KEY = os.getenv("BREEZ_API_KEY")
SEED_PHRASE = os.getenv("SEED_PHRASE")
# Models for request/response from fastapi import APIRouter
ln_router = APIRouter(prefix="/v1/lnurl", tags=["lnurl"])
# --- Models ---
class PaymentMethodEnum(str, Enum): class PaymentMethodEnum(str, Enum):
LIGHTNING = "LIGHTNING" LIGHTNING = "LIGHTNING"
LIQUID = "LIQUID" BITCOIN_ADDRESS = "BITCOIN_ADDRESS"
LIQUID_ADDRESS = "LIQUID_ADDRESS"
class ReceivePaymentBody(BaseModel): class ReceivePaymentBody(BaseModel):
amount: int = Field(..., description="Amount in satoshis to receive") amount: int = Field(..., description="Amount in satoshis to receive")
method: PaymentMethodEnum = Field(PaymentMethodEnum.LIGHTNING, description="Payment method") method: PaymentMethodEnum = Field(PaymentMethodEnum.LIGHTNING, description="Payment method")
description: Optional[str] = Field(None, description="Optional description for invoice")
asset_id: Optional[str] = Field(None, description="Asset ID for Liquid asset (optional)")
class SendPaymentBody(BaseModel): class SendPaymentBody(BaseModel):
destination: str = Field(..., description="Payment destination (invoice or address)") destination: str = Field(..., description="Payment destination (invoice or address)")
amount: Optional[int] = Field(None, description="Amount in satoshis to send") amount_sat: Optional[int] = Field(None, description="Amount in satoshis to send (for Bitcoin)")
amount_asset: Optional[float] = Field(None, description="Amount to send (for asset payments)")
asset_id: Optional[str] = Field(None, description="Asset ID for Liquid asset (optional)")
drain: bool = Field(False, description="Whether to drain the wallet") drain: bool = Field(False, description="Whether to drain the wallet")
class ListPaymentsParams: class SendOnchainBody(BaseModel):
def __init__( address: str = Field(..., description="Destination Bitcoin or Liquid address")
self, amount_sat: Optional[int] = Field(None, description="Amount in satoshis to send (ignored if drain)")
from_timestamp: Optional[int] = Query(None, description="Filter payments from this timestamp"), drain: bool = Field(False, description="Send all funds")
to_timestamp: Optional[int] = Query(None, description="Filter payments to this timestamp"), fee_rate_sat_per_vbyte: Optional[int] = Field(None, description="Custom fee rate (optional)")
offset: Optional[int] = Query(None, description="Pagination offset"),
limit: Optional[int] = Query(None, description="Pagination limit")
):
self.from_timestamp = from_timestamp
self.to_timestamp = to_timestamp
self.offset = offset
self.limit = limit
class PaymentResponse(BaseModel): class PaymentResponse(BaseModel):
timestamp: int timestamp: int
@@ -75,9 +55,11 @@ class PaymentResponse(BaseModel):
fees_sat: int fees_sat: int
payment_type: str payment_type: str
status: str status: str
details: str details: Any
destination: str destination: Optional[str] = None
tx_id: Optional[str] = None tx_id: Optional[str] = None
payment_hash: Optional[str] = None
swap_id: Optional[str] = None
class PaymentListResponse(BaseModel): class PaymentListResponse(BaseModel):
payments: List[PaymentResponse] payments: List[PaymentResponse]
@@ -87,139 +69,42 @@ class ReceiveResponse(BaseModel):
fees_sat: int fees_sat: int
class SendResponse(BaseModel): class SendResponse(BaseModel):
payment_status: str status: str
destination: str destination: Optional[str] = None
fees_sat: int fees_sat: Optional[int] = None
payment_hash: Optional[str] = None
swap_id: Optional[str] = None
# Breez SDK Event Listener class SendOnchainResponse(BaseModel):
class SdkListener(EventListener): status: str
def __init__(self): address: str
self.synced = False fees_sat: Optional[int] = None
self.paid = []
def on_event(self, event): # LNURL Models
if isinstance(event, SdkEvent.SYNCED): class ParseInputBody(BaseModel):
self.synced = True input: str
if isinstance(event, SdkEvent.PAYMENT_SUCCEEDED):
if event.details.destination:
self.paid.append(event.details.destination)
def is_paid(self, destination: str): class PrepareLnurlPayBody(BaseModel):
return destination in self.paid data: Dict[str, Any] # The .data dict from parse_input
amount_sat: int
comment: Optional[str] = None
validate_success_action_url: Optional[bool] = True
# Initialize Breez SDK client class LnurlPayBody(BaseModel):
class BreezClient: prepare_response: Dict[str, Any] # The dict from prepare_lnurl_pay
_instance = None
def __new__(cls): class LnurlAuthBody(BaseModel):
if cls._instance is None: data: Dict[str, Any] # The .data dict from parse_input
cls._instance = super(BreezClient, cls).__new__(cls)
cls._instance.initialize()
return cls._instance
def initialize(self): class LnurlWithdrawBody(BaseModel):
if not BREEZ_API_KEY: data: Dict[str, Any] # The .data dict from parse_input
raise Exception("Missing Breez API key in environment variables") amount_msat: int
if not SEED_PHRASE: comment: Optional[str] = None
raise Exception("Missing seed phrase in environment variables")
config = default_config(LiquidNetwork.MAINNET, BREEZ_API_KEY) # --- Dependencies ---
config.working_dir = './tmp'
connect_request = ConnectRequest(config=config, mnemonic=SEED_PHRASE)
self.instance = connect(connect_request)
self.listener = SdkListener()
self.instance.add_event_listener(self.listener)
self.is_initialized = True
def wait_for_sync(self, timeout_seconds: int = 30):
"""Wait for the SDK to sync before proceeding."""
import time
start_time = time.time()
while time.time() - start_time < timeout_seconds:
if self.listener.synced:
return True
time.sleep(1)
raise Exception("Sync timeout: SDK did not sync within the allocated time.")
def list_payments(self, params: ListPaymentsParams) -> List[Dict[str, Any]]:
self.wait_for_sync()
req = ListPaymentsRequest(
from_timestamp=params.from_timestamp,
to_timestamp=params.to_timestamp,
offset=params.offset,
limit=params.limit
)
payments = self.instance.list_payments(req)
payment_list = []
for payment in payments:
payment_dict = {
'timestamp': payment.timestamp,
'amount_sat': payment.amount_sat,
'fees_sat': payment.fees_sat,
'payment_type': str(payment.payment_type),
'status': str(payment.status),
'details': str(payment.details),
'destination': payment.destination,
'tx_id': payment.tx_id
}
payment_list.append(payment_dict)
return payment_list
def receive_payment(self, amount: int, payment_method: str = 'LIGHTNING') -> Dict[str, Any]:
try:
self.wait_for_sync()
except Exception as e:
raise Exception(f"Error during SDK sync: {e}")
try:
if isinstance(amount, int):
receive_amount = ReceiveAmount.BITCOIN(amount)
else:
receive_amount = amount
prepare_req = PrepareReceiveRequest(payment_method=getattr(PaymentMethod, payment_method), amount=receive_amount)
except Exception as e:
raise Exception(f"Error preparing receive request: {e}")
try:
prepare_res = self.instance.prepare_receive_payment(prepare_req)
except Exception as e:
raise Exception(f"Error preparing receive payment: {e}")
try:
req = ReceivePaymentRequest(prepare_response=prepare_res)
res = self.instance.receive_payment(req)
except Exception as e:
raise Exception(f"Error receiving payment: {e}")
return {
'destination': res.destination,
'fees_sat': prepare_res.fees_sat
}
def send_payment(self, destination: str, amount: Optional[int] = None, drain: bool = False) -> Dict[str, Any]:
self.wait_for_sync()
pay_amount = PayAmount.DRAIN if drain else PayAmount.BITCOIN(amount) if amount else None
prepare_req = PrepareSendRequest(destination=destination, amount=pay_amount)
prepare_res = self.instance.prepare_send_payment(prepare_req)
req = SendPaymentRequest(prepare_response=prepare_res)
res = self.instance.send_payment(req)
return {
'payment_status': 'success',
'destination': res.payment.destination,
'fees_sat': prepare_res.fees_sat
}
# Dependency for API key validation
async def get_api_key(api_key: str = Header(None, alias=API_KEY_NAME)): async def get_api_key(api_key: str = Header(None, alias=API_KEY_NAME)):
if not API_KEY: if not API_KEY:
raise HTTPException(status_code=500, detail="API key not configured on server") raise HTTPException(status_code=500, detail="API key not configured on server")
if api_key != API_KEY: if api_key != API_KEY:
raise HTTPException( raise HTTPException(
status_code=401, status_code=401,
@@ -228,22 +113,30 @@ async def get_api_key(api_key: str = Header(None, alias=API_KEY_NAME)):
) )
return api_key return api_key
# Dependency for Breez client def get_payment_handler():
def get_breez_client():
try: try:
return BreezClient() return PaymentHandler()
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to initialize Breez client: {str(e)}") raise HTTPException(status_code=500, detail=f"Failed to initialize PaymentHandler: {str(e)}")
# API Routes # --- API Endpoints ---
@app.get("/list_payments", response_model=PaymentListResponse) @app.get("/list_payments", response_model=PaymentListResponse)
async def list_payments( async def list_payments(
params: ListPaymentsParams = Depends(), from_timestamp: Optional[int] = Query(None),
to_timestamp: Optional[int] = Query(None),
offset: Optional[int] = Query(None),
limit: Optional[int] = Query(None),
api_key: str = Depends(get_api_key), api_key: str = Depends(get_api_key),
client: BreezClient = Depends(get_breez_client) handler: PaymentHandler = Depends(get_payment_handler)
): ):
try: try:
payments = client.list_payments(params) params = {
"from_timestamp": from_timestamp,
"to_timestamp": to_timestamp,
"offset": offset,
"limit": limit
}
payments = handler.list_payments(params)
return {"payments": payments} return {"payments": payments}
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@@ -252,12 +145,14 @@ async def list_payments(
async def receive_payment( async def receive_payment(
request: ReceivePaymentBody, request: ReceivePaymentBody,
api_key: str = Depends(get_api_key), api_key: str = Depends(get_api_key),
client: BreezClient = Depends(get_breez_client) handler: PaymentHandler = Depends(get_payment_handler)
): ):
try: try:
result = client.receive_payment( result = handler.receive_payment(
amount=request.amount, amount=request.amount,
payment_method=request.method payment_method=request.method.value,
description=request.description,
asset_id=request.asset_id
) )
return result return result
except Exception as e: except Exception as e:
@@ -267,23 +162,130 @@ async def receive_payment(
async def send_payment( async def send_payment(
request: SendPaymentBody, request: SendPaymentBody,
api_key: str = Depends(get_api_key), api_key: str = Depends(get_api_key),
client: BreezClient = Depends(get_breez_client) handler: PaymentHandler = Depends(get_payment_handler)
): ):
try: try:
result = client.send_payment( result = handler.send_payment(
destination=request.destination, destination=request.destination,
amount=request.amount, amount_sat=request.amount_sat,
amount_asset=request.amount_asset,
asset_id=request.asset_id,
drain=request.drain drain=request.drain
) )
return result return result
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
# Health check endpoint @app.post("/send_onchain", response_model=SendOnchainResponse)
async def send_onchain(
request: SendOnchainBody,
api_key: str = Depends(get_api_key),
handler: PaymentHandler = Depends(get_payment_handler)
):
try:
# Prepare onchain payment
prepare = handler.prepare_pay_onchain(
amount_sat=request.amount_sat,
drain=request.drain,
fee_rate_sat_per_vbyte=request.fee_rate_sat_per_vbyte
)
# Execute onchain payment
handler.pay_onchain(
address=request.address,
prepare_response=prepare
)
return {"status": "initiated", "address": request.address, "fees_sat": prepare.get("total_fees_sat")}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/onchain_limits")
async def onchain_limits(
api_key: str = Depends(get_api_key),
handler: PaymentHandler = Depends(get_payment_handler)
):
try:
return handler.fetch_onchain_limits()
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/health") @app.get("/health")
async def health(): async def health():
return {"status": "ok"} return {"status": "ok"}
@ln_router.post("/parse_input")
async def parse_input(
request: ParseInputBody,
api_key: str = Depends(get_api_key),
handler: PaymentHandler = Depends(get_payment_handler)
):
try:
return handler.parse_input(request.input)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@ln_router.post("/prepare")
async def prepare(
request: PrepareLnurlPayBody,
api_key: str = Depends(get_api_key),
handler: PaymentHandler = Depends(get_payment_handler)
):
try:
from breez_sdk_liquid import LnUrlPayRequestData
data_obj = LnUrlPayRequestData(**request.data)
return handler.prepare_lnurl_pay(
data=data_obj,
amount_sat=request.amount_sat,
comment=request.comment,
validate_success_action_url=request.validate_success_action_url
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@ln_router.post("/pay")
async def pay(
request: LnurlPayBody,
api_key: str = Depends(get_api_key),
handler: PaymentHandler = Depends(get_payment_handler)
):
try:
from breez_sdk_liquid import PrepareLnUrlPayResponse
prepare_obj = PrepareLnUrlPayResponse(**request.prepare_response)
return handler.lnurl_pay(prepare_obj)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@ln_router.post("/auth")
async def auth(
request: LnurlAuthBody,
api_key: str = Depends(get_api_key),
handler: PaymentHandler = Depends(get_payment_handler)
):
try:
from breez_sdk_liquid import LnUrlAuthRequestData
data_obj = LnUrlAuthRequestData(**request.data)
return {"success": handler.lnurl_auth(data_obj)}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@ln_router.post("/withdraw")
async def withdraw(
request: LnurlWithdrawBody,
api_key: str = Depends(get_api_key),
handler: PaymentHandler = Depends(get_payment_handler)
):
try:
from breez_sdk_liquid import LnUrlWithdrawRequestData
data_obj = LnUrlWithdrawRequestData(**request.data)
return handler.lnurl_withdraw(
data=data_obj,
amount_msat=request.amount_msat,
comment=request.comment
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
app.include_router(ln_router)
if __name__ == "__main__": if __name__ == "__main__":
import uvicorn import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000) uvicorn.run(app, host="0.0.0.0", port=8000)

View File

@@ -10,7 +10,7 @@ package-mode = false
python = "^3.10" python = "^3.10"
fastapi = "^0.111.0" fastapi = "^0.111.0"
uvicorn = {extras = ["standard"], version = "^0.30.1"} uvicorn = {extras = ["standard"], version = "^0.30.1"}
breez-sdk-liquid = "*" breez-sdk-liquid = "0.8.2"
python-dotenv = "^1.0.1" python-dotenv = "^1.0.1"
requests = "^2.31.0" requests = "^2.31.0"