From bd5c6615040a82a4a6e468f9ecdceb241a2c4606 Mon Sep 17 00:00:00 2001 From: openhands Date: Sun, 22 Feb 2026 19:39:36 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20address=20review=20=E2=80=94=20ring=20bu?= =?UTF-8?q?ffer=20validation,=20div-by-zero,=20sparkline=20alignment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ringBuffer length validation in extractSeries and extractSupplySeries - Fix division-by-zero when oldest holder count is 0 - Align supply series start with other series (consistent pre-launch skip) - Center flat sparklines vertically instead of pinning to bottom --- landing/src/components/LiveStats.vue | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/landing/src/components/LiveStats.vue b/landing/src/components/LiveStats.vue index 55039fb..363eafe 100644 --- a/landing/src/components/LiveStats.vue +++ b/landing/src/components/LiveStats.vue @@ -95,13 +95,19 @@ function weiToEth(wei: string | null | undefined): number { * Skips leading zeros (pre-launch padding). */ function extractSeries(ringBuffer: string[], pointer: number, slotOffset: number): number[] { + if (ringBuffer.length !== RING_HOURS * RING_SEGMENTS) { + // eslint-disable-next-line no-console + console.warn(`Ring buffer size mismatch: expected ${RING_HOURS * RING_SEGMENTS}, got ${ringBuffer.length}`); + return []; + } const raw: number[] = []; for (let i = 0; i < RING_HOURS; i++) { // Walk from oldest to newest const idx = ((pointer + 1 + i) % RING_HOURS) * RING_SEGMENTS + slotOffset; raw.push(Number(ringBuffer[idx] || '0')); } - // Skip leading zeros + // Skip leading zeros (pre-launch padding) — use findIndex on any non-zero + // Note: legitimate zero values mid-series are kept, only leading zeros trimmed const firstNonZero = raw.findIndex(v => v > 0); return firstNonZero === -1 ? [] : raw.slice(firstNonZero); } @@ -110,6 +116,7 @@ function extractSeries(ringBuffer: string[], pointer: number, slotOffset: number * Build cumulative net supply series from minted (slot 1) and burned (slot 2). */ function extractSupplySeries(ringBuffer: string[], pointer: number): number[] { + if (ringBuffer.length !== RING_HOURS * RING_SEGMENTS) return []; const minted: number[] = []; const burned: number[] = []; for (let i = 0; i < RING_HOURS; i++) { @@ -117,15 +124,15 @@ function extractSupplySeries(ringBuffer: string[], pointer: number): number[] { minted.push(Number(ringBuffer[idx + 1] || '0')); burned.push(Number(ringBuffer[idx + 2] || '0')); } - // Build cumulative net supply change + // Find first hour with any activity (align with extractSeries) + const firstActive = minted.findIndex((m, i) => m > 0 || burned[i] > 0); + if (firstActive === -1) return []; + // Build cumulative net supply change from first active hour const cumulative: number[] = []; let sum = 0; - let hasData = false; - for (let i = 0; i < RING_HOURS; i++) { - const net = minted[i] - burned[i]; - if (net !== 0) hasData = true; - sum += net; - if (hasData) cumulative.push(sum); + for (let i = firstActive; i < RING_HOURS; i++) { + sum += minted[i] - burned[i]; + cumulative.push(sum); } return cumulative; } @@ -138,10 +145,11 @@ function toSvgPoints(series: number[]): string { const min = Math.min(...series); const max = Math.max(...series); const range = max - min || 1; + const isFlat = max === min; return series .map((v, i) => { const x = (i / (series.length - 1)) * 80; - const y = 24 - ((v - min) / range) * 22 - 1; // 1px padding top/bottom + const y = isFlat ? 12 : 24 - ((v - min) / range) * 22 - 1; // center flat lines return `${x.toFixed(1)},${y.toFixed(1)}`; }) .join(' '); @@ -169,7 +177,7 @@ const holderGrowthIndicator = computed((): string | null => { if (series.length < 2) return null; const oldest = series[0]; const newest = series[series.length - 1]; - if (oldest === 0) return null; + if (oldest === 0) return newest > 0 ? `${newest} holders` : null; const pct = ((newest - oldest) / oldest) * 100; if (Math.abs(pct) < 0.1) return '~ flat'; return pct > 0 ? `↑ ${pct.toFixed(1)}% this week` : `↓ ${Math.abs(pct).toFixed(1)}% this week`;