Skip to content

feat: prioritize Jupiter Price API V3 for token price fetching with fallbacks#1

Merged
Hebx merged 19 commits intofix/wallet-price-fallback-sourcesfrom
feat/jupiter-price-api-integration
Nov 21, 2025
Merged

feat: prioritize Jupiter Price API V3 for token price fetching with fallbacks#1
Hebx merged 19 commits intofix/wallet-price-fallback-sourcesfrom
feat/jupiter-price-api-integration

Conversation

@Hebx
Copy link
Owner

@Hebx Hebx commented Nov 14, 2025

Prioritized Token Price Fetching with Jupiter Price API V3

Description

This PR implements a prioritized price fetching system for wallet token holdings, prioritizing Jupiter's Price API V3 for real-time Solana token prices, with intelligent fallbacks to CoinGecko and Birdeye APIs.

Type of Change

  • New feature (non-breaking change which adds functionality)
  • Enhancement (improves existing functionality)

What's Changed

🚀 New Features

1. Jupiter Price API V3 Integration

  • Batch Price Fetching: Implemented fetchTokenPricesFromJupiter() to fetch prices for multiple tokens in a single API call
  • Dedicated Price Endpoint: Uses Jupiter's dedicated /price/v3 endpoint instead of swap quote API
    • Lite tier: https://lite-api.jup.ag/price/v3 (no API key required)
    • Pro tier: https://api.jup.ag/price/v3 (with API key)
  • Efficient: Reduces API calls from N (one per token) to 1 (batch request)

2. Prioritized Fallback Chain

Implemented intelligent fallback system with three tiers:

  1. Jupiter Price API V3 (Priority 1) - Real-time DEX prices, most accurate for Solana tokens
  2. CoinGecko API (Priority 2) - Reliable fallback for tokens Jupiter doesn't have
  3. Birdeye API (Priority 3) - Final fallback for remaining tokens

3. Arbitrary Token Support

  • Extended price fetching beyond SOL to support all SPL tokens
  • Added fetchTokenPriceFromCoinGecko() for arbitrary Solana tokens
  • Special handling for SOL (uses CoinGecko ID-based API)

🔧 Improvements

Enhanced Logging

  • Detailed logging at each step of the price fetching process
  • Tracks which tokens are found/missing at each fallback tier
  • Logs API responses and errors for debugging
  • Clear indicators of which price source was used for each token

Better Error Handling

  • Graceful handling when Jupiter doesn't have prices (expected for low-liquidity/new tokens)
  • Proper error handling for rate limits (Birdeye 429 errors)
  • Fallback to hardcoded prices for stablecoins (USDC, USDT)

Response Format Fix

  • Fixed Jupiter Price API V3 response parsing
    • Response is directly the data object (not wrapped in { data: {...} })
    • Price field is usdPrice (not price)

Technical Details

API Endpoints Used

  1. Jupiter Price API V3

    • Endpoint: GET /price/v3?ids=token1,token2,token3
    • Response: { [mintAddress]: { usdPrice: number, blockId: number, decimals: number, priceChange24h: number } }
    • Reference: Jupiter Price API V3 Docs
  2. CoinGecko API

    • Endpoint: GET /api/v3/simple/token_price/solana?contract_addresses={address}&vs_currencies=usd
    • Special case: SOL uses ID-based endpoint (/simple/price?ids=solana)
  3. Birdeye API (existing, unchanged)

    • Endpoint: GET /defi/v3/token/market-data/multiple?list_address={addresses}

Performance Improvements

  • Before: N API calls (one per token) to Birdeye
  • After: 1 batch call to Jupiter + fallbacks only for missing tokens
  • Result: Faster price fetching, especially for wallets with many tokens

Why Jupiter First?

  1. Real-time accuracy: Prices derived from actual DEX swap transactions
  2. Solana-native: Optimized for Solana ecosystem tokens
  3. Efficient: Batch API supports multiple tokens in one request
  4. Free tier available: No API key required for basic usage

Fallback Rationale

  • CoinGecko: Reliable for established tokens, good coverage
  • Birdeye: Comprehensive Solana token coverage, but rate-limited
  • Hardcoded: Stablecoins (USDC, USDT) always ~$1.00

Testing

Tested Scenarios

✅ SOL price fetching (Jupiter → CoinGecko fallback)
✅ USDC price fetching (Jupiter → hardcoded fallback)
✅ Multiple tokens batch request
✅ Tokens not in Jupiter (fallback to CoinGecko/Birdeye)
✅ Rate-limited Birdeye (graceful degradation)
✅ Response format parsing (usdPrice field)

Breaking Changes

None - this is a non-breaking enhancement. Existing functionality remains unchanged, with improved price accuracy and performance.

Migration Notes

No migration required. The changes are backward compatible and automatically improve price fetching for all wallet holdings.


Note

Prioritizes Jupiter Price API V3 for wallet pricing with batch requests and fallbacks to CoinGecko/Birdeye, adds tests, improves env handling, and streamlines CI/CD and release tagging with version bumps.

  • Backend (wallet pricing):
    • Jupiter Price API V3 integration: Batch fetch via price/v3 with fetchTokenPricesFromJupiter and single-token wrappers; supports arbitrary SPL tokens and SOL.
    • Prioritized fallbacks: Jupiter → CoinGecko → Birdeye, plus stablecoin hardcoded prices; stricter price validation and detailed logging.
    • Route updates: Refactor apps/server/src/routes/wallet/holdings.ts to use new pricing flow and enrich holdings.
    • Env handling: Load .env without overriding CI vars in apps/server/src/server.ts and src/lib/supabase.ts, with clearer missing-var errors.
    • Tests: Add unit/integration tests for Jupiter Price API V3 and fallback logic in __tests__/jupiter-price-api-v3.test.ts and __tests__/holdings-price-fallback.test.ts.
  • CI/CD:
    • Deploy: Simplify Vercel production deploy to a single npx vercel deploy step in .github/workflows/deploy-vercel-production.yml.
    • Release (Changesets): Gate tag creation on CHANGELOG.md updates; create tag to trigger Vercel deploy and GitHub release.
    • Release: Use tag as release name in .github/workflows/release.yml.
    • Tests workflow: Add secret validation, set GRID_ENV, improve server health checks, and artifact uploads.
  • Versioning:
    • Bump versions to 0.1.1 and add CHANGELOGs for apps/client, apps/server, and packages/shared.

Written by Cursor Bugbot for commit 5332a2a. This will update automatically on new commits. Configure here.

Hebx added 2 commits November 21, 2025 02:48
…allback chain

- Integrate Jupiter Price API V3 for efficient batch price fetching
- Implement prioritized fallback chain: Jupiter → CoinGecko → Birdeye
- Add support for arbitrary token price fetching (not just SOL)
- Fix response parsing to handle Jupiter API V3 format (usdPrice field)
- Add comprehensive logging for debugging price fetch failures
- Improve error handling and fallback logic

This ensures we get the most accurate real-time prices from Jupiter first,
with reliable fallbacks for tokens Jupiter doesn't have prices for.
- Add tests for batch price fetching with Jupiter Price API V3
- Add tests for prioritized fallback chain (Jupiter -> CoinGecko -> Birdeye)
- Add tests for arbitrary token price fetching from CoinGecko
- Add tests for response format validation (usdPrice field)
- Add tests for error handling and performance optimizations
- Verify batch request efficiency vs individual requests
@Hebx Hebx force-pushed the feat/jupiter-price-api-integration branch from f0ecaf3 to 8dd09b0 Compare November 21, 2025 01:50
@github-actions
Copy link

✅ Changeset Detected

Thanks for adding a changeset! This change will be included in the next release.

Hebx and others added 10 commits November 21, 2025 02:53
- Fix hasApiKey check from !process.env.JUPITER_API_KEY to !!process.env.JUPITER_API_KEY
- Update test to conditionally check for correct endpoint based on API key presence
- Test now correctly verifies lite-api.jup.ag when no key, api.jup.ag when key is set

Fixes test failure where inverted logic caused wrong endpoint to be tested
* chore: version packages

* chore: clean up changelog and remove AI review artifacts

- Remove PR darkresearch#92 reference, update to darkresearch#110
- Add missing PRs to changelog: darkresearch#102, darkresearch#104, darkresearch#105
- Remove AI-generated review markdown files
- Add proper PR attributions throughout

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Bot <bot@example.com>
- Detect version bumps by checking if CHANGELOG.md was updated
- Automatically create and push git tag
- This triggers Vercel deployment and GitHub release workflows
- No more manual tag creation needed
…ases

- Changes release title from 'Release 0.1.1' to 'v0.1.1'
- More concise and matches standard versioning conventions
- Install bun dependencies before Vercel build
- Add required environment variables for Expo build
- Should fix 'spawn sh ENOENT' error
- Replace manual Vercel CLI commands with vercel-action
- Build using standard Expo export process
- Should fix 'spawn sh ENOENT' error
- Simplifies deployment workflow
- Fix tag auto-creation to detect CHANGELOG updates correctly
- Simplify Vercel deployment to use platform builds (avoids spawn sh errors)
- Only deploy on releases (tags), not every main commit
- Remove pre-build steps, let Vercel handle building
- Use ./apps/client path instead of cd into directory
- Prevents path doubling issue in Vercel CLI
- Add GRID_ENV: production to both integration and E2E test jobs
- Add debug step to verify environment variables are set before server starts
- Improve error messages with better logging when server fails to start
- This should fix backend server startup failures in GitHub Actions

The debug step will help identify if secrets are missing or empty,
which was causing the server to crash immediately on startup.
- Remove path argument, let Vercel project settings define root directory
- Vercel project is configured with apps/client as root
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Hebx and others added 2 commits November 21, 2025 03:45
- Fix: Call fetchTokenPricesWithFallbacks instead of fetchMarketDataWithFallbacks
  This ensures Jupiter Price API V3 is prioritized as intended (Jupiter -> CoinGecko -> Birdeye)
- Fix: Add isFinite check to price validation to prevent Infinity values
  This matches the test expectations and prevents calculation errors downstream

Fixes the bug where the new Jupiter-first implementation was never called,
and ensures price validation properly rejects Infinity values.
- Remove pre-build step and --build-env flags
- Vercel will use environment variables from project settings
- This ensures EXPO_PUBLIC_BACKEND_API_URL is available during Expo build
- Fixes localhost:3001 being used in production
Hebx added 5 commits November 21, 2025 03:55
- Add CI-aware error messages in supabase.ts that detect GitHub Actions context
- Configure dotenv to not override existing env vars (respects GitHub Actions secrets)
- Add early validation checks in workflow before starting server
- Improve error messages to help debug missing environment variables
The test was validating Jupiter's old swap/v1 endpoint, but the
implementation now uses the price/v3 endpoint. Updated all endpoint
references and validation logic to match the actual implementation:

- Changed endpoint URLs from swap/v1 to price/v3
- Updated test descriptions to reference Price API V3
- Replaced outAmount validation with usdPrice validation
- Added test for batch request URL construction with ids parameter
- Updated fallback chain description to mention Price API V3

This ensures the test validates the actual production code and will
catch regressions in the Jupiter Price API V3 integration.
Add isFinite() validation to prevent Infinity and -Infinity values
from passing price validation checks. This fixes calculation errors
downstream when computing token values.

Fixed validation points:
- CoinGecko SOL price validation
- CoinGecko token price validation
- Jupiter prices in result map
- CoinGecko prices in result map
- Birdeye prices in fallback chain
- Birdeye prices in market data fetch
- SOL price from fallbacks

All price validations now follow the pattern:
typeof price === 'number' && isFinite(price) && price > 0

This matches the test expectations in holdings-price-fallback.test.ts
which explicitly tests for isFinite validation (line 71, 80).
- Add 'Validate required secrets' step in integration-tests and e2e-tests jobs
- Check if GitHub secrets exist before attempting to start server
- Provide clear error messages with instructions when secrets are missing
- Fail fast with helpful guidance instead of generic environment variable errors

This prevents the server from attempting to start with missing credentials
and provides actionable error messages pointing to where secrets should be
configured in GitHub Actions.
@Hebx Hebx merged commit fa719d1 into fix/wallet-price-fallback-sources Nov 21, 2025
1 check passed
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.

2 participants