From e1e6790628c8cfb092287fc438b79ab4cb13ca25 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Thu, 19 Mar 2026 19:05:57 -0400 Subject: [PATCH] feat: add zombie warning for auto-liquidation risk based on inactivity --- src/app/hashtag/[tag]/page.tsx | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/app/hashtag/[tag]/page.tsx b/src/app/hashtag/[tag]/page.tsx index 9f3a512..d055d10 100644 --- a/src/app/hashtag/[tag]/page.tsx +++ b/src/app/hashtag/[tag]/page.tsx @@ -6,10 +6,13 @@ import { formatCurrency, formatNumber } from '@/lib/utils' import { PriceChart } from '@/components/PriceChart' import { TradePanel } from './TradePanel' import { ResearchPanel } from './ResearchPanel' -import { Hash, Clock, Link as LinkIcon } from 'lucide-react' +import { Hash, Clock, Link as LinkIcon, AlertTriangle } from 'lucide-react' import { formatDistanceToNow } from 'date-fns' import Link from 'next/link' +const ZOMBIE_ZERO_COUNT = parseInt(process.env.ZOMBIE_ZERO_COUNT ?? '1000', 10) +const PRICE_UPDATE_INTERVAL_MINUTES = parseInt(process.env.PRICE_UPDATE_INTERVAL_MINUTES ?? '60', 10) + export const dynamic = 'force-dynamic' interface Props { @@ -150,6 +153,30 @@ export default async function HashtagPage({ params, searchParams }: Props) { /> + {/* Zombie warning — only shown when signed in, holding a position, and threshold reached */} + {session && (activeLong || activeShort) && hashtag.zeroCount >= ZOMBIE_ZERO_COUNT * 0.9 && (() => { + const zombieSince = formatDistanceToNow( + new Date(Date.now() - hashtag.zeroCount * PRICE_UPDATE_INTERVAL_MINUTES * 60 * 1000), + ) + const zombieEta = formatDistanceToNow( + new Date(Date.now() + (ZOMBIE_ZERO_COUNT - hashtag.zeroCount) * PRICE_UPDATE_INTERVAL_MINUTES * 60 * 1000), + { addSuffix: true }, + ) + return ( +
+ +
+

Auto-liquidation risk

+

+ No activity detected for {zombieSince}. + If this continues, your position will be force-closed{' '} + {zombieEta}. +

+
+
+ ) + })()} + {/* Trade panel or sign-in prompt */} {session ? (