Skip to content

Feat/network fees l2 toggle - #277

Merged
Flotapponnier merged 210 commits into
mainfrom
feat/network-fees-l2-toggle
Jun 2, 2026
Merged

Feat/network fees l2 toggle#277
Flotapponnier merged 210 commits into
mainfrom
feat/network-fees-l2-toggle

Conversation

@Flotapponnier

Copy link
Copy Markdown
Collaborator

What this changes

Type

  • New benchmark spec (benchmarks/<slug>.yml)
  • New harness (harnesses/<slug>/)
  • Site / component changes
  • Docs / tutorial
  • Other

Checklist

  • pnpm validate passes
  • pnpm typecheck passes
  • pnpm build passes
  • If a new spec: queries dry-run successfully against the Prometheus URL
  • If a new harness: README documents inputs, regions, timeouts, and how to run it locally
  • No API keys, secrets or private endpoints committed

Flotapponnier and others added 30 commits May 26, 2026 19:24
#147)

Logs every fork that produces a visible draft render to the user:
  kv_hit / kv_miss / kv_empty / kv_shape / kv_stale / kv_timeout /
  kv_neterr / kv_http / collapse / placeholder_used

Includes slug + timing per call. All prefixed with [DRAFT-TRACE] for
easy grep in Vercel logs. Plain console.warn — no extra deps.

Revert this commit once we have the cause pinned.
* chore(obs): temporary [DRAFT-TRACE] logs on bench draft fallback paths

Logs every fork that produces a visible draft render to the user:
  kv_hit / kv_miss / kv_empty / kv_shape / kv_stale / kv_timeout /
  kv_neterr / kv_http / collapse / placeholder_used

Includes slug + timing per call. All prefixed with [DRAFT-TRACE] for
easy grep in Vercel logs. Plain console.warn — no extra deps.

Revert this commit once we have the cause pinned.

* fix(solana-tx-landing harness): bump Astralane default tip to 1M lamports

Sync from the private mobula-api harness. Astralane raised their min
tip floor 500_000 → 1_000_000; keeps the public harness reproducing
the same probe config.
Two root causes pinned via [DRAFT-TRACE] logs on staging:

1. Prom queries quantile_over_time(0.99, …[24h]) consistently take
   4-8s under load. The 4s client timeout aborted, collapsing benches
   to draft when the per-bench KV snapshot wasn't available as fallback.
   Bump to 10s — fits the observed worst case with headroom.

2. The /api/cron/health-check route runs every 5 min but only computed
   Slack transitions. Add a loadAllBenchmarks() call so the per-bench
   unstable_cache stays warm and writeSnapshot() refreshes the KV
   snapshot layer. Eliminates the cold-start window where a fresh
   Vercel function instance has no in-memory cache AND the snapshot is
   stale or missing — exactly the pattern that produces the visible
   'bench in draft' symptom users observed.
…ne in light chip (#150)

* fix(perf): bump Prom timeout 4s→10s + cron pre-warms bench cache

Two root causes pinned via [DRAFT-TRACE] logs on staging:

1. Prom queries quantile_over_time(0.99, …[24h]) consistently take
   4-8s under load. The 4s client timeout aborted, collapsing benches
   to draft when the per-bench KV snapshot wasn't available as fallback.
   Bump to 10s — fits the observed worst case with headroom.

2. The /api/cron/health-check route runs every 5 min but only computed
   Slack transitions. Add a loadAllBenchmarks() call so the per-bench
   unstable_cache stays warm and writeSnapshot() refreshes the KV
   snapshot layer. Eliminates the cold-start window where a fresh
   Vercel function instance has no in-memory cache AND the snapshot is
   stale or missing — exactly the pattern that produces the visible
   'bench in draft' symptom users observed.

* fix(logo): wrap dark-toned provider logos in light chip

1RPC, Blocknative, Lava, Tenderly, Jito and Astralane have single-tone
(mostly dark) artwork that disappears against the page background on
small bench cards. Add to NEEDS_LIGHT_CHIP so they render on a white
chip with a hairline shadow — same treatment as Relay, Debridge, Tonapi.
Same single-tone artwork pattern as the previous batch — invisible on
the bench card background. Wrap in white chip for contrast.
…alane, Sky, dydx) (#153)

Verified via SVG fill audit: those 4 logos have fill="white" content,
which the previous white chip rendered as invisible-on-invisible.
Split into two sets — light chip (#fff for dark logos) and dark chip
(#0f172a for white logos).
…154)

The safety throw 'every bench draft, refusing to update cache' crashes
next build when Prom is fully unreachable during the build window.

Replace the throw with a [DRAFT-TRACE] warning + return the draft array.
With the snapshot/KV fallback + 10s Prom timeout + cron pre-warm already
mitigating user-visible drafts, this safety net's value is marginal.
* feat(bench-005): add coinpaprika, covalent, coinstats, sim-dune to network-coverage

* feat(bench-005): add coinpaprika/covalent/coinstats logos

* fix(bench-005): correct CoinStats endpoint path
)

* feat(bench-027): add Mobula Swap-Send to solana-tx-landing-latency providers

* feat(harnesses): sync solana-tx-landing OSS mirror with Mobula provider
…cial/oracle pairs) into one canonical entry (#163)
The distribution view used a linear scale anchored at max(p99). On benches
with very wide ranges (l1-finality spans 0.4s on TON to 36 min on Monero,
ratio 5370x) every fast row collapsed to a single invisible pixel at the
left edge, making 7 of 9 chains visually indistinguishable. Only the two
slowest rows had visible bars.

Port the same auto-log heuristic ranked-bar-chart already uses: when
max/min > 50, switch to base-10 log projection so each row gets a
proportional, distinguishable position. Footer flags 'log scale' so
the reader knows when it kicks in.

Same component is shared by every bench in distribution view, so this
fixes l1-finality, l2-block-time, validator-yield, perp-fees and any
other bench with wide dynamic range in one shot.
fix(distribution): auto log scale when dynamic range > 50x
Narrow-range benches with small absolute minimums collapse every median
dot into a single sliver at the left. solana-tx-landing-latency is the
canonical case: 5 providers all have p50 = 2 slots on a 14-slot field,
so every median lands at 14 % of the track and there is no visible
spread between the leaders.

Switch both linear and log scale to use fieldMin as the left baseline.
The leader now sits at 0 % and laggards spread across the full track.
Footer always shows 'min X' so the reader knows the chart is relative
to observed range, not absolute zero.
fix(distribution): anchor left edge at fieldMin, not zero
scrub deploy IDs and team scope from public workflow
GMGN's WebSocket pushes Solana chain-tip events (channel=chain_stat, gk='s', rs=ms:slot) sub-second. Adds it as the 4th provider on the head-lag bench.

YAML:
- New provider entry; queries deliberately omit chain= so per-tab filters auto-hide GMGN on Base/BNB and surface it on All/Solana.
- Methodology + cardinality lines updated.

Harness sync (matches private mobula-api/miniapps/aggregator-head-lag):
- gmgn_monitor.go: chromedp cf_clearance mint + utls HelloChrome_120 ClientHello (h1-only ALPN) + WS subscribe + slot-event parser.
- Dockerfile: chromium + minimal X/font libs for chromedp.
- go.mod: utls + chromedp deps.
- log_buffer.go, config.go, main.go: GMGN_PROXY env + startup banner + goroutine launch.

Validated: bun run validate, typecheck, spec tests all green.
feat(bench-001): add GMGN as a provider (Solana-only) + sync harness
scrub slack webhook and grafana URL from public repo
Flotapponnier and others added 24 commits June 1, 2026 21:18
… tab swap (#251)

The Chart child component used `key={seriesKey}` where seriesKey only
encoded range + region. When the parent swapped seriesOverride via a
metric panel tab click, lines useMemo did recompute (override added to
deps) but the Chart child's internal state (drawn paths, slicedLines)
kept the prior render cached. Adding the active panel label to the key
forces a clean remount on tab swap.
…ogy, faq for v2 pipeline (#252)

Rewrites the bench documentation to describe the local hl-node fills
stream rather than the deprecated daily CSV bucket. The methodology
list now covers all 9 metrics actually emitted (effective fee, fees
per user, price deviation, last fill age, fills per minute, taker
share, per asset top three, plus the heartbeat and rolling window
mechanics). FAQ entries that referenced the CSV URL or the old
frontend list (OKX, GMGN, Dexterity, KGEN, ASXN) updated to match
the current builders.json (Phantom, Axiom, pvp.trade, Insilico,
DefiApp, MetaMask, Dexari, Okto). Source URL points at the new
miniapps/hyperliquid-frontends-local harness.

No em dashes anywhere in prose per content guideline. All character
caps respected.
…#253)

Audit-driven cleanup verified to have zero visible impact on the site.

Deletes (confirmed zero imports across src/):
- src/components/benchmark-table.tsx (201 LOC, never imported)
- src/lib/methodology-tooltip.ts (37 LOC, helper never wired up)
- src/lib/utils.ts (cn() helper, never called)
- CURRENT_ISSUE and ISSUE_DATE_LONG exports in site.ts

Lint cleanups:
- Drop three stale eslint-disable directives (apple-icon, icon,
  benchmarks/[slug]/page) for rules that no longer fire
- Fix two unescaped apostrophes in mcp/page.tsx
- Remove unused activeTemplate variable in share-section.tsx
- Drop padB / padR from a useMemo deps array in time-series-chart.tsx
  where they were never read in the closure

Kept on purpose despite audit suggestions:
- .card CSS class (used 5x by card / live / benchmark-grid / body)
- --color-accent-soft and --color-banner-* tokens (used by Tailwind
  utilities in benchmark-grid, view-switcher, home-bench-table,
  site-banner)
- GithubIcon custom SVG (lucide-react dropped its GitHub brand mark)
- Static three.js import on the 3D logo (replacing with next/dynamic
  re-introduces the SVG flash that PR #231 deliberately removed)
- Hook-rule and ref-during-render lints in benchmark-body /
  time-series-chart: real refactors, out of scope for a zero-impact
  cleanup, deferred to a follow-up

Verified: pnpm typecheck clean, pnpm build green.
User reports the banner leaves a phantom gap in Telegram WebView even
once dismissed (localStorage doesn't always persist in in-app browsers,
and the wrapper's padding still measures even when the banner returns
null). Drop the component, drop the import, drop the spacer's banner-
related comment + the now-irrelevant initial height estimate.
This time I greped every file myself instead of trusting agents.

Deletes (zero usages confirmed across src/):
- src/components/live-dashboard.tsx — 6-line re-export shim; inlined the
  import in app/page.tsx so the shim has nothing left to redirect.
- src/lib/brand.ts: brandIsDark() — never called anywhere.
- src/lib/live/format.ts: fmtAge() — never called. live-indicator.tsx
  has its own formatAge() with day handling that fmtAge lacks, so they
  weren't an actual duplicate either.
- src/components/chain-coverage-chip.tsx: leaderChains(),
  perChainRankSegments(), chainLabelFor(), chainLeader() — exported but
  never imported AND never called from within the same file. TypeScript
  noUnusedLocals confirms they were stranded.

Visibility tightened:
- src/lib/brand.ts: isLight() now non-exported (only used by
  chipTextColor in the same file).

Drive-by cleanup that fell out:
- Dropped ProviderResult import in chain-coverage-chip.tsx (only the
  deleted helpers used it).

Verified clean: pnpm typecheck + pnpm tsc --noEmit --noUnusedLocals
--noUnusedParameters + pnpm build all pass. Net: -79 lines.
…bView (#259)

User reports a 1-2 px gap at the top of the header in Telegram in-app
Safari that lets page content peek through during scroll. Root cause:
body had overflow-x: clip (PR #242 safety net) and WebKit treats clip
on body as creating a containing block for position: fixed descendants.
The fixed header was then anchored to body's top edge, not the viewport,
and momentum scroll desynced it from the URL-bar animation, producing
the visible slit.

Move the overflow-x clip safety net to <html> only. <main> and <article>
already carry overflow-x-clip (PR #244) so page-level horizontal overflow
remains contained without needing it on body. Drop the translate3d hint
on the header — it was paired with the clip workaround and is not needed
once fixed positions cleanly against the viewport.
…g) (#262)

Web search confirmed user is not alone. WebKit bug 297779 reports that
on iOS 26 Safari + WKWebView (Telegram in-app browser, Chrome iOS), any
position: fixed element drifts 10-24 px when scroll direction reverses,
exposing the page under the header through a thin gap. Mastodon and
LinkedIn ship the same symptom. Apple acknowledged the bug, partially
fixed it in iOS 26.1 but residual reports persist into Dec 2025.

position: sticky uses a different render path in WebKit that does not
trip the jitter heuristic. It is also simpler:
- no spacer div needed (the element stays in normal flow)
- no useRef + ResizeObserver to keep the spacer in sync
- no headerH state

Net: -25 lines on top of fixing the cosmetic gap. Desktop and standalone
Safari behavior are identical, sticky just renders more reliably in
WebViews.

Refs:
- https://bugs.webkit.org/show_bug.cgi?id=297779
- mastodon/mastodon#36144
- TelegramMessenger/Telegram-iOS#1748
)

* fix: switch header to position: sticky (iOS 26 WebKit fixed jitter bug)

Web search confirmed user is not alone. WebKit bug 297779 reports that
on iOS 26 Safari + WKWebView (Telegram in-app browser, Chrome iOS), any
position: fixed element drifts 10-24 px when scroll direction reverses,
exposing the page under the header through a thin gap. Mastodon and
LinkedIn ship the same symptom. Apple acknowledged the bug, partially
fixed it in iOS 26.1 but residual reports persist into Dec 2025.

position: sticky uses a different render path in WebKit that does not
trip the jitter heuristic. It is also simpler:
- no spacer div needed (the element stays in normal flow)
- no useRef + ResizeObserver to keep the spacer in sync
- no headerH state

Net: -25 lines on top of fixing the cosmetic gap. Desktop and standalone
Safari behavior are identical, sticky just renders more reliably in
WebViews.

Refs:
- https://bugs.webkit.org/show_bug.cgi?id=297779
- mastodon/mastodon#36144
- TelegramMessenger/Telegram-iOS#1748

* ranked-bar+ledger: add Top-N selector and drop unscored rows

* ledger+ranked-bar: drop rows with zero headline value across p50/p90/p99
position: sticky and position: fixed both jitter 10-24 px on iOS 26 when
scroll direction changes (bugs.webkit.org/297779). Apple acknowledged
the bug, partial fix in 26.1, residual reports into late 2025. Mastodon
and LinkedIn ship the same symptom and concluded it is unfixable from
the site side.

Mitigation: keep sticky only on md+ where the desktop render path is
clean. On mobile the header stays in normal flow, scrolls away with the
page, and the jitter cannot appear because nothing is positioned. Same
pattern as most mobile sites — pull to top to see the nav.

Single class change: `sticky top-0` -> `relative md:sticky md:top-0`.
…ws (#268)

Previous PR (#267) dropped sticky on all mobile to dodge the iOS 26
WebKit jitter bug. Overkill — the symptom only manifests visibly inside
in-app WebViews (Telegram, Instagram, Facebook, Twitter, TikTok) where
the host's own URL-bar overlay animates on top of WebKit's misposition.
Regular mobile Safari and Chrome iOS render sticky cleanly enough for
end users.

Mechanism:
- Inline script in layout.tsx head detects iOS WebView via UA (no
  `Safari/` token on an iOS device = WKWebView in-app host) and adds
  the `ios-webview` class on <html> before React hydrates.
- globals.css scopes a non-sticky override to that class on the site
  header at < md viewports.
- site-header.tsx exposes a stable identifier class (`site-header-root`)
  and stays sticky-top-0 by default everywhere else.

No flash on first paint because the class lands during the same render
tick as the dark-mode detection script next to it. Build + typecheck
clean.
…bution, donut) (#269)

* feat(bench): network fees — current native transfer cost USD across 11 L1 chains

* chart: Top-N selector on all 4 chart views via shared hook+component
* feat(bench): network fees — current native transfer cost USD across 11 L1 chains

* chart: Top-N selector on all 4 chart views via shared hook+component

* wallet-labels-coverage: drop All chains aggregate tab
@Flotapponnier
Flotapponnier merged commit de9289b into main Jun 2, 2026
1 check failed
Flotapponnier added a commit that referenced this pull request Jun 4, 2026
…tely) (#301)

PR #277 'Feat/network fees l2 toggle' was mis-named and ended up sweeping every dev change into main on 2026-06-02 (233 files, 9k+ line delta). Reverts the full PR to restore the previous prod surface; a follow-up PR will cherry-pick only the network-fees bench + its deps back into main.
@Flotapponnier
Flotapponnier deleted the feat/network-fees-l2-toggle branch June 18, 2026 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant