diff --git a/balancer-js/examples/pools/bpt-price.ts b/balancer-js/examples/pools/bpt-price.ts index 58a4aebc2..c8d338746 100644 --- a/balancer-js/examples/pools/bpt-price.ts +++ b/balancer-js/examples/pools/bpt-price.ts @@ -3,6 +3,10 @@ import { BalancerSDK } from '@balancer-labs/sdk'; const sdk = new BalancerSDK({ network: 1, rpcUrl: 'https://rpc.ankr.com/eth', + coingecko: { + coingeckoApiKey: 'CG-ViHyrfvtLz2WSCJzm59TfGow', + isDemoApiKey: true, + }, }); const bptPriceExample = async () => { diff --git a/balancer-js/src/modules/data/index.ts b/balancer-js/src/modules/data/index.ts index d63de8f45..a4f506e68 100644 --- a/balancer-js/src/modules/data/index.ts +++ b/balancer-js/src/modules/data/index.ts @@ -20,6 +20,7 @@ import { BalancerNetworkConfig, BalancerDataRepositories, GraphQLQuery, + CoingeckoConfig, } from '@/types'; import { PoolsSubgraphRepository } from './pool/subgraph'; import { SubgraphPoolDataService } from '../sor/pool-data/subgraphPoolDataService'; @@ -75,7 +76,8 @@ export class Data implements BalancerDataRepositories { networkConfig: BalancerNetworkConfig, provider: Provider, contracts: Contracts, - subgraphQuery?: GraphQLQuery + subgraphQuery?: GraphQLQuery, + coingecko?: CoingeckoConfig ) { this.pools = new PoolsSubgraphRepository({ url: networkConfig.urls.subgraph, @@ -167,7 +169,8 @@ export class Data implements BalancerDataRepositories { const coingeckoRepository = new CoingeckoPriceRepository( tokenAddresses, - networkConfig.chainId + networkConfig.chainId, + coingecko ); const subgraphPriceRepository = new SubgraphPriceRepository( @@ -187,7 +190,7 @@ export class Data implements BalancerDataRepositories { ); const coingeckoHistoricalRepository = - new CoingeckoHistoricalPriceRepository(networkConfig.chainId); + new CoingeckoHistoricalPriceRepository(networkConfig.chainId, coingecko); this.tokenHistoricalPrices = new HistoricalPriceProvider( coingeckoHistoricalRepository, diff --git a/balancer-js/src/modules/data/token-prices/coingecko-historical.ts b/balancer-js/src/modules/data/token-prices/coingecko-historical.ts index 4d7c3abf4..c574c826a 100644 --- a/balancer-js/src/modules/data/token-prices/coingecko-historical.ts +++ b/balancer-js/src/modules/data/token-prices/coingecko-historical.ts @@ -5,6 +5,7 @@ import { TokenPrices, Network, HistoricalPrices, + CoingeckoConfig, } from '@/types'; import axios, { AxiosError } from 'axios'; import { tokenAddressForPricing } from '@/lib/utils'; @@ -18,11 +19,15 @@ export class CoingeckoHistoricalPriceRepository implements Findable { prices: TokenPrices = {}; nativePrice?: Promise; urlBase: string; + apiKey?: string; - constructor(private chainId: Network = 1) { - this.urlBase = `https://api.coingecko.com/api/v3/coins/${this.platform( + constructor(private chainId: Network = 1, coingecko?: CoingeckoConfig) { + this.urlBase = `https://${ + coingecko?.coingeckoApiKey && !coingecko.isDemoApiKey ? 'pro-' : '' + }api.coingecko.com/api/v3/coins/${this.platform( chainId )}/contract/%TOKEN_ADDRESS%/market_chart/range?vs_currency=usd`; + this.apiKey = coingecko?.coingeckoApiKey; } private async fetch( @@ -33,7 +38,10 @@ export class CoingeckoHistoricalPriceRepository implements Findable { const url = this.urlRange(address, timestamp); console.time(`fetching coingecko historical for ${address}`); try { - const { data } = await axios.get(url, { signal }); + const { data } = await axios.get(url, { + signal, + headers: { 'x-cg-pro-api-key': this.apiKey ?? '' }, + }); console.timeEnd(`fetching coingecko historical for ${address}`); console.log(data); return data; diff --git a/balancer-js/src/modules/data/token-prices/coingecko.ts b/balancer-js/src/modules/data/token-prices/coingecko.ts index 865b649c5..4dcd700b1 100644 --- a/balancer-js/src/modules/data/token-prices/coingecko.ts +++ b/balancer-js/src/modules/data/token-prices/coingecko.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ -import { Findable, Network, Price, TokenPrices } from '@/types'; +import { CoingeckoConfig, Findable, Network, Price, TokenPrices } from '@/types'; import axios, { AxiosError } from 'axios'; import { TOKENS } from '@/lib/constants/tokens'; import { Debouncer, tokenAddressForPricing } from '@/lib/utils'; @@ -13,16 +13,22 @@ export class CoingeckoPriceRepository implements Findable { urlBase: string; baseTokenAddresses: string[]; debouncer: Debouncer; + apiKey?: string; - constructor(tokenAddresses: string[], private chainId: Network = 1) { + constructor( + tokenAddresses: string[], + private chainId: Network = 1, + coingecko?: CoingeckoConfig + ) { this.baseTokenAddresses = tokenAddresses.map(tokenAddressForPricing); this.urlBase = `https://api.coingecko.com/api/v3/simple/token_price/${this.platform( chainId )}?vs_currencies=usd,eth`; + this.apiKey = coingecko?.coingeckoApiKey; this.debouncer = new Debouncer( this.fetch.bind(this), 200, - 10 + coingecko?.tokensPerPriceRequest ?? 10 ); } @@ -33,6 +39,7 @@ export class CoingeckoPriceRepository implements Findable { try { const { data } = await axios.get(this.url(addresses), { signal, + headers: { ApiKey: this.apiKey ?? '' }, }); return data; } catch (error) { diff --git a/balancer-js/src/modules/sdk.module.ts b/balancer-js/src/modules/sdk.module.ts index a99c6b9f9..30418c46d 100644 --- a/balancer-js/src/modules/sdk.module.ts +++ b/balancer-js/src/modules/sdk.module.ts @@ -59,7 +59,8 @@ export class BalancerSDK implements BalancerSDKRoot { this.networkConfig, sor.provider, this.balancerContracts, - config.subgraphQuery + config.subgraphQuery, + config.coingecko ); this.swaps = new Swaps(this.config); diff --git a/balancer-js/src/types.ts b/balancer-js/src/types.ts index 8953e693e..b6ec8ba16 100644 --- a/balancer-js/src/types.ts +++ b/balancer-js/src/types.ts @@ -45,6 +45,7 @@ export interface BalancerSdkConfig { sor?: Partial; tenderly?: BalancerTenderlyConfig; enableLogging?: boolean; + coingecko?: CoingeckoConfig; } export interface BalancerTenderlyConfig { @@ -460,3 +461,9 @@ export interface GraphQLQuery { // eslint-disable-next-line @typescript-eslint/no-explicit-any attrs: any; } + +export type CoingeckoConfig = { + coingeckoApiKey: string; + tokensPerPriceRequest?: number; + isDemoApiKey?: boolean; +};