Files
SatsFaucet/backend/src/services/quote.ts
SatsFaucet 623eb720dc Redesign faucet claim flow: login → loading → eligibility → claim
- Backend: payout is now random between FAUCET_MIN_SATS and FAUCET_MAX_SATS
- Remove weighted buckets; simplify config and .env.example
- Frontend: show loading and eligibility in main body, modal only for confirm/success
- Rename Confirm payout to Claim; add styles for body loading and eligible state

Made-with: Cursor
2026-03-02 14:59:37 +01:00

45 lines
1.5 KiB
TypeScript

import { randomInt } from "crypto";
import { v4 as uuidv4 } from "uuid";
import { config } from "../config.js";
import { getDb } from "../db/index.js";
import { getWalletBalanceSats } from "./lnbits.js";
const QUOTE_TTL_SECONDS = 60;
/**
* Random payout between FAUCET_MIN_SATS and FAUCET_MAX_SATS (inclusive),
* capped by daily budget remaining.
*/
export function computePayoutForClaim(todayPaidSats: number): number {
const remaining = Math.max(0, config.dailyBudgetSats - todayPaidSats);
if (remaining < config.faucetMinSats) return 0;
const min = Math.max(config.faucetMinSats, 1);
const max = Math.min(config.faucetMaxSats, remaining);
if (max < min) return 0;
return randomInt(min, max + 1);
}
export interface CreateQuoteResult {
quoteId: string;
payoutSats: number;
expiresAt: number;
}
export async function createQuote(pubkey: string, lightningAddress: string): Promise<CreateQuoteResult | null> {
const db = getDb();
const now = Math.floor(Date.now() / 1000);
const dayStart = now - (now % 86400);
const todayPaid = await db.getPaidSatsSince(dayStart);
let payout = computePayoutForClaim(todayPaid);
if (payout <= 0) return null;
const walletBalance = await getWalletBalanceSats();
payout = Math.min(payout, Math.max(0, walletBalance));
if (payout < config.faucetMinSats) return null;
const quoteId = uuidv4();
const expiresAt = now + QUOTE_TTL_SECONDS;
await db.createQuote(quoteId, pubkey, payout, lightningAddress, expiresAt);
return { quoteId, payoutSats: payout, expiresAt };
}