Skip to content

Commit

Permalink
feat(warpMonitor): Use coingecko api key for value monitoring (#4787)
Browse files Browse the repository at this point in the history
### Description

- Fetching coingecko api from GCP secrets and suing with CoinGecko
Client
- Using coingecko-api-v3 package to support passing API keys 

### Drive-By Changes

- Rename eclipse warp route config files and add `tokenCoinGeckoId`

### Testing

Manual
  • Loading branch information
Mo-Hussain authored Nov 5, 2024
1 parent 0772863 commit 7b3b079
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 51 deletions.
5 changes: 5 additions & 0 deletions .changeset/honest-experts-promise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': minor
---

Support using apiKey for CoinGeckoTokenPriceGetter
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ data:
type: collateral
hypAddress: stride1pvtesu3ve7qn7ctll2x495mrqf2ysp6fws68grvcu6f7n2ajghgsh2jdj6
tokenAddress: ibc/BF3B4F53F3694B66E13C23107C84B6485BD2B96296BB7EC680EA77BBA75B4801
tokenCoinGeckoId: celestia
name: Celestia
symbol: TIA
decimals: 6
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ data:
type: collateral
hypAddress: stride134axwdlam929m3mar3wv95nvkyep7mr87ravkqcpf8dfe3v0pjlqwrw6ee
tokenAddress: 'stutia'
tokenCoinGeckoId: stride-staked-tia
name: Stride Staked TIA
symbol: stTIA
decimals: 6
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ spec:
update-on-redeploy: "{{ now }}"
data:
GCP_SECRET_OVERRIDES_ENABLED: "true"
GCP_SECRET_OVERRIDE_{{ $.Values.hyperlane.runEnv | upper }}_COINGECKO_API_KEY: {{ printf "'{{ .%s_coingecko_api_key | toString }}'" .Values.hyperlane.runEnv }}
{{/*
* For each network, create an environment variable with the RPC endpoint.
* The templating of external-secrets will use the data section below to know how
Expand All @@ -30,9 +31,9 @@ spec:
GCP_SECRET_OVERRIDE_{{ $.Values.hyperlane.runEnv | upper }}_RPC_ENDPOINTS_{{ . | upper }}: {{ printf "'{{ .%s_rpcs | toString }}'" . }}
{{- end }}
data:
- secretKey: deployer_key
- secretKey: {{ printf "%s_coingecko_api_key" .Values.hyperlane.runEnv }}
remoteRef:
key: {{ printf "hyperlane-%s-key-deployer" .Values.hyperlane.runEnv }}
key: {{ printf "%s-coingecko-api-key" .Values.hyperlane.runEnv }}
{{/*
* For each network, load the secret in GCP secret manager with the form: environment-rpc-endpoint-network,
* and associate it with the secret key networkname_rpc.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import {
rootLogger,
} from '@hyperlane-xyz/utils';

import { DeployEnvironment } from '../../src/config/environment.js';
import { fetchGCPSecret } from '../../src/utils/gcloud.js';
import { startMetricsServer } from '../../src/utils/metrics.js';
import { readYaml } from '../../src/utils/utils.js';
import { getArgs } from '../agent-utils.js';
Expand Down Expand Up @@ -636,8 +638,10 @@ async function checkWarpRouteMetrics(
tokenConfig: WarpRouteConfig,
chainMetadata: ChainMap<ChainMetadata>,
) {
const tokenPriceGetter =
CoinGeckoTokenPriceGetter.withDefaultCoinGecko(chainMetadata);
const tokenPriceGetter = CoinGeckoTokenPriceGetter.withDefaultCoinGecko(
chainMetadata,
await getCoinGeckoApiKey(),
);

setInterval(async () => {
try {
Expand Down Expand Up @@ -672,4 +676,22 @@ async function checkWarpRouteMetrics(
}, checkFrequency);
}

async function getCoinGeckoApiKey(): Promise<string | undefined> {
const environment: DeployEnvironment = 'mainnet3';
let apiKey: string | undefined;
try {
apiKey = (await fetchGCPSecret(
`${environment}-coingecko-api-key`,
false,
)) as string;
} catch (e) {
logger.error(
'Error fetching CoinGecko API key, proceeding with public tier',
e,
);
}

return apiKey;
}

main().then(logger.info).catch(logger.error);
3 changes: 1 addition & 2 deletions typescript/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@
"@safe-global/safe-deployments": "1.37.8",
"@solana/spl-token": "^0.3.8",
"@solana/web3.js": "^1.78.0",
"@types/coingecko-api": "^1.0.10",
"@wagmi/chains": "^1.8.0",
"bignumber.js": "^9.1.1",
"coingecko-api": "^1.0.10",
"coingecko-api-v3": "^0.0.29",
"cosmjs-types": "^0.9.0",
"cross-fetch": "^3.1.5",
"ethers": "^5.7.2",
Expand Down
34 changes: 14 additions & 20 deletions typescript/sdk/src/gas/token-prices.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import CoinGecko from 'coingecko-api';
import { CoinGeckoClient, SimplePriceResponse } from 'coingecko-api-v3';

import { rootLogger, sleep } from '@hyperlane-xyz/utils';

Expand All @@ -10,12 +10,11 @@ export interface TokenPriceGetter {
getTokenExchangeRate(base: ChainName, quote: ChainName): Promise<number>;
}

export type CoinGeckoInterface = Pick<CoinGecko, 'simple'>;
export type CoinGeckoSimpleInterface = CoinGecko['simple'];
export type CoinGeckoSimplePriceParams = Parameters<
CoinGeckoSimpleInterface['price']
>[0];
export type CoinGeckoResponse = ReturnType<CoinGeckoSimpleInterface['price']>;
export type CoinGeckoInterface = Pick<CoinGeckoClient, 'simplePrice'>;
export type CoinGeckoSimplePriceInterface = CoinGeckoClient['simplePrice'];
export type CoinGeckoSimplePriceParams =
Parameters<CoinGeckoSimplePriceInterface>[0];
export type CoinGeckoResponse = ReturnType<CoinGeckoSimplePriceInterface>;

type TokenPriceCacheEntry = {
price: number;
Expand Down Expand Up @@ -85,10 +84,11 @@ export class CoinGeckoTokenPriceGetter implements TokenPriceGetter {

static withDefaultCoinGecko(
chainMetadata: ChainMap<ChainMetadata>,
apiKey?: string,
expirySeconds?: number,
sleepMsBetweenRequests = 5000,
): CoinGeckoTokenPriceGetter {
const coinGecko = new CoinGecko();
const coinGecko = new CoinGeckoClient(undefined, apiKey);
return new CoinGeckoTokenPriceGetter(
coinGecko,
chainMetadata,
Expand Down Expand Up @@ -153,20 +153,14 @@ export class CoinGeckoTokenPriceGetter implements TokenPriceGetter {
await sleep(this.sleepMsBetweenRequests);

if (toQuery.length > 0) {
let response: any;
let response: SimplePriceResponse;
try {
response = await this.coinGecko.simple.price({
ids: toQuery,
vs_currencies: [currency],
response = await this.coinGecko.simplePrice({
ids: toQuery.join(','),
vs_currencies: currency,
});

if (response.success === true) {
const prices = toQuery.map((id) => response.data[id][currency]);
toQuery.map((id, i) => this.cache.put(id, prices[i]));
} else {
rootLogger.warn('Failed to query token prices', response.message);
return undefined;
}
const prices = toQuery.map((id) => response[id][currency]);
toQuery.map((id, i) => this.cache.put(id, prices[i]));
} catch (e) {
rootLogger.warn('Error when querying token prices', e);
return undefined;
Expand Down
21 changes: 9 additions & 12 deletions typescript/sdk/src/test/MockCoinGecko.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { SimplePriceResponse } from 'coingecko-api-v3';

import type {
CoinGeckoInterface,
CoinGeckoResponse,
CoinGeckoSimpleInterface,
CoinGeckoSimplePriceInterface,
CoinGeckoSimplePriceParams,
} from '../gas/token-prices.js';
import type { ChainName } from '../types.js';
Expand All @@ -18,26 +20,21 @@ export class MockCoinGecko implements CoinGeckoInterface {
this.fail = {};
}

price(params: CoinGeckoSimplePriceParams): CoinGeckoResponse {
const data: any = {};
for (const id of params.ids) {
price(input: CoinGeckoSimplePriceParams): CoinGeckoResponse {
const data: SimplePriceResponse = {};
for (const id of input.ids) {
if (this.fail[id]) {
return Promise.reject(`Failed to fetch price for ${id}`);
}
data[id] = {
usd: this.tokenPrices[id],
};
}
return Promise.resolve({
success: true,
message: '',
code: 200,
data,
});
return Promise.resolve(data);
}

get simple(): CoinGeckoSimpleInterface {
return this;
get simplePrice(): CoinGeckoSimplePriceInterface {
return this.price;
}

setTokenPrice(chain: ChainName, price: number): void {
Expand Down
27 changes: 14 additions & 13 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8066,7 +8066,6 @@ __metadata:
"@safe-global/safe-deployments": "npm:1.37.8"
"@solana/spl-token": "npm:^0.3.8"
"@solana/web3.js": "npm:^1.78.0"
"@types/coingecko-api": "npm:^1.0.10"
"@types/mocha": "npm:^10.0.1"
"@types/node": "npm:^16.9.1"
"@types/sinon": "npm:^17.0.1"
Expand All @@ -8075,7 +8074,7 @@ __metadata:
"@wagmi/chains": "npm:^1.8.0"
bignumber.js: "npm:^9.1.1"
chai: "npm:4.5.0"
coingecko-api: "npm:^1.0.10"
coingecko-api-v3: "npm:^0.0.29"
cosmjs-types: "npm:^0.9.0"
cross-fetch: "npm:^3.1.5"
dotenv: "npm:^10.0.0"
Expand Down Expand Up @@ -13160,13 +13159,6 @@ __metadata:
languageName: node
linkType: hard

"@types/coingecko-api@npm:^1.0.10":
version: 1.0.10
resolution: "@types/coingecko-api@npm:1.0.10"
checksum: 2523f946e6d293c2ee94a0abee624f53c34b4643f8df685d0164509aba66e8234276e5d8c202c514551024757f0987f7062daa7428ccaf6673bad9a5c55779a2
languageName: node
linkType: hard

"@types/concat-stream@npm:^1.6.0":
version: 1.6.1
resolution: "@types/concat-stream@npm:1.6.1"
Expand Down Expand Up @@ -16754,10 +16746,12 @@ __metadata:
languageName: node
linkType: hard

"coingecko-api@npm:^1.0.10":
version: 1.0.10
resolution: "coingecko-api@npm:1.0.10"
checksum: e0000df5aebbeee508f25824485fe8e4be57cd07825b3cfbf2dc3c51b646200eefd336c833e81747d4a209bf10c32019baef1070fb2bfbcdbae099420954d1fa
"coingecko-api-v3@npm:^0.0.29":
version: 0.0.29
resolution: "coingecko-api-v3@npm:0.0.29"
dependencies:
https: "npm:^1.0.0"
checksum: e60a0996472419232a144ec77028c060bd9c289f799dd40d46dbb7229cff3d868a3e35bf88724059dc25767b8136d794789e4dd31711592fa73a7be1ca2fcbc7
languageName: node
linkType: hard

Expand Down Expand Up @@ -21651,6 +21645,13 @@ __metadata:
languageName: node
linkType: hard

"https@npm:^1.0.0":
version: 1.0.0
resolution: "https@npm:1.0.0"
checksum: ccea8a8363a018d4b241db7748cff3a85c9f5b71bf80639e9c37dc6823f590f35dda098b80b726930e9f945387c8bfd6b1461df25cab5bf65a31903d81875b5d
languageName: node
linkType: hard

"human-id@npm:^1.0.2":
version: 1.0.2
resolution: "human-id@npm:1.0.2"
Expand Down

0 comments on commit 7b3b079

Please sign in to comment.