From 2d61a8854f38a61507289af3520e52ff54ccb1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Fri, 21 Oct 2022 17:35:58 +0200 Subject: [PATCH 1/3] improving on split payment handling --- lnbits/extensions/splitpayments/models.py | 2 +- lnbits/extensions/splitpayments/tasks.py | 72 ++++++++--------------- 2 files changed, 24 insertions(+), 50 deletions(-) diff --git a/lnbits/extensions/splitpayments/models.py b/lnbits/extensions/splitpayments/models.py index 4b95ed18b..6338d97f4 100644 --- a/lnbits/extensions/splitpayments/models.py +++ b/lnbits/extensions/splitpayments/models.py @@ -14,7 +14,7 @@ class Target(BaseModel): class TargetPutList(BaseModel): wallet: str = Query(...) alias: str = Query("") - percent: float = Query(..., ge=0.01) + percent: float = Query(..., ge=0.01, lt=100) class TargetPut(BaseModel): diff --git a/lnbits/extensions/splitpayments/tasks.py b/lnbits/extensions/splitpayments/tasks.py index cfc6c226f..53378b205 100644 --- a/lnbits/extensions/splitpayments/tasks.py +++ b/lnbits/extensions/splitpayments/tasks.py @@ -1,13 +1,11 @@ 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 get_current_extension_name, urlsafe_short_hash -from lnbits.tasks import internal_invoice_queue, register_invoice_listener +from lnbits.core.services import create_invoice, pay_invoice +from lnbits.helpers import get_current_extension_name +from lnbits.tasks import register_invoice_listener from .crud import get_targets @@ -22,60 +20,36 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if payment.extra.get("tag") == "splitpayments" or payment.extra.get("splitted"): - # already splitted, ignore + if payment.extra.get("tag") == "splitpayments": + # already a splitted payment, ignore return - # now we make some special internal transfers (from no one to the receiver) targets = await get_targets(payment.wallet_id) if not targets: return - 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]) + total_percent = sum([target.percent for target in targets]) - if amount_left < 0: - logger.error( - "splitpayments failure: amount_left is negative.", payment.payment_hash - ) + if total_percent > 100: + logger.error("splitpayment failure: total percent adds up to more than 100%") 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, + logger.debug(f"performing split payments to {len(targets)} targets") + for target in targets: + amount = int(payment.amount * target.percent / 100) # msats + payment_hash, payment_request = await create_invoice( + wallet_id=target.wallet, + amount=int(amount / 1000), # sats + internal=True, + memo=f"split payment: {target.percent}% for {target.alias or target.wallet}", extra={"tag": "splitpayments"}, ) + logger.debug(f"created split invoice: {payment_hash}") - # manually send this for now - await internal_invoice_queue.put(internal_checking_id) - return + checking_id = await pay_invoice( + payment_request=payment_request, + wallet_id=payment.wallet_id, + extra={"tag": "splitpayments"}, + ) + logger.debug(f"paid split invoice: {checking_id}") From fe879ad9b964766c25f8b59a0323d009d332166d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Fri, 21 Oct 2022 18:15:27 +0200 Subject: [PATCH 2/3] add tpos to pr --- lnbits/extensions/tpos/tasks.py | 58 ++++++++++----------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/lnbits/extensions/tpos/tasks.py b/lnbits/extensions/tpos/tasks.py index f18d16892..6369bbc7f 100644 --- a/lnbits/extensions/tpos/tasks.py +++ b/lnbits/extensions/tpos/tasks.py @@ -1,11 +1,11 @@ import asyncio -import json -from lnbits.core import db as core_db -from lnbits.core.crud import create_payment +from loguru import logger + from lnbits.core.models import Payment -from lnbits.helpers import get_current_extension_name, urlsafe_short_hash -from lnbits.tasks import internal_invoice_queue, register_invoice_listener +from lnbits.core.services import create_invoice, pay_invoice +from lnbits.helpers import get_current_extension_name +from lnbits.tasks import register_invoice_listener from .crud import get_tpos @@ -20,11 +20,9 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if payment.extra.get("tag") == "tpos" and payment.extra.get("tipSplitted"): - # already splitted, ignore + if payment.extra.get("tag") != "tpos": return - # now we make some special internal transfers (from no one to the receiver) tpos = await get_tpos(payment.extra.get("tposId")) tipAmount = payment.extra.get("tipAmount") @@ -32,39 +30,17 @@ async def on_invoice_paid(payment: Payment) -> None: # no tip amount return - tipAmount = tipAmount * 1000 - amount = payment.amount - tipAmount - - # 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, tipSplitted=True)), - amount, - payment.payment_hash, - ), - ) - - # perform the internal transfer using the same payment_hash - internal_checking_id = f"internal_{urlsafe_short_hash()}" - await create_payment( + payment_hash, payment_request = await create_invoice( wallet_id=tpos.tip_wallet, - checking_id=internal_checking_id, - payment_request="", - payment_hash=payment.payment_hash, - amount=tipAmount, - memo=f"Tip for {payment.memo}", - pending=False, - extra={"tipSplitted": True}, + amount=int(tipAmount), # sats + internal=True, + memo=f"tpos tip", ) + logger.debug(f"tpos: tip invoice created: {payment_hash}") - # manually send this for now - await internal_invoice_queue.put(internal_checking_id) - return + checking_id = await pay_invoice( + payment_request=payment_request, + wallet_id=payment.wallet_id, + extra={"tag": "tpos"}, + ) + logger.debug(f"tpos: tip invoice paid: {checking_id}") From e1fbb8c3cd112d56bbd147565cc649f007d42287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Fri, 21 Oct 2022 18:28:39 +0200 Subject: [PATCH 3/3] fix livestream extension --- lnbits/extensions/livestream/tasks.py | 52 ++++++++------------------- 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/lnbits/extensions/livestream/tasks.py b/lnbits/extensions/livestream/tasks.py index 626c698ca..d081332f5 100644 --- a/lnbits/extensions/livestream/tasks.py +++ b/lnbits/extensions/livestream/tasks.py @@ -4,10 +4,10 @@ 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 get_current_extension_name, urlsafe_short_hash -from lnbits.tasks import internal_invoice_listener, register_invoice_listener +from lnbits.core.services import create_invoice, pay_invoice +from lnbits.helpers import get_current_extension_name +from lnbits.tasks import register_invoice_listener from .crud import get_livestream_by_track, get_producer, get_track @@ -44,44 +44,20 @@ async def on_invoice_paid(payment: Payment) -> None: # now we make a special kind of internal transfer amount = int(payment.amount * (100 - ls.fee_pct) / 100) - # mark the original payment with two extra keys, "shared_with" and "received" - # (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, - shared_with=[producer.name, producer.id], - received=payment.amount, - ) - ), - payment.amount - amount, - payment.payment_hash, - ), - ) - - # perform an internal transfer using the same payment_hash to the producer wallet - internal_checking_id = f"internal_{urlsafe_short_hash()}" - await create_payment( - wallet_id=producer.wallet, - checking_id=internal_checking_id, - payment_request="", - payment_hash=payment.payment_hash, - amount=amount, + payment_hash, payment_request = await create_invoice( + wallet_id=tpos.tip_wallet, + amount=amount, # sats + internal=True, memo=f"Revenue from '{track.name}'.", - pending=False, ) + logger.debug(f"livestream: producer invoice created: {payment_hash}") - # manually send this for now - # await internal_invoice_paid.send(internal_checking_id) - await internal_invoice_listener.put(internal_checking_id) + checking_id = await pay_invoice( + payment_request=payment_request, + wallet_id=payment.wallet_id, + extra={"tag": "livestream"}, + ) + logger.debug(f"livestream: producer invoice paid: {checking_id}") # so the flow is the following: # - we receive, say, 1000 satoshis