/* Sybilhunt — Docs page. window-mounted. Uses kit-components.jsx primitives. */ // Scroll-reveal wrapper function Reveal({ children, delay = 0, y = 24 }) { const ref = React.useRef(null); const [shown, setShown] = React.useState(false); React.useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { setShown(true); io.unobserve(el); } }); }, { threshold: 0.16 }); io.observe(el); return () => io.disconnect(); }, []); return (
{children}
); } // Count-up number function CountUp({ to, prefix = '', suffix = '', dur = 1400 }) { const ref = React.useRef(null); const [val, setVal] = React.useState(0); React.useEffect(() => { const el = ref.current; if (!el) return; let raf, started = false; const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting && !started) { started = true; const t0 = performance.now(); const tick = (t) => { const p = Math.min(1, (t - t0) / dur); const eased = 1 - Math.pow(1 - p, 3); setVal(to * eased); if (p < 1) raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); } }); }, { threshold: 0.5 }); io.observe(el); return () => { io.disconnect(); cancelAnimationFrame(raf); }; }, [to, dur]); const fmt = (n) => Math.round(n).toLocaleString('en-US'); return {prefix}{fmt(val)}{suffix}; } const DOC_CONCEPTS = [ { tag: 'What Sybils are', t: 'One person, a hundred faces', d: 'A Sybil spins up dozens or hundreds of accounts and poses as a crowd of real users — to grab rewards meant for many people.' }, { tag: 'Why they\u2019re dangerous', t: 'They take what isn\u2019t theirs', d: 'Sybils drain airdrop pools, distort activity metrics and erode trust in the project. Real participants get less — or nothing.' }, { tag: 'Why projects pay', t: 'Cheaper to catch than to lose', d: 'Handing $5M to bots is a direct loss. It\u2019s cheaper to give hunters a slice of the pool to filter Sybils out before distribution.' }, ]; const DOC_STEPS = [ { n: '01', t: 'Pick an active hunt', d: 'Open a partner campaign. Inside: the pool size, the rules, and the kind of Sybils we\u2019re after.' }, { n: '02', t: 'Analyze wallets & links', d: 'Trace funding sources, transaction timing, shared contracts and behavioral patterns that tie accounts into one cluster.' }, { n: '03', t: 'Build the evidence', d: 'Assemble the cluster: the set of accounts one actor controls, and the on-chain proof that links them.' }, { n: '04', t: 'Submit & claim', d: 'Confirmed clusters split the pool by what they found. Earlier and sharper reports earn a bigger share.' }, ]; const DOC_FAQ = [ { q: 'How is the reward calculated?', a: 'Each confirmed cluster earns a share of the pool proportional to the number of Sybil accounts it proves and the confidence of the evidence. Earlier submissions break ties.' }, { q: 'What counts as proof?', a: 'On-chain links — shared funding wallets, coordinated timing, identical contract interactions, recycled gas — packaged into a clear cluster a reviewer can verify independently.' }, { q: 'Do I need KYC to hunt?', a: 'No KYC to investigate or submit. Payouts in USDC are sent to the wallet that filed the confirmed report.' }, { q: 'Who reviews submissions?', a: 'The partner project plus Sybilhunt\u2019s forensics team review each cluster before rewards are released, so false positives don\u2019t cost real users.' }, ]; function DocsHeader() { const go = (hash) => { window.location.href = 'index.html' + (hash ? '#' + hash : ''); }; return (
go('')} />
); } function DNav({ onClick, active, children }) { return ( ); } function FaqItem({ q, a }) { const [open, setOpen] = React.useState(false); return (

{a}

); } function DocsApp() { return (
{/* Hero */}
Documentation

An open sybil hunt where the community wins

Sybilhunt connects projects that hand out rewards with hunters who know how to find fraud. The project puts up a pool — hunters bring the evidence — bots get nothing.

{/* Concepts */}
{DOC_CONCEPTS.map((c, i) => ( {c.tag}
{c.t}

{c.d}

))}
{/* How a hunt works */}
How a hunt works

From open campaign to paid reward

{DOC_STEPS.map((s, i) => (
{s.n}
{s.t}

{s.d}

))}
{/* FAQ */}
FAQ

Questions hunters ask

{DOC_FAQ.map((f) => )}
{/* CTA */}
); } function DocStat({ value, label, tone = 'default' }) { const colors = { default: 'var(--text-strong)', signal: 'var(--signal-400)', coral: 'var(--coral-300)' }; return (
{value}
{label}
); } ReactDOM.createRoot(document.getElementById('root')).render();