Commit Graph
4 Commits
Author SHA1 Message Date
jwinterm 5d8d5e193f feat(tips): stage 5 — GC workers + fail-closed flag + capabilities + openapi
- GC: cancel_old_drafts (draft >7d -> cancelled), cancel_stuck_pending_confirmation
  (>7d), log_stuck_claiming (read-only, >15min). Draft GC hourly + lifecycle GC
  5min, spawned behind FEATURE_TIPS. Funded-but-unattached safety net is the
  7-day window + clawback incl 'cancelled'.
- config validate(): tips enabled fails closed unless a supported chain
  (btc/ltc/xmr/wow) is on AND tip_share_base is set.
- capabilities: advertise tips=true only when actually serveable.
- regenerated openapi.json (8 /tips/social/* endpoints).

Public-tips port COMPLETE (stages 1-5). Full suite green.
2026-07-10 15:51:20 -04:00
jwinterm b7e3510553 feat(tips): stage 4 — claim / clawback / confirm-sweep + sweep reconciler (money-out)
Escrow settlement, audited guards ported verbatim:
- mark_tip_claiming: status IN('pending','claiming') AND confs>=required AND
  funding_amount_verified AND sweep_confirmed_at IS NULL (double-claim guard).
- confirm_tip_sweep: RECORD-not-settle, first-recorder-wins (COALESCE +
  sweep_txid IS NULL OR =$3) — RBF-steal safe; reconciler owns claiming->claimed.
- confirm_sweep_onchain: SOLE writer of 'claimed', one-way status='claiming' AND
  sweep_confirmed_at IS NULL lock; settles only after on-chain sweep confirms to
  per-asset depth (btc/ltc 1, wow 4, xmr 10).
- clawback: 5-status set incl 'cancelled', blocked once sweep_confirmed_at set.
- revert_sweep_on_reorg: only from 'claimed', re-opens to 'claiming' + clears txid.
- sweep_reconciler: address-history-driven (not recorded txid), pick_winner
  (earliest height, lexi-smallest tie), pg advisory locks on a pinned conn for
  single-instance safety; reorg pass reverts only on affirmative vanish, never on
  probe error. DMs stubbed, exactly-once stamps kept.
- POST claim/confirm-sweep/clawback endpoints + openapi.
- 16 integration + 12 reconciler unit tests; build clean; SocialTipRow dead_code
  allow removed (all fields now read).
2026-07-10 15:34:14 -04:00
jwinterm b63cac19e2 feat(tips): stage 3 — attach-funding + funding-verification worker (money-in)
- attach_funding_to_tip: atomic guarded UPDATE (COALESCE + CASE), idempotent on
  same txid, 400 on a different txid; non-drafts land pending_confirmation so the
  verifier (not the caller) owns the ->pending transition.
- worker (src/tips/confirmation.rs): XMR/WOW confirmation counting via LWS;
  amount verification for BTC/LTC (Electrum full history, confirmed-only) +
  XMR/WOW (classify_funding_amount, separate-then-subtract net). Verified->pending,
  Short->funding_mismatch; Unfunded/Drained/LwsError never mutate status (outage-
  safe). Spawned behind FEATURE_TIPS on a 60s loop w/ catch_unwind guard.
- POST /tips/social/:id/attach-funding endpoint + openapi.
- 5 DB tests + 6 classify unit tests; build clean.
2026-07-10 14:53:46 -04:00
jwinterm f3d6be95b8 feat(tips): stage 2 — create / get-public / get-sent / cancel routes
Public-tip create/read/cancel surface matching the client contract:
- POST /tips/social (draft or funded), GET /tips/social/sent,
  GET /tips/social/:id/public (unauth; 404s non-public), POST .../:id/cancel.
- DB: insert (draft/pending_confirmation), get_sent, guarded cancel_draft
  (owner + draft-only).
- Validates is_public (targeted rejected), amount>0, claim_key_hash 64-hex,
  encrypted_key <=4096 hex, tip_address; share_url from TIP_SHARE_BASE_URL.
- ensure_tips_enabled gate; openapi paths+schemas+tag registered.
No funds move. 5 route/DB tests pass.
2026-07-10 08:50:28 -04:00