Files
SatsFaucet/context/backend_overview.md
Michaël 3734365463 first commit
Made-with: Cursor
2026-02-26 18:33:00 -03:00

6.0 KiB

backend_overview.md

1. Purpose

This document defines the complete backend architecture and behavior for the Sats Faucet application.

The backend is responsible for:

  • Verifying NIP-98 signed authentication.
  • Enforcing all eligibility rules.
  • Fetching and caching Nostr account data.
  • Enforcing cooldowns and anti-abuse constraints.
  • Generating and locking entropy payout quotes.
  • Executing Lightning payouts via LNbits.
  • Maintaining transparency statistics.
  • Providing operational safety controls.

This backend must be production-safe, abuse-resistant, and configurable entirely via environment variables.


2. Tech Stack Requirements

Recommended stack:

  • Language: Go, TypeScript (Node/Express), or Python (FastAPI)
  • Database: PostgreSQL
  • Optional: Redis (rate limiting + nonce replay protection)
  • LNbits for Lightning payments
  • Reverse proxy with TLS (nginx or Caddy)

The backend must be stateless except for database persistence.


3. Environment Variables

All logic must be driven via .env configuration.

Key categories:

3.1 Security

  • JWT_SECRET
  • HMAC_IP_SECRET
  • NIP98_MAX_SKEW_SECONDS
  • NONCE_TTL_SECONDS
  • TRUST_PROXY
  • ALLOWED_ORIGINS

3.2 Faucet Economics

  • FAUCET_ENABLED
  • EMERGENCY_STOP
  • FAUCET_MIN_SATS
  • FAUCET_MAX_SATS
  • PAYOUT_WEIGHT_SMALL
  • PAYOUT_WEIGHT_MEDIUM
  • PAYOUT_WEIGHT_LARGE
  • PAYOUT_WEIGHT_JACKPOT
  • PAYOUT_SMALL_SATS
  • PAYOUT_MEDIUM_SATS
  • PAYOUT_LARGE_SATS
  • PAYOUT_JACKPOT_SATS
  • DAILY_BUDGET_SATS
  • MAX_CLAIMS_PER_DAY
  • MIN_WALLET_BALANCE_SATS

3.3 Eligibility

  • MIN_ACCOUNT_AGE_DAYS
  • MIN_ACTIVITY_SCORE
  • MIN_NOTES_COUNT
  • MIN_FOLLOWING_COUNT
  • MIN_FOLLOWERS_COUNT
  • ACTIVITY_LOOKBACK_DAYS

3.4 Cooldowns

  • COOLDOWN_DAYS
  • IP_COOLDOWN_DAYS
  • MAX_CLAIMS_PER_IP_PER_PERIOD

3.5 Nostr

  • NOSTR_RELAYS
  • RELAY_TIMEOUT_MS
  • MAX_EVENTS_FETCH
  • METADATA_CACHE_HOURS

3.6 LNbits

  • LNBITS_BASE_URL
  • LNBITS_ADMIN_KEY
  • LNBITS_WALLET_ID
  • DEPOSIT_LIGHTNING_ADDRESS
  • DEPOSIT_LNURLP

4. Database Schema

4.1 users

  • pubkey (PK)
  • nostr_first_seen_at
  • notes_count
  • followers_count
  • following_count
  • activity_score
  • last_metadata_fetch_at
  • created_at
  • updated_at

4.2 claims

  • id (PK)
  • pubkey (FK users.pubkey)
  • claimed_at
  • payout_sats
  • ip_hash
  • payout_destination_hash
  • status (pending, paid, failed)
  • lnbits_payment_hash
  • error_message

4.3 ip_limits

  • ip_hash (PK)
  • last_claimed_at
  • claim_count_period

4.4 quotes

  • quote_id (PK)
  • pubkey
  • payout_sats
  • created_at
  • expires_at
  • status (active, consumed, expired)

4.5 daily_stats (optional)

  • date (PK)
  • total_paid_sats
  • total_claims
  • unique_pubkeys

All IP addresses must be stored as HMAC(IP, HMAC_IP_SECRET).


5. NIP-98 Authentication

Every protected endpoint must:

  1. Extract NIP-98 header or payload.
  2. Verify signature against pubkey.
  3. Verify HTTP method and URL match signed payload.
  4. Verify timestamp within allowed skew.
  5. Verify nonce not previously used.
  6. Reject if invalid.

Nonces must be stored in Redis or DB for NONCE_TTL_SECONDS.


6. IP Resolution

If TRUST_PROXY=true:

  • Read first valid IP from X-Forwarded-For. Else:
  • Use request remote address.

Then:

  • Hash IP using HMAC_IP_SECRET.
  • Never store raw IP.

7. Eligibility Engine

Eligibility flow:

  1. Check FAUCET_ENABLED.
  2. Check EMERGENCY_STOP.
  3. Check LNbits wallet balance >= MIN_WALLET_BALANCE_SATS.
  4. Check pubkey cooldown.
  5. Check IP cooldown.
  6. Fetch or load cached Nostr profile.
  7. Compute account age.
  8. Compute activity score.
  9. Compare with thresholds.

Return structured result with denial code if failed.


8. Nostr Data Fetching

For a given pubkey:

  1. Query relays in parallel.

  2. Fetch:

    • kind 0 (metadata)
    • kind 1 (notes)
    • kind 3 (contacts)
  3. Compute:

    • earliest created_at
    • notes count in ACTIVITY_LOOKBACK_DAYS
    • following count

Cache results for METADATA_CACHE_HOURS.

If no events found:

  • Deny as account_too_new.

9. Activity Scoring

Example scoring logic:

  • Has metadata: +10
  • Notes >= MIN_NOTES_COUNT: +20
  • Following >= MIN_FOLLOWING_COUNT: +10
  • Followers >= MIN_FOLLOWERS_COUNT: +10

Score must be deterministic and logged.


10. Entropy Payout System

Weighted random selection:

  1. Build array based on configured weights.
  2. Generate secure random number.
  3. Select payout bucket.

Before finalizing quote:

  • Check daily spend.
  • Check MAX_CLAIMS_PER_DAY.

If budget exceeded:

  • Either deny or downgrade payout to FAUCET_MIN_SATS.

11. Claim Flow

11.1 POST /claim/quote

Input:

  • lightning_address

Steps:

  • Run eligibility engine.
  • If eligible, generate payout.
  • Insert quote record with expiry (e.g., 60 seconds).
  • Return quote_id and payout_sats.

11.2 POST /claim/confirm

Input:

  • quote_id

Steps:

  • Verify quote exists and active.
  • Re-check cooldown and budget.
  • Execute LNbits payment.
  • Update claim record.
  • Mark quote consumed.

Must be idempotent.


12. LNbits Integration

Payout flow:

  1. Resolve Lightning address to LNURL.
  2. Fetch LNURL payRequest.
  3. Call callback with amount in millisats.
  4. Handle success/failure response.
  5. Store payment hash.

On failure:

  • Mark claim failed.
  • Do not lock cooldown unless configured.

13. Public Endpoints

GET /health GET /config GET /stats GET /deposit

No authentication required.


14. Logging and Monitoring

Each claim attempt must log:

  • pubkey
  • ip_hash
  • eligibility result
  • payout amount
  • payment status

Metrics to track:

  • denial reasons count
  • payout distribution
  • daily spend

15. Security Hard Requirements

  • Strict CORS
  • Rate limit /claim endpoints
  • Nonce replay protection
  • HMAC IP hashing
  • Admin keys never exposed
  • All secrets loaded from env

16. Production Readiness Checklist

Backend is complete when:

  • NIP-98 auth fully verified.
  • Pubkey and IP cooldown enforced.
  • Account age check enforced.
  • Activity score enforced.
  • Entropy payout cannot be rerolled.
  • Daily budget cannot be exceeded.
  • LNbits payout works and errors handled safely.
  • Emergency stop disables claims instantly.
  • Logs clearly show denial reasons.