From 06c553219ac34e5ca8a00c0598ebbc0ddccfe285 Mon Sep 17 00:00:00 2001 From: Riccardo Balbo Date: Mon, 13 Jul 2026 10:59:49 +0200 Subject: [PATCH] Merge commit from fork * fix: daily withdrawal limit * feat: unit tests for cumulative daily withdrawal --- lnbits/core/services/payments.py | 5 ++--- lnbits/helpers.py | 10 ++++++++++ tests/unit/test_services_payments.py | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/lnbits/core/services/payments.py b/lnbits/core/services/payments.py index fb3cd24f2..0b8d6b56e 100644 --- a/lnbits/core/services/payments.py +++ b/lnbits/core/services/payments.py @@ -17,7 +17,7 @@ from lnbits.db import Connection, Filters from lnbits.decorators import check_user_extension_access from lnbits.exceptions import InvoiceError, PaymentError, UnsupportedError from lnbits.fiat import get_fiat_provider -from lnbits.helpers import check_callback_url +from lnbits.helpers import check_callback_url, daystart_timestamp from lnbits.settings import settings from lnbits.task_manager import task_manager from lnbits.utils.crypto import fake_privkey, random_secret_and_hash, verify_preimage @@ -557,10 +557,9 @@ async def check_wallet_daily_withdraw_limit( raise ValueError("It is not allowed to spend funds from this server.") payments = await get_payments( - since=int(time.time()) - 60 * 60 * 24, + since=daystart_timestamp(), outgoing=True, wallet_id=wallet_id, - limit=1, conn=conn, ) if len(payments) == 0: diff --git a/lnbits/helpers.py b/lnbits/helpers.py index 88a001b34..127170586 100644 --- a/lnbits/helpers.py +++ b/lnbits/helpers.py @@ -372,3 +372,13 @@ def sha256s(value: str) -> str: Returns the hex as a string. """ return hashlib.sha256(value.encode("utf-8")).hexdigest() + + +def daystart_timestamp(dt: datetime | None = None) -> int: + """ + Returns the timestamp of the start of the day for the given + datetime (or now in UTC if not provided). + """ + dt = dt or datetime.now(timezone.utc) + day_start = dt.replace(hour=0, minute=0, second=0, microsecond=0) + return int(day_start.timestamp()) diff --git a/tests/unit/test_services_payments.py b/tests/unit/test_services_payments.py index a3ad69042..c2404503a 100644 --- a/tests/unit/test_services_payments.py +++ b/tests/unit/test_services_payments.py @@ -26,6 +26,7 @@ from lnbits.core.services.payments import ( check_payment_status, check_pending_payments, check_time_limit_between_transactions, + check_wallet_daily_withdraw_limit, check_transaction_status, check_wallet_limits, create_payment_request, @@ -248,6 +249,23 @@ async def test_check_wallet_limits_and_time_limit( settings.lnbits_wallet_limit_secs_between_trans = original_limit +@pytest.mark.anyio +async def test_check_wallet_daily_limit_counts_all_daily_payments(settings: Settings): + wallet = await _create_wallet() + await _create_payment(wallet, amount_msat=-2_000, status=PaymentState.SUCCESS) + await _create_payment(wallet, amount_msat=-3_000, status=PaymentState.SUCCESS) + + original_limit = settings.lnbits_wallet_limit_daily_max_withdraw + try: + settings.lnbits_wallet_limit_daily_max_withdraw = 5 + with pytest.raises( + ValueError, match="Daily withdrawal limit of 5 sats reached." + ): + await check_wallet_daily_withdraw_limit(wallet.id, 1_000) + finally: + settings.lnbits_wallet_limit_daily_max_withdraw = original_limit + + @pytest.mark.anyio async def test_calculate_fiat_amounts_handles_conversion_and_errors( mocker: MockerFixture,