import { useEffect, useState } from 'react'; // CoinGecko DGB→USD, opt-in via Settings > Display. Fetched once per // mount + on manual refresh. NOT persisted per-second; caching for one // session is enough — an approximate price stays useful for a while. // // Privacy trade-off: enabling this reveals to CoinGecko that a browser // on the user's IP is checking the DGB price. Not seed-linked; not // address-linked; but it IS a data point. The Settings toggle names // the trade-off honestly. const ENDPOINT = 'https://api.coingecko.com/api/v3/simple/price?ids=digibyte&vs_currencies=usd'; interface PriceState { usd: number | null; fetchedAt: number | null; error: string | null; loading: boolean; } export function usePrice(enabled: boolean): PriceState & { refresh: () => void } { const [state, setState] = useState({ usd: null, fetchedAt: null, error: null, loading: false, }); const [nonce, setNonce] = useState(0); useEffect(() => { if (!enabled) { setState({ usd: null, fetchedAt: null, error: null, loading: false }); return; } let cancelled = false; setState((s) => ({ ...s, loading: true, error: null })); (async () => { try { const res = await fetch(ENDPOINT); if (!res.ok) throw new Error(`CoinGecko HTTP ${res.status}`); const body = (await res.json()) as { digibyte?: { usd?: number } }; const usd = body.digibyte?.usd ?? null; if (cancelled) return; if (typeof usd !== 'number') throw new Error('price missing in response'); setState({ usd, fetchedAt: Date.now(), error: null, loading: false }); } catch (e) { if (cancelled) return; setState({ usd: null, fetchedAt: null, error: (e as Error).message, loading: false }); } })(); return () => { cancelled = true; }; }, [enabled, nonce]); return { ...state, refresh: () => setNonce((n) => n + 1) }; }