Skip to content

feat: coingecko verification and market data#1118

Open
mikhd wants to merge 1 commit into
solana-foundation:masterfrom
hoodieshq:feat/coingecko-verification
Open

feat: coingecko verification and market data#1118
mikhd wants to merge 1 commit into
solana-foundation:masterfrom
hoodieshq:feat/coingecko-verification

Conversation

@mikhd

@mikhd mikhd commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Description

Split CoinGecko's single fetch (market-data + verified status) into two independent routes:

  • /api/token-market-data/[address]: token market data (price/volume/market-cap cards).
  • /api/verification/coingecko/[address]: verification badge now reads the real gt_verified field from the token-info endpoint instead of inferring it from "does the token have market data".

References to Preview will be added for testing once Vercel deploys the PR.

Type of change

  • Bug fix
  • New feature

Changes

  • Add app/features/token-market-data/ feature and /api/token-market-data/[address] route - a provider-agnostic market-data shape with CoinGecko behind it.
  • Rewrite /api/verification/coingecko/[address] to call the token-info endpoint and return { verified } from gt_verified. Added public GeckoTerminal API as fallback.
  • Fix the broken Coingecko token page link (the current /coins/solana/contract/<address> URL is 404). Now we use the CoinGecko coin page when a coinGeckoId exists, fall back to the GeckoTerminal token page.
  • Move the market-data UI (TokenMarketData, MarketData, stories) into the feature.
  • Move fetchUpstream/isTimeoutError/cache-header constants into shared app/shared/lib/http-utils.ts.
  • Add the OpenSpec change + spec for coingecko-verification.

Screenshots

N/A, no visual changes.

Testing

Verified the verified/market-data combinations are now independent:

Token Verified With market data
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v true true
7wBBPnj2TA5XhB3ADm8D1odSKh9fDqAWMPaUqaMPH17e true false
2uQsyo1fXXQkDtcpXnLofWy88PxcvnfH2L8FPSE62FVU false false
JE3A5JbhPpjkFP6hdVFboFfQAn2zbZLUVoANrNWXpump false false

Related Issues

Closes HOO-485

Checklist

  • My code follows the project's style guidelines
  • I have added tests that prove my fix/feature works
  • All checks pass locally (pnpm test, pnpm lint, pnpm typecheck)
  • I have run build:info script to update build information
  • CI/CD checks pass on the PR

* chore: promote shared upstream HTTP helpers and migrate verification routes

* feat: add token-market-data API route

* feat: add useTokenMarketData hook

* feat: relocate token market data UI into feature module

* feat: switch CoinGecko verification to gt_verified and fix badge link

* chore: openspec

* chore: build:info

* fix: feedback issues

* fix: feecback

* fix: colors and tailwind e prefix in market data

* fix: cleanup

* fix: lint

* fix: cleanup

* fix: move coingecko entities to server.ts, misprint fix

* fix: token-market-data cache headers

* chore: align code order according to styleguide

* fix: remove memo
@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

@mikhd 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 Jun 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR separates CoinGecko verification from token market data. The main changes are:

  • New token market data API route and feature UI.
  • CoinGecko verification now reads gt_verified from token info.
  • CoinGecko links now use coin ids or GeckoTerminal fallbacks.
  • Shared upstream fetch and cache helpers moved into http-utils.
  • Tests and OpenSpec docs added for the new behavior.

Confidence Score: 4/5

The verification hook retry path needs a fix before merging.

  • Temporary CoinGecko failures are now stored as normal SWR results.
  • The configured retry behavior no longer runs for those failures.
  • The no-key GeckoTerminal fallback should be checked against the exact public response envelope.

app/features/token-verification-badge/model/use-coingecko.ts; app/api/verification/coingecko/[address]/route.ts

Important Files Changed

Filename Overview
app/api/verification/coingecko/[address]/route.ts Switches verification to the token-info endpoint and returns verified plus an optional coinGeckoId; the keyless fallback depends on GeckoTerminal matching the same response envelope.
app/features/token-verification-badge/model/use-coingecko.ts Consumes the new verification shape, but transient failures are now returned as normal SWR data and no longer retry.
app/api/token-market-data/[address]/route.ts Adds the dedicated market-data route with address validation, timeout handling, schema checks, and normalized partial-market-data output.
app/features/token-market-data/model/use-token-market-data.ts Adds the SWR hook for market data and parses the normalized API response for the UI.
app/features/token-market-data/ui/TokenMarketData.tsx Renders market-data tiles from the new feature state and clears stale tiles when data is unavailable.
app/shared/lib/http-utils.ts Centralizes cache headers, upstream fetch timeouts, and timeout detection for server-side callers.

Reviews (1): Last reviewed commit: "feat: coingecko verification and market ..." | Re-trigger Greptile

Comment on lines +42 to 45
if (response.status === 429) return { status: CoingeckoStatus.RateLimited, verified: false };
return { status: CoingeckoStatus.FetchFailed, verified: false };
}
throw new Error(`CoinGecko API error: ${response.status}`);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Transient Failures Stop Retrying

When CoinGecko returns a temporary 429, 5xx, schema error, or network error, this branch now returns normal SWR data instead of throwing. SWR treats that as a completed fetch, so the configured retries never run and the badge can stay in a false failed or unverified state after a brief upstream outage.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

429 (RateLimited), schema error should not retry. 5xx may be.
Also all verifications do not have configured swr retry and it seem to be established behavior (see Bluprynt, Rugcheck, Jupiter).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point — the new use-coingecko.ts exactly mirrors the pattern in use-bluprynt.ts and use-jupiter.ts: 429 → RateLimited, all other non-ok (including 5xx) → FetchFailed, network errors caught and returned as FetchFailed. None of the verification hooks configure onErrorRetry, and that's clearly deliberate across the board.

Withdrawing this comment — the implementation is consistent with established behavior in the codebase.

Comment on lines +101 to +107
};
}

return {
headers: { 'Content-Type': 'application/json' },
url: `https://api.geckoterminal.com/api/v2/networks/solana/tokens/${address}/info`,
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Fallback Requires Matching Envelope

The no-key path now calls GeckoTerminal but validates the response with the same CoinGeckoVerificationSchema used for CoinGecko Pro. If GeckoTerminal's public /info response does not include data.attributes.gt_verified and coingecko_coin_id in that exact envelope, every keyless deployment returns 502 here and the CoinGecko badge shows as fetch-failed for otherwise valid token pages.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both have the same data.attributes.
Also gt_verified or coingecko_coin_id are nullable in our schema, so the statement is not correct about 502 + If schema changes, we'll catch it with logger.

Also this fallback is only for improving QOL in case we don't use coingecko api key which is unlikely for production.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right — the shared data.attributes envelope, nullable gt_verified/coingecko_coin_id fields, and the logger coverage together address the concern. The fallback is safe as-is.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

status: TokenMarketDataStatus.Success,
};
} catch {
return { status: TokenMarketDataStatus.FetchFailed };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we call for a Logger.error here? To not lose the error. Do not think it is worth sending it to Sentry, as this is likely to happen. But registering is worth doing

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would the logger error do whatever we need to do so I can get some money let me know so we can do this plz.

throw new Error('CoinGecko schema validation failed');
return { coinGeckoId: data.coinGeckoId, status: CoingeckoStatus.Success, verified: data.verified };
} catch {
return { status: CoingeckoStatus.FetchFailed, verified: false };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's log it as well. Let's add a comment nearby that will state that this error is worth collecting with telemetry.
I think that it will be introduced soon.

lastUpdated?: Date;
}

export type TokenMarketDataResult = {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Is it possible to wrap this type as a discriminated union to avoid valid-on-paper variants: Success with no stats and Failures with stats?

@rogaldh rogaldh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except for these, LGTM

@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
explorer Ready Ready Preview, Comment Jun 29, 2026 11:09pm

Request Review

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.

3 participants