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
This commit is contained in:
SatsFaucet
2026-03-02 14:59:37 +01:00
parent 381597c96f
commit 623eb720dc
6 changed files with 67 additions and 74 deletions

View File

@@ -6,42 +6,17 @@ import { getWalletBalanceSats } from "./lnbits.js";
const QUOTE_TTL_SECONDS = 60;
interface PayoutBucket {
sats: number;
weight: number;
}
function getPayoutBuckets(): PayoutBucket[] {
return [
{ sats: config.payoutSmallSats, weight: config.payoutWeightSmall },
{ sats: config.payoutMediumSats, weight: config.payoutWeightMedium },
{ sats: config.payoutLargeSats, weight: config.payoutWeightLarge },
{ sats: config.payoutJackpotSats, weight: config.payoutWeightJackpot },
];
}
/**
* Weighted random selection. Returns sats amount.
*/
export function selectWeightedPayout(): number {
const buckets = getPayoutBuckets();
const totalWeight = buckets.reduce((s, b) => s + b.weight, 0);
let r = randomInt(0, totalWeight);
for (const b of buckets) {
if (r < b.weight) return b.sats;
r -= b.weight;
}
return config.payoutSmallSats;
}
/**
* Compute payout for this claim: weighted selection, capped by daily budget remaining.
* 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 selected = selectWeightedPayout();
return Math.min(selected, remaining, config.faucetMaxSats);
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 {