Skip to content

Support all coingecko coins in marketstats and v4 fiatrates endpoints#4110

Open
msalcala11 wants to merge 2 commits intobitpay:masterfrom
msalcala11:more-rates
Open

Support all coingecko coins in marketstats and v4 fiatrates endpoints#4110
msalcala11 wants to merge 2 commits intobitpay:masterfrom
msalcala11:more-rates

Conversation

@msalcala11
Copy link
Contributor

@msalcala11 msalcala11 commented Feb 24, 2026

Description

This PR refactors CoinGecko resolution for marketstats and v4/fiatrates so BWS can support all CoinGecko-listed tokens across BitPay-supported chains via deterministic chain + tokenAddress lookup, while preserving DB-cached defaults for the Exchange Rates view.

Changelog

  • Added a shared query parser (coin, chain, tokenAddress) used by both coinGeckoGetMarketStats and coinGeckoGetFiatRates to reduce duplicated parsing logic.
  • Reworked coin resolution to use CoinGecko contract lookup (/v3/coins/{platform}/contract/{address}) when tokenAddress is provided.
  • Restricted chain usage to token lookups and made validation errors explicit (Unsupported chain, tokenAddress requires valid chain, Invalid tokenAddress, etc.).
  • Added token-address format validation through repo helpers (crypto-wallet-core Validation.validateAddress) before making CoinGecko calls.
  • Kept coin-only requests scoped to the default DB-cached set; non-default token requests now require token lookup params.
  • Added request timeout to CoinGecko HTTP calls to reduce hanging upstream requests.
  • Kept DB caching for default coins only; token/non-default lookups bypass DB market/fiat caches.
  • Updated token list normalization to avoid mutating source token objects in-place.
  • Expanded integration tests substantially for token resolution, chain/token validation, cache behavior, alias coverage, and error-path behavior.

Testing Notes


let ids: string[];
let secondary: string | undefined;
for (const id of candidates.slice(0, 10)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

each iteration makes a blocking /v3/coins/{id} request. if the goal is to get the first instance for secondary consider using Promise.all/Promise.allSettled here and picking the first match from the results

Copy link
Contributor Author

@msalcala11 msalcala11 Feb 27, 2026

Choose a reason for hiding this comment

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

As I thought through this, I realized we can remove this block entirely if we require chain and tokenAddress query params for all tokens. Just pushed up a commit to do that.

API_KEY: config.coinGecko.apiKey,
};
if (httpStatusCode === 429 || coinGeckoErrorCode === 429) {
const rateLimitErr: any = new Error('coinGecko rate limit');
Copy link
Contributor

Choose a reason for hiding this comment

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

i think its worth it to keep the rate limit logging

logger.warn('CoinGecko rate limit: %o', { url, httpStatusCode, coinGeckoErrorCode, body });

}
const hasCoinGeckoError = !!(status?.error_code || status?.error_message);
if ((httpStatusCode && httpStatusCode >= 400) || hasCoinGeckoError) {
const cgErr: any = new Error(status?.error_message || body?.status || 'coinGecko error');
Copy link
Contributor

Choose a reason for hiding this comment

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

same thing here with maintaining original logging. and do we want to keep the body field in the error like before?

cgErr.body = body;

try {
chainParam = getQueryString(req.query, 'chain');
} catch {
chainParam = undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a reason to not throw an error here?

try {
chainParam = getQueryString(req.query, 'chain');
} catch {
chainParam = undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

same here. undefined might lead to silent errors

@msalcala11 msalcala11 force-pushed the more-rates branch 3 times, most recently from 1129b7a to 9e835f4 Compare February 28, 2026 05:03
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