| import { NextResponse } from 'next/server' |
| import { fetchWalletSignals, isHeliusConfigured } from '@/lib/helius' |
| import { calculateChurnScore } from '@/lib/agent-engine' |
| import { sendCustomEvent, isTorqueConfigured } from '@/lib/torque-mcp' |
| import { pushEvent } from '@/lib/event-store' |
| import { recordIntervention } from '@/lib/attribution-store' |
|
|
| export async function POST(req: Request) { |
| const { address, autoFire = false } = await req.json() |
|
|
| if (!address || typeof address !== 'string') { |
| return NextResponse.json({ error: 'address required' }, { status: 400 }) |
| } |
| if (!isHeliusConfigured()) { |
| return NextResponse.json({ error: 'HELIUS_API_KEY not configured' }, { status: 503 }) |
| } |
|
|
| const signals = await fetchWalletSignals(address) |
| if (!signals) { |
| return NextResponse.json({ error: 'Failed to fetch wallet data from Helius' }, { status: 502 }) |
| } |
|
|
| const { score, risk, signals: detectedSignals } = calculateChurnScore({ |
| daysInactive: signals.daysInactive, |
| volumeDropPct: signals.volumeDropPct, |
| uniqueProtocols: signals.uniqueProtocols, |
| currentStreak: signals.currentStreak, |
| hasLiquidation: signals.hasLiquidation, |
| }) |
|
|
| let torqueResult: { fired: boolean; eventId?: string; eventName?: string } = { fired: false } |
|
|
| if (autoFire && isTorqueConfigured() && (risk === 'critical' || risk === 'high' || risk === 'medium')) { |
| const eventName = risk === 'critical' || risk === 'high' ? 'churn_risk_high' : 'churn_risk_medium' |
| const result = await sendCustomEvent(address, eventName, { |
| risk, score, |
| daysInactive: signals.daysInactive, |
| protocols: signals.protocols, |
| source: 'helius_live', |
| detectedBy: 'flowstate-helius-scan', |
| }) |
| if (result.success && result.eventId) { |
| pushEvent({ |
| ingestionId: result.eventId, |
| wallet: address, |
| eventName, |
| risk, |
| score, |
| firedAt: new Date().toISOString(), |
| source: 'scan', |
| }) |
| recordIntervention(address, eventName, score) |
| torqueResult = { fired: true, eventId: result.eventId, eventName } |
| } |
| } |
|
|
| return NextResponse.json({ |
| address, |
| signals, |
| score, |
| risk, |
| detectedSignals, |
| torque: torqueResult, |
| }) |
| } |
|
|