Skip to content

Add Epoch 1000 validator edition page#1677

Open
Jotatavo wants to merge 3 commits into
solana-foundation:mainfrom
Jotatavo:feat/epoch1000-validator-edition
Open

Add Epoch 1000 validator edition page#1677
Jotatavo wants to merge 3 commits into
solana-foundation:mainfrom
Jotatavo:feat/epoch1000-validator-edition

Conversation

@Jotatavo

Copy link
Copy Markdown
Contributor

Introduce /epoch1000/validator with vote account lookup via Trillium, validator survivor cards with logo support, and wallet/validator edition nav.

Summary

  • Adds /epoch1000/validator for validator vote account checks
  • Uses Trillium API (sw_first_epoch_with_stake) for first validating epoch
  • Generates shareable validator cards with logo and custom OG copy
  • Adds "wallet | Validator Edition" navigation on epoch1000 pages

Introduce /epoch1000/validator with vote account lookup via Trillium, validator survivor cards with logo support, and wallet/validator edition nav.
@vercel

vercel Bot commented Jul 10, 2026

Copy link
Copy Markdown

@Jotatavo is attempting to deploy a commit to the Solana Foundation Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds the /epoch1000/validator feature — a vote-account lookup page that calls the Trillium API, generates shareable validator survivor cards with logo support, and adds a "wallet | Validator Edition" navigation bar to both epoch1000 pages. It also addresses the previously flagged SSRF, unbounded response body, and unsafe-cast issues from earlier review rounds.

  • New validator flow: POST /api/epoch1000/validator/check validates the address, rate-limits, deduplicates in-flight Trillium requests via a two-layer cache, and returns a structured payload including tier, epochs survived, and an optional logo URL.
  • OG image upgrade: og/route.tsx gains a validator variant that fetches the logo from an allowlisted host (trillium.so only), enforces a 512 KB stream cap, and caches up to 64 results per instance.
  • Shareable card page: /epoch1000/validator/card renders a tier-colored card with OG metadata derived from search params, mirroring the existing wallet card pattern.

Confidence Score: 5/5

Safe to merge; the new validator flow is well-bounded with address validation, rate limiting, an SSRF allowlist, and a size-capped streaming reader.

The previously flagged SSRF, unbounded download, and unsafe-cast issues have all been addressed. The remaining notes are confined to the OG image route and neither can cause incorrect validator data to be returned or user-facing errors to escape silently.

apps/web/src/app/api/epoch1000/og/route.tsx — stream cancellation and content-type validation in readLimitedResponseBody and getRemoteImageDataUrl.

Important Files Changed

Filename Overview
apps/web/src/app/api/epoch1000/og/route.tsx Adds validator OG card variant with remote logo fetching; now includes allowlist, size cap, and LRU eviction. Two minor issues: stream not cancelled on size-limit hit, and remote content-type not validated before embedding in data URL.
apps/web/src/app/api/epoch1000/validator/check/route.ts New POST route for validator vote-account lookup; correctly validates address, applies rate limiting, deduplicates in-flight requests via hot cache, and returns structured payload with tier info.
apps/web/src/lib/epoch1000/vote-account.ts New Trillium API integration; addresses the previous Array.isArray safety concern and gracefully handles 404/non-array responses.
apps/web/src/lib/epoch1000/validator-cache.ts Two-layer cache (in-process hot cache + Next.js unstable_cache) with TTL, pending-promise deduplication, size-bounded eviction, and a test-reset helper. Logic is correct.
apps/web/src/components/epoch1000/ValidatorChecker.tsx Client-side validator checker component; uses i18n for checker strings. window.location.origin is safely guarded by the result ternary and never accessed during SSR.
apps/web/src/components/epoch1000/ValidatorEpoch1000Experience.tsx New validator landing page experience; mirrors the wallet experience pattern.
apps/web/src/app/[locale]/epoch1000/validator/page.tsx New validator landing page with full metadata/OG setup and edition nav; straightforward server component.
apps/web/src/app/[locale]/epoch1000/validator/card/page.tsx New shareable validator card page; correctly generates OG metadata from search params and renders tier-colored card.
apps/web/src/components/epoch1000/Epoch1000EditionNav.tsx New wallet/validator edition nav component; clean, receives labels as props, uses proper accessible nav landmark.
apps/web/src/lib/epoch1000/card-params.ts Adds logoUrl field to CheckResult and CardVariant type; cardParams now emits k=validator and vl params for the validator variant.
packages/i18n/messages/web/en/common.json Adds all validator-edition i18n keys under epoch1000.validator; page, checker, card, OG, and tier strings are complete and consistent with wallet-edition structure.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant ValidatorChecker as ValidatorChecker (client)
    participant CheckRoute as POST /api/epoch1000/validator/check
    participant HotCache as In-process cache
    participant NextCache as unstable_cache
    participant Trillium as Trillium API
    participant OGRoute as GET /api/epoch1000/og

    User->>ValidatorChecker: Enter vote account
    ValidatorChecker->>CheckRoute: POST voteAccount
    CheckRoute->>CheckRoute: Validate Solana address
    CheckRoute->>HotCache: getHotValidatorFirstTransaction
    alt Cache hit
        HotCache-->>CheckRoute: Promise ValidatorLookup
    else Cache miss
        CheckRoute->>CheckRoute: Apply rate limit
        CheckRoute->>NextCache: getCachedValidatorFirstTransaction
        NextCache->>Trillium: GET /validator_rewards/voteAccount
        Trillium-->>NextCache: array of epoch rows with icon_url
        NextCache-->>HotCache: Settle and store
        NextCache-->>CheckRoute: ValidatorLookup
    end
    CheckRoute->>CheckRoute: buildValidatorLookupPayload
    CheckRoute-->>ValidatorChecker: epochsSurvived firstEpoch tier logoUrl
    ValidatorChecker->>OGRoute: "GET /api/epoch1000/og?k=validator&vl=logoUrl"
    OGRoute->>OGRoute: Validate vl URL allowlist trillium.so HTTPS only
    OGRoute->>Trillium: GET logoUrl up to 512 KB
    Trillium-->>OGRoute: image bytes
    OGRoute-->>ValidatorChecker: PNG card image
    ValidatorChecker-->>User: Show card with share copy PNG buttons
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant ValidatorChecker as ValidatorChecker (client)
    participant CheckRoute as POST /api/epoch1000/validator/check
    participant HotCache as In-process cache
    participant NextCache as unstable_cache
    participant Trillium as Trillium API
    participant OGRoute as GET /api/epoch1000/og

    User->>ValidatorChecker: Enter vote account
    ValidatorChecker->>CheckRoute: POST voteAccount
    CheckRoute->>CheckRoute: Validate Solana address
    CheckRoute->>HotCache: getHotValidatorFirstTransaction
    alt Cache hit
        HotCache-->>CheckRoute: Promise ValidatorLookup
    else Cache miss
        CheckRoute->>CheckRoute: Apply rate limit
        CheckRoute->>NextCache: getCachedValidatorFirstTransaction
        NextCache->>Trillium: GET /validator_rewards/voteAccount
        Trillium-->>NextCache: array of epoch rows with icon_url
        NextCache-->>HotCache: Settle and store
        NextCache-->>CheckRoute: ValidatorLookup
    end
    CheckRoute->>CheckRoute: buildValidatorLookupPayload
    CheckRoute-->>ValidatorChecker: epochsSurvived firstEpoch tier logoUrl
    ValidatorChecker->>OGRoute: "GET /api/epoch1000/og?k=validator&vl=logoUrl"
    OGRoute->>OGRoute: Validate vl URL allowlist trillium.so HTTPS only
    OGRoute->>Trillium: GET logoUrl up to 512 KB
    Trillium-->>OGRoute: image bytes
    OGRoute-->>ValidatorChecker: PNG card image
    ValidatorChecker-->>User: Show card with share copy PNG buttons
Loading

Reviews (3): Last reviewed commit: "fix(epoch1000): restrict validator logo ..." | Re-trigger Greptile

Comment thread apps/web/src/lib/epoch1000/vote-account.ts Outdated
- Fix Trillium lookup when sw_first_epoch_with_stake is missing on latest epoch row

- Add Array.isArray guard on Trillium API response

- Harden OG validator logo fetch with HTTPS host allowlist and cache cap

- Move ValidatorChecker strings to i18n
Comment thread apps/web/src/app/api/epoch1000/og/route.tsx
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