import asyncio import json from loguru import logger from lnbits.core import db as core_db from lnbits.core.crud import create_payment from lnbits.core.models import Payment from lnbits.helpers import urlsafe_short_hash from lnbits.tasks import internal_invoice_queue, register_invoice_listener from .crud import get_targets async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() register_invoice_listener(invoice_queue) while True: payment = await invoice_queue.get() await on_invoice_paid(payment) async def on_invoice_paid(payment: Payment) -> None: if payment.extra.get("tag") == "splitpayments" or payment.extra.get("splitted"): # already splitted, ignore return # now we make some special internal transfers (from no one to the receiver) targets = await get_targets(payment.wallet_id) transfers = [ (target.wallet, int(target.percent * payment.amount / 100)) for target in targets ] transfers = [(wallet, amount) for wallet, amount in transfers if amount > 0] amount_left = payment.amount - sum([amount for _, amount in transfers]) if amount_left < 0: logger.error( "splitpayments failure: amount_left is negative.", payment.payment_hash ) return if not targets: return # mark the original payment with one extra key, "splitted" # (this prevents us from doing this process again and it's informative) # and reduce it by the amount we're going to send to the producer await core_db.execute( """ UPDATE apipayments SET extra = ?, amount = ? WHERE hash = ? AND checking_id NOT LIKE 'internal_%' """, ( json.dumps(dict(**payment.extra, splitted=True)), amount_left, payment.payment_hash, ), ) # perform the internal transfer using the same payment_hash for wallet, amount in transfers: internal_checking_id = f"internal_{urlsafe_short_hash()}" await create_payment( wallet_id=wallet, checking_id=internal_checking_id, payment_request="", payment_hash=payment.payment_hash, amount=amount, memo=payment.memo, pending=False, extra={"tag": "splitpayments"}, ) # manually send this for now await internal_invoice_queue.put(internal_checking_id) return