fix wallet instance

This commit is contained in:
shroominic
2025-06-30 17:54:43 +00:00
parent e5354fd773
commit ccf213aae1
4 changed files with 12 additions and 115 deletions
+2 -2
View File
@@ -5,7 +5,7 @@ from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from sqlmodel import select from sqlmodel import select
from .cashu import WALLET from .cashu import wallet
from .db import ApiKey, create_session from .db import ApiKey, create_session
admin_router = APIRouter(prefix="/admin") admin_router = APIRouter(prefix="/admin")
@@ -112,7 +112,7 @@ async def dashboard(request: Request) -> str:
# avoid rounding issues. # avoid rounding issues.
total_user_balance = sum(key.balance for key in api_keys) // 1000 total_user_balance = sum(key.balance for key in api_keys) // 1000
# Fetch balance from cashu # Fetch balance from cashu
current_balance = (await WALLET.fetch_wallet_state()).balance current_balance = (await wallet().fetch_wallet_state()).balance
owner_balance = current_balance - total_user_balance owner_balance = current_balance - total_user_balance
return f"""<!DOCTYPE html> return f"""<!DOCTYPE html>
+10 -13
View File
@@ -16,19 +16,19 @@ DEV_LN_ADDRESS = "routstr@minibits.cash"
DEVS_DONATION_RATE = float(os.environ.get("DEVS_DONATION_RATE", 0.021)) # 2.1% DEVS_DONATION_RATE = float(os.environ.get("DEVS_DONATION_RATE", 0.021)) # 2.1%
NSEC = os.environ["NSEC"] # Nostr private key for the wallet NSEC = os.environ["NSEC"] # Nostr private key for the wallet
WALLET: Wallet | None = None wallet_instance: Wallet | None = None
async def init_wallet() -> None: async def init_wallet() -> None:
global WALLET global wallet_instance
WALLET = await Wallet.create(nsec=NSEC) wallet_instance = await Wallet.create(nsec=NSEC)
def wallet() -> Wallet: def wallet() -> Wallet:
global WALLET global wallet_instance
if WALLET is None: if wallet_instance is None:
raise ValueError("Wallet not initialized") raise ValueError("Wallet not initialized")
return WALLET return wallet_instance
async def delete_key_if_zero_balance(key: ApiKey, session: AsyncSession) -> None: async def delete_key_if_zero_balance(key: ApiKey, session: AsyncSession) -> None:
@@ -187,20 +187,17 @@ async def refund_balance(amount_msats: int, key: ApiKey, session: AsyncSession)
if key.refund_address is None: if key.refund_address is None:
raise ValueError("Refund address not set.") raise ValueError("Refund address not set.")
assert WALLET is not None, "Wallet not initialized" return await wallet().send_to_lnurl(key.refund_address, amount=amount_sats)
return await WALLET.send_to_lnurl(key.refund_address, amount=amount_sats)
async def x_cashu_refund(key: ApiKey, session: AsyncSession) -> str: async def x_cashu_refund(key: ApiKey, session: AsyncSession) -> str:
assert WALLET is not None, "Wallet not initialized" refund_token = await wallet().send(key.balance)
refund_token = await WALLET.send(key.balance)
await session.delete(key) await session.delete(key)
await session.commit() await session.commit()
return refund_token return refund_token
async def redeem(cashu_token: str, lnurl: str) -> int: async def redeem(cashu_token: str, lnurl: str) -> int:
assert WALLET is not None, "Wallet not initialized" amount_sats, _ = await wallet().redeem(cashu_token)
amount_sats, _ = await WALLET.redeem(cashu_token) await wallet().send_to_lnurl(lnurl, amount=amount_sats)
await WALLET.send_to_lnurl(lnurl, amount=amount_sats)
return amount_sats return amount_sats
-42
View File
@@ -99,48 +99,6 @@ async def test_refund_balance_with_address(
mock_refund.assert_called_once() mock_refund.assert_called_once()
@pytest.mark.asyncio
async def test_refund_balance_without_address(
async_client: AsyncClient, test_session: AsyncSession
) -> None:
"""Test refunding balance when no refund address is set."""
# Create key without refund address - with unique ID
unique_id = str(uuid.uuid4())[:8]
api_key = f"test-key-no-refund-{unique_id}"
key = ApiKey(
hashed_key=api_key,
balance=500000,
refund_address=None,
total_spent=0,
total_requests=0,
)
test_session.add(key)
await test_session.commit()
# Mock the WALLET instance at the router.account module level
with patch("router.account.WALLET") as mock_wallet:
mock_wallet.send = AsyncMock(return_value="cashuBqQSEQ...")
response = await async_client.post(
"/v1/wallet/refund", headers={"Authorization": f"Bearer sk-{api_key}"}
)
assert response.status_code == 200
data = response.json()
assert data["recipient"] is None
assert data["msats"] == 500000
assert data["token"] == "cashuBqQSEQ..."
# Verify wallet.send was called with the correct amount (msats converted to sats)
mock_wallet.send.assert_called_once_with(500)
# Verify the API key was deleted after refund
deleted = await test_session.get(ApiKey, api_key)
assert deleted is None
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_topup_balance_endpoint( async def test_topup_balance_endpoint(
-58
View File
@@ -1,58 +0,0 @@
import asyncio
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from router.main import app, lifespan
from tests.conftest import TEST_ENV
@pytest.mark.asyncio
async def test_background_tasks_cancel_on_shutdown() -> None:
pricing_started = asyncio.Event()
pricing_cancelled = asyncio.Event()
async def fake_update() -> None:
pricing_started.set()
try:
await asyncio.Event().wait()
except asyncio.CancelledError:
pricing_cancelled.set()
raise
refund_started = asyncio.Event()
refund_cancelled = asyncio.Event()
async def fake_refund() -> None:
refund_started.set()
try:
await asyncio.Event().wait()
except asyncio.CancelledError:
refund_cancelled.set()
raise
with patch.dict("os.environ", TEST_ENV, clear=True):
mock_wallet = AsyncMock()
mock_wallet.__aenter__ = AsyncMock(return_value=mock_wallet)
mock_wallet.__aexit__ = AsyncMock(return_value=None)
mock_state = MagicMock()
mock_state.balance = 1000
mock_wallet.fetch_wallet_state = AsyncMock(return_value=mock_state)
mock_wallet.send_to_lnurl = AsyncMock(return_value=100)
mock_wallet.redeem = AsyncMock(return_value=(1, "sat"))
mock_wallet.send = AsyncMock(return_value="cashuAtoken123")
with (
patch("router.cashu.Wallet.create", AsyncMock(return_value=mock_wallet)),
patch("router.cashu.WALLET", mock_wallet),
):
with (
patch("router.main.update_sats_pricing", new=fake_update),
patch("router.main.check_for_refunds", new=fake_refund),
):
async with lifespan(app):
await pricing_started.wait()
await refund_started.wait()
assert pricing_cancelled.is_set()
assert refund_cancelled.is_set()