Parent: #877
Depends on: #878 , #879
Scope
New Vercel cron that syncs trade_history → pl_points for buy events within the campaign window.
Logic
Query trade_history for event_type = 'mint' where block_timestamp is within campaign window
Filter out ZAP_PLOTLINK address (self-mints via zap contract)
For each unprocessed trade:
Compute points: reserve_amount converted to PLOT (1 PL per 1 PLOT spent)
Look up user's current streak tier from pl_streaks → apply boost multiplier
Insert pl_points row with action = 'buy', boosted points, metadata = { trade_id }
Check if buyer has a referrer in pl_referrals:
If yes: insert action = 'referral' points (20% of buyer's buy points, also boosted by referrer's streak) for the referrer
Dedup via metadata->>'trade_id' — skip if already processed
Endpoint
POST /api/cron/airdrop-points
Schedule: Every 5 min (*/5 * * * *)
Auth: CRON_SECRET header (same pattern as existing crons)
Existing Infrastructure
trade_history table already populated by src/app/api/cron/trade-history/route.ts (every 5 min)
ZAP_PLOTLINK address defined in lib/contracts/constants.ts
Streak boost lookup from lib/airdrop/streak.ts (see [Airdrop P2] Streak check-in system (SIWE) #882 )
Files
src/app/api/cron/airdrop-points/route.ts
lib/airdrop/points.ts (helper: compute points with boost)
Acceptance Criteria
Parent: #877
Depends on: #878, #879
Scope
New Vercel cron that syncs
trade_history→pl_pointsfor buy events within the campaign window.Logic
trade_historyforevent_type = 'mint'whereblock_timestampis within campaign windowZAP_PLOTLINKaddress (self-mints via zap contract)reserve_amountconverted to PLOT (1 PL per 1 PLOT spent)pl_streaks→ apply boost multiplierpl_pointsrow withaction = 'buy', boosted points,metadata = { trade_id }pl_referrals:action = 'referral'points (20% of buyer's buy points, also boosted by referrer's streak) for the referrermetadata->>'trade_id'— skip if already processedEndpoint
POST /api/cron/airdrop-pointsSchedule: Every 5 min (
*/5 * * * *)Auth:
CRON_SECRETheader (same pattern as existing crons)Existing Infrastructure
trade_historytable already populated bysrc/app/api/cron/trade-history/route.ts(every 5 min)ZAP_PLOTLINKaddress defined inlib/contracts/constants.tslib/airdrop/streak.ts(see [Airdrop P2] Streak check-in system (SIWE) #882)Files
src/app/api/cron/airdrop-points/route.tslib/airdrop/points.ts(helper: compute points with boost)Acceptance Criteria
trade_historytopl_pointsCAMPAIGN_END