mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-02-24 14:51:05 +01:00
154 lines
6.1 KiB
Python
154 lines
6.1 KiB
Python
import asyncio
|
|
|
|
import httpx
|
|
from loguru import logger
|
|
|
|
from lnbits.core.models import Payment
|
|
from lnbits.core.services import check_transaction_status
|
|
from lnbits.helpers import get_current_extension_name
|
|
from lnbits.tasks import register_invoice_listener
|
|
|
|
from .boltz import (
|
|
create_claim_tx,
|
|
create_refund_tx,
|
|
get_swap_status,
|
|
start_confirmation_listener,
|
|
start_onchain_listener,
|
|
)
|
|
from .crud import (
|
|
get_all_pending_reverse_submarine_swaps,
|
|
get_all_pending_submarine_swaps,
|
|
get_reverse_submarine_swap,
|
|
get_submarine_swap,
|
|
update_swap_status,
|
|
)
|
|
|
|
"""
|
|
testcases for boltz startup
|
|
A. normal swaps
|
|
1. test: create -> kill -> start -> startup invoice listeners -> pay onchain funds -> should complete
|
|
2. test: create -> kill -> pay onchain funds -> start -> startup check -> should complete
|
|
3. test: create -> kill -> mine blocks and hit timeout -> start -> should go timeout/failed
|
|
4. test: create -> kill -> pay to less onchain funds -> mine blocks hit timeout -> start lnbits -> should be refunded
|
|
|
|
B. reverse swaps
|
|
1. test: create instant -> kill -> boltz does lockup -> not confirmed -> start lnbits -> should claim/complete
|
|
2. test: create instant -> kill -> no lockup -> start lnbits -> should start onchain listener -> boltz does lockup -> should claim/complete (difficult to test)
|
|
3. test: create -> kill -> boltz does lockup -> not confirmed -> start lnbits -> should start tx listener -> after confirmation -> should claim/complete
|
|
4. test: create -> kill -> boltz does lockup -> confirmed -> start lnbits -> should claim/complete
|
|
5. test: create -> kill -> boltz does lockup -> hit timeout -> boltz refunds -> start -> should timeout
|
|
"""
|
|
|
|
|
|
async def check_for_pending_swaps():
|
|
try:
|
|
swaps = await get_all_pending_submarine_swaps()
|
|
reverse_swaps = await get_all_pending_reverse_submarine_swaps()
|
|
if len(swaps) > 0 or len(reverse_swaps) > 0:
|
|
logger.debug(f"Boltz - startup swap check")
|
|
except:
|
|
# database is not created yet, do nothing
|
|
return
|
|
|
|
if len(swaps) > 0:
|
|
logger.debug(f"Boltz - {len(swaps)} pending swaps")
|
|
for swap in swaps:
|
|
try:
|
|
swap_status = get_swap_status(swap)
|
|
# should only happen while development when regtest is reset
|
|
if swap_status.exists is False:
|
|
logger.debug(f"Boltz - swap: {swap.boltz_id} does not exist.")
|
|
await update_swap_status(swap.id, "failed")
|
|
continue
|
|
|
|
payment_status = await check_transaction_status(
|
|
swap.wallet, swap.payment_hash
|
|
)
|
|
|
|
if payment_status.paid:
|
|
logger.debug(
|
|
f"Boltz - swap: {swap.boltz_id} got paid while offline."
|
|
)
|
|
await update_swap_status(swap.id, "complete")
|
|
else:
|
|
if swap_status.hit_timeout:
|
|
if not swap_status.has_lockup:
|
|
logger.debug(
|
|
f"Boltz - swap: {swap.id} hit timeout, but no lockup tx..."
|
|
)
|
|
await update_swap_status(swap.id, "timeout")
|
|
else:
|
|
logger.debug(f"Boltz - refunding swap: {swap.id}...")
|
|
await create_refund_tx(swap)
|
|
await update_swap_status(swap.id, "refunded")
|
|
|
|
except Exception as exc:
|
|
logger.error(f"Boltz - swap: {swap.id} - {str(exc)}")
|
|
|
|
if len(reverse_swaps) > 0:
|
|
logger.debug(f"Boltz - {len(reverse_swaps)} pending reverse swaps")
|
|
for reverse_swap in reverse_swaps:
|
|
try:
|
|
swap_status = get_swap_status(reverse_swap)
|
|
|
|
if swap_status.exists is False:
|
|
logger.debug(
|
|
f"Boltz - reverse_swap: {reverse_swap.boltz_id} does not exist."
|
|
)
|
|
await update_swap_status(reverse_swap.id, "failed")
|
|
continue
|
|
|
|
# if timeout hit, boltz would have already refunded
|
|
if swap_status.hit_timeout:
|
|
logger.debug(
|
|
f"Boltz - reverse_swap: {reverse_swap.boltz_id} timeout."
|
|
)
|
|
await update_swap_status(reverse_swap.id, "timeout")
|
|
continue
|
|
|
|
if not swap_status.has_lockup:
|
|
# start listener for onchain address
|
|
logger.debug(
|
|
f"Boltz - reverse_swap: {reverse_swap.boltz_id} restarted onchain address listener."
|
|
)
|
|
await start_onchain_listener(reverse_swap)
|
|
continue
|
|
|
|
if reverse_swap.instant_settlement or swap_status.confirmed:
|
|
await create_claim_tx(reverse_swap, swap_status.lockup)
|
|
else:
|
|
logger.debug(
|
|
f"Boltz - reverse_swap: {reverse_swap.boltz_id} restarted confirmation listener."
|
|
)
|
|
await start_confirmation_listener(reverse_swap, swap_status.lockup)
|
|
|
|
except Exception as exc:
|
|
logger.error(f"Boltz - reverse swap: {reverse_swap.id} - {str(exc)}")
|
|
|
|
|
|
async def wait_for_paid_invoices():
|
|
invoice_queue = asyncio.Queue()
|
|
register_invoice_listener(invoice_queue, get_current_extension_name())
|
|
|
|
while True:
|
|
payment = await invoice_queue.get()
|
|
await on_invoice_paid(payment)
|
|
|
|
|
|
async def on_invoice_paid(payment: Payment) -> None:
|
|
if "boltz" != payment.extra.get("tag"):
|
|
# not a boltz invoice
|
|
return
|
|
|
|
await payment.set_pending(False)
|
|
swap_id = payment.extra.get("swap_id")
|
|
swap = await get_submarine_swap(swap_id)
|
|
|
|
if not swap:
|
|
logger.error(f"swap_id: {swap_id} not found.")
|
|
return
|
|
|
|
logger.info(
|
|
f"Boltz - lightning invoice is paid, normal swap completed. swap_id: {swap_id}"
|
|
)
|
|
await update_swap_status(swap_id, "complete")
|