From 214dfabc55b032092434aa72f3a0bfd97bd56114 Mon Sep 17 00:00:00 2001 From: Shroominic Date: Tue, 29 Apr 2025 13:08:30 +0800 Subject: [PATCH] pay-out --- .env.example | 2 +- router/account.py | 2 +- router/auth.py | 6 +++--- router/{redeem.py => cashu.py} | 38 +++++++++++++++++++++++++++++++++- router/main.py | 2 +- 5 files changed, 43 insertions(+), 7 deletions(-) rename router/{redeem.py => cashu.py} (88%) diff --git a/.env.example b/.env.example index b5b5b8f4..ae073d79 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,6 @@ UPSTREAM_BASE_URL="https://api.openai.com/v1" UPSTREAM_API_KEY="sk-21212121212121212121212121212121" -RECIEIVE_LN_ADDRESS="shroominic@walletofsatoshi.com" +RECIEVE_LN_ADDRESS="shroominic@walletofsatoshi.com" COST_PER_REQUEST="10" diff --git a/router/account.py b/router/account.py index c075e174..ed07cba6 100644 --- a/router/account.py +++ b/router/account.py @@ -2,7 +2,7 @@ from typing import Annotated from fastapi import APIRouter, Header, HTTPException, Depends from .auth import validate_bearer_key -from .redeem import refund_balance, credit_balance, create_token +from .cashu import refund_balance, credit_balance, create_token from .db import ApiKey, AsyncSession, get_session account_router = APIRouter(prefix="/v1/wallet") diff --git a/router/auth.py b/router/auth.py index f8beedea..ea4cada1 100644 --- a/router/auth.py +++ b/router/auth.py @@ -6,11 +6,10 @@ from typing import Literal from fastapi import HTTPException from pydantic import BaseModel, Field -from .redeem import credit_balance +from .cashu import credit_balance, pay_out from .db import ApiKey, AsyncSession from .price import btc_usd_ask_price -RECIEIVE_LN_ADDRESS = os.environ["RECIEIVE_LN_ADDRESS"] COST_PER_REQUEST = ( int(os.environ.get("COST_PER_REQUEST", "1")) * 1000 ) # Convert to msats @@ -50,7 +49,6 @@ async def validate_bearer_key(bearer_key: str, session: AsyncSession) -> ApiKey: raise HTTPException( status_code=401, detail=f"Invalid or expired cashu key: {e}" ) - print(bearer_key) raise HTTPException(status_code=401, detail="Invalid API key") @@ -133,6 +131,8 @@ async def adjust_payment_for_tokens( session.add(key) await session.commit() + await pay_out(session) + return cost_data diff --git a/router/redeem.py b/router/cashu.py similarity index 88% rename from router/redeem.py rename to router/cashu.py index d6d8e238..e0a75e09 100644 --- a/router/redeem.py +++ b/router/cashu.py @@ -1,11 +1,15 @@ +import os import httpx from cashu.core.base import Token # type: ignore from cashu.wallet.wallet import Wallet # type: ignore from cashu.wallet.helpers import deserialize_token_from_string, receive # type: ignore - +from sqlmodel import select, func, col from .db import ApiKey, AsyncSession +RECIEVE_LN_ADDRESS = os.environ["RECIEVE_LN_ADDRESS"] +MINIMUM_PAYOUT = 100 # sat +DEVS_DONATION_RATE = 0.021 # 2.1% WALLET = None @@ -23,6 +27,7 @@ async def _initialize_wallet(mint_url: str | None = None) -> Wallet: unit="sat", # todo change to msat ) await wallet.load_mint_info() + await wallet.load_mint_keysets() if not hasattr(wallet, "keyset_id") or wallet.keyset_id is None: await wallet.activate_keyset() await wallet.load_proofs(reload=True) @@ -76,6 +81,37 @@ async def _pay_invoice_with_cashu( return quote.amount +async def pay_out(session: AsyncSession) -> None: + """ + Calculates the pay-out amount based on the spent balance, profit, and donation rate. + """ + balance = ( + await session.exec( + select(func.sum(col(ApiKey.balance))).where(ApiKey.balance > 0) + ) + ).one() + if balance is None: + raise ValueError("No balance to pay out.") + user_balance = balance // 1000 + wallet = await _initialize_wallet() + wallet_balance = wallet.available_balance + + assert wallet_balance >= user_balance, "Something went deeply wrong." + + if (revenue := wallet_balance - user_balance) <= MINIMUM_PAYOUT: + return + + devs_donation = int(revenue * DEVS_DONATION_RATE) + owners_draw = revenue - devs_donation + + await send_to_lnurl(wallet, RECIEVE_LN_ADDRESS, owners_draw) + await send_to_lnurl( + wallet, + "npub130mznv74rxs032peqym6g3wqavh472623mt3z5w73xq9r6qqdufs7ql29s@npub.cash", + devs_donation, + ) + + async def credit_balance(cashu_token: str, key: ApiKey, session: AsyncSession) -> int: token_obj: Token = deserialize_token_from_string(cashu_token) wallet: Wallet = await _initialize_wallet(token_obj.mint) diff --git a/router/main.py b/router/main.py index 8be1cabf..0d4f60db 100644 --- a/router/main.py +++ b/router/main.py @@ -6,7 +6,7 @@ from .db import init_db from .proxy import proxy_router from .account import account_router from .auth import read_models -from .redeem import _initialize_wallet +from .cashu import _initialize_wallet __version__ = "0.0.1"