From f2b89db92c3a8de2d6ec94d174e3f3da437662fe Mon Sep 17 00:00:00 2001 From: blackcoffeexbt <87530449+blackcoffeexbt@users.noreply.github.com> Date: Tue, 28 Jul 2026 10:59:04 +0100 Subject: [PATCH] Move wallet Lightning Address lookups into CRUD --- lnbits/core/crud/wallets.py | 45 +++++++++++++++++++ lnbits/core/services/lightning_address.py | 53 ++++------------------- lnbits/middleware.py | 6 +-- 3 files changed, 56 insertions(+), 48 deletions(-) diff --git a/lnbits/core/crud/wallets.py b/lnbits/core/crud/wallets.py index 61a8519d1..aae4d243b 100644 --- a/lnbits/core/crud/wallets.py +++ b/lnbits/core/crud/wallets.py @@ -1,5 +1,6 @@ from datetime import datetime, timezone from time import time +from typing import Any from uuid import uuid4 from lnbits.core.db import db @@ -229,6 +230,50 @@ async def get_wallets_count(): return row.get("count", 0) +async def wallet_lightning_address_exists( + local_part: str, conn: Connection | None = None +) -> bool: + row: Any = await (conn or db).fetchone( + """ + SELECT id FROM wallets + WHERE lightning_address = :lightning_address + """, + {"lightning_address": local_part}, + ) + return bool(row) + + +async def wallet_lightning_address_exists_for_other_wallet( + local_part: str, wallet_id: str, conn: Connection | None = None +) -> bool: + row: Any = await (conn or db).fetchone( + """ + SELECT id FROM wallets + WHERE lightning_address = :lightning_address + AND id != :wallet_id + """, + {"lightning_address": local_part, "wallet_id": wallet_id}, + ) + return bool(row) + + +async def get_wallet_by_lightning_address(local_part: str) -> Wallet | None: + return await db.fetchone( + """ + SELECT wallets.*, COALESCE(( + SELECT balance FROM balances WHERE wallet_id = wallets.id + ), 0) AS balance_msat FROM wallets + INNER JOIN accounts ON wallets.user = accounts.id + WHERE lightning_address = :lightning_address + AND wallet_type = 'lightning' + AND deleted = false + AND accounts.activated = true + """, + {"lightning_address": local_part.lower()}, + Wallet, + ) + + async def get_wallet_for_key( key: str, conn: Connection | None = None, diff --git a/lnbits/core/services/lightning_address.py b/lnbits/core/services/lightning_address.py index 38ec77a5c..b8888f379 100644 --- a/lnbits/core/services/lightning_address.py +++ b/lnbits/core/services/lightning_address.py @@ -16,6 +16,11 @@ from lnurl import ( from pydantic import parse_obj_as from sqlalchemy.exc import OperationalError +from lnbits.core.crud.wallets import ( + get_wallet_by_lightning_address, + wallet_lightning_address_exists, + wallet_lightning_address_exists_for_other_wallet, +) from lnbits.core.db import db from lnbits.core.models.wallets import Wallet from lnbits.db import Connection, Database @@ -91,31 +96,6 @@ def _generate_local_part() -> str: return f"{participle}.{noun}.{suffix:03d}" -async def _core_address_exists(local_part: str, conn: Connection | None = None) -> bool: - row: Any = await (conn or db).fetchone( - """ - SELECT id FROM wallets - WHERE lightning_address = :lightning_address - """, - {"lightning_address": local_part}, - ) - return bool(row) - - -async def _core_address_exists_for_other_wallet( - local_part: str, wallet_id: str, conn: Connection | None = None -) -> bool: - row: Any = await (conn or db).fetchone( - """ - SELECT id FROM wallets - WHERE lightning_address = :lightning_address - AND id != :wallet_id - """, - {"lightning_address": local_part, "wallet_id": wallet_id}, - ) - return bool(row) - - async def legacy_lnurlp_address_exists(local_part: str) -> bool: try: row: Any = await _LEGACY_LNURLP_DB.fetchone( @@ -138,7 +118,7 @@ async def generate_lightning_address_local_part( ) -> str: for _ in range(100): local_part = _generate_local_part() - if await _core_address_exists(local_part, conn): + if await wallet_lightning_address_exists(local_part, conn): continue if await legacy_lnurlp_address_exists(local_part): continue @@ -187,7 +167,9 @@ async def validate_lightning_address_local_part( ) if not allow_blacklisted and _uses_blacklisted_word(local_part): raise ValueError("Lightning Address contains a reserved word.") - if await _core_address_exists_for_other_wallet(local_part, wallet.id, conn): + if await wallet_lightning_address_exists_for_other_wallet( + local_part, wallet.id, conn + ): raise ValueError("Lightning Address is already taken.") if await legacy_lnurlp_address_exists(local_part): raise ValueError("Lightning Address is already taken.") @@ -288,23 +270,6 @@ async def ensure_wallet_lightning_address( return wallet -async def get_wallet_by_lightning_address(local_part: str) -> Wallet | None: - return await db.fetchone( - """ - SELECT wallets.*, COALESCE(( - SELECT balance FROM balances WHERE wallet_id = wallets.id - ), 0) AS balance_msat FROM wallets - INNER JOIN accounts ON wallets.user = accounts.id - WHERE lightning_address = :lightning_address - AND wallet_type = 'lightning' - AND deleted = false - AND accounts.activated = true - """, - {"lightning_address": local_part.lower()}, - Wallet, - ) - - def lightning_address_for_request(request: Request, local_part: str) -> str: return f"{local_part}@{request.url.netloc}" diff --git a/lnbits/middleware.py b/lnbits/middleware.py index bae246070..4d534d7b8 100644 --- a/lnbits/middleware.py +++ b/lnbits/middleware.py @@ -123,10 +123,8 @@ class ExtensionsRedirectMiddleware: username = path_parts[2].lower() base_username = username.partition("+")[0] - from lnbits.core.services.lightning_address import ( - get_wallet_by_lightning_address, - legacy_lnurlp_address_exists, - ) + from lnbits.core.crud.wallets import get_wallet_by_lightning_address + from lnbits.core.services.lightning_address import legacy_lnurlp_address_exists if await legacy_lnurlp_address_exists(username): return False