From 8b9573cdae7d168167cec49cd20c39bd42e16a73 Mon Sep 17 00:00:00 2001 From: lendihop Date: Mon, 22 Jul 2024 10:26:43 +0200 Subject: [PATCH 1/3] load btc exchange rates from coingecko --- src/index.ts | 17 ++++++++++++++++- src/utils/bitcoin.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/utils/bitcoin.ts diff --git a/src/index.ts b/src/index.ts index 8b1d9ff..1213ad1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,7 @@ import { getAliceBobEstimationPayload } from './utils/alice-bob/get-alice-bob-es import { getAliceBobOrderInfo } from './utils/alice-bob/get-alice-bob-order-info'; import { getAliceBobPairInfo } from './utils/alice-bob/get-alice-bob-pair-info'; import { getAliceBobPairsInfo } from './utils/alice-bob/get-alice-bob-pairs-info'; +import { btcExchangeRateProvider } from './utils/bitcoin'; import { CodedError } from './utils/errors'; import { coinGeckoTokens } from './utils/gecko-tokens'; import { getExternalApiErrorPayload, isDefined, isNonEmptyString } from './utils/helpers'; @@ -175,12 +176,16 @@ app.get('/api/abtest', (_, res) => { }); app.get('/api/exchange-rates/tez', makeProviderDataRequestHandler(tezExchangeRateProvider)); +app.get('/api/exchange-rates/btc', makeProviderDataRequestHandler(btcExchangeRateProvider)); app.get('/api/exchange-rates', async (_req, res) => { const tokensExchangeRates = await getExchangeRates(); const { data: tezExchangeRate, error: tezExchangeRateError } = await getProviderStateWithTimeout( tezExchangeRateProvider ); + const { data: btcExchangeRate, error: btcExchangeRateError } = await getProviderStateWithTimeout( + btcExchangeRateProvider + ); if (tezExchangeRateError !== undefined) { return res.status(500).send({ @@ -188,7 +193,17 @@ app.get('/api/exchange-rates', async (_req, res) => { }); } - res.json([...tokensExchangeRates, { exchangeRate: tezExchangeRate.toString() }]); + if (btcExchangeRateError !== undefined) { + return res.status(500).send({ + error: btcExchangeRateError.message + }); + } + + res.json([ + ...tokensExchangeRates, + { tokenAddress: 'tez', exchangeRate: tezExchangeRate.toString() }, + { tokenAddress: 'btc', exchangeRate: btcExchangeRate.toString() } + ]); }); app.get('/api/moonpay-sign', async (_req, res) => { diff --git a/src/utils/bitcoin.ts b/src/utils/bitcoin.ts new file mode 100644 index 0000000..9f9db3d --- /dev/null +++ b/src/utils/bitcoin.ts @@ -0,0 +1,30 @@ +import { AxiosError } from 'axios'; + +import { getMarketsBySymbols } from './coingecko'; +import { isDefined } from './helpers'; +import logger from './logger'; +import SingleQueryDataProvider from './SingleQueryDataProvider'; + +const getBtcExchangeRate = async () => { + try { + const [btcMarket] = await getMarketsBySymbols(['btc']); + + return btcMarket.current_price; + } catch (e) { + if (!(e instanceof AxiosError)) { + logger.error('Request for BTC exchange rate failed with unknown error'); + } else if (isDefined(e.response) && isDefined(e.response.data)) { + logger.error( + `Request for BTC exchange rate failed with status ${e.response.status} and message ${e.response.data}` + ); + } else if (isDefined(e.response) && isDefined(e.response.status)) { + logger.error(`Request for BTC exchange rate failed with status ${e.response.status}`); + } else { + logger.error('Request for BTC exchange rate failed without response'); + } + + throw e; + } +}; + +export const btcExchangeRateProvider = new SingleQueryDataProvider(60000, getBtcExchangeRate); From 23bc09b6c243f81aca8fcaddbc8ec763d5c76ee2 Mon Sep 17 00:00:00 2001 From: lendihop Date: Mon, 22 Jul 2024 14:39:46 +0200 Subject: [PATCH 2/3] fix backwards compatibility / refactor --- src/index.ts | 18 ++---------------- src/utils/bitcoin.ts | 30 ------------------------------ src/utils/coingecko.ts | 34 +++++++++++++++++++++++++++++++++- src/utils/tezos.ts | 29 ----------------------------- src/utils/tokens.ts | 2 +- 5 files changed, 36 insertions(+), 77 deletions(-) delete mode 100644 src/utils/bitcoin.ts diff --git a/src/index.ts b/src/index.ts index 1213ad1..66a1771 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,7 +30,7 @@ import { getAliceBobEstimationPayload } from './utils/alice-bob/get-alice-bob-es import { getAliceBobOrderInfo } from './utils/alice-bob/get-alice-bob-order-info'; import { getAliceBobPairInfo } from './utils/alice-bob/get-alice-bob-pair-info'; import { getAliceBobPairsInfo } from './utils/alice-bob/get-alice-bob-pairs-info'; -import { btcExchangeRateProvider } from './utils/bitcoin'; +import { btcExchangeRateProvider, tezExchangeRateProvider } from './utils/coingecko'; import { CodedError } from './utils/errors'; import { coinGeckoTokens } from './utils/gecko-tokens'; import { getExternalApiErrorPayload, isDefined, isNonEmptyString } from './utils/helpers'; @@ -38,7 +38,6 @@ import logger from './utils/logger'; import { getSignedMoonPayUrl } from './utils/moonpay/get-signed-moonpay-url'; import { getSigningNonce } from './utils/signing-nonce'; import SingleQueryDataProvider from './utils/SingleQueryDataProvider'; -import { tezExchangeRateProvider } from './utils/tezos'; import { getExchangeRates } from './utils/tokens'; const PINO_LOGGER = { @@ -183,9 +182,6 @@ app.get('/api/exchange-rates', async (_req, res) => { const { data: tezExchangeRate, error: tezExchangeRateError } = await getProviderStateWithTimeout( tezExchangeRateProvider ); - const { data: btcExchangeRate, error: btcExchangeRateError } = await getProviderStateWithTimeout( - btcExchangeRateProvider - ); if (tezExchangeRateError !== undefined) { return res.status(500).send({ @@ -193,17 +189,7 @@ app.get('/api/exchange-rates', async (_req, res) => { }); } - if (btcExchangeRateError !== undefined) { - return res.status(500).send({ - error: btcExchangeRateError.message - }); - } - - res.json([ - ...tokensExchangeRates, - { tokenAddress: 'tez', exchangeRate: tezExchangeRate.toString() }, - { tokenAddress: 'btc', exchangeRate: btcExchangeRate.toString() } - ]); + res.json([...tokensExchangeRates, { exchangeRate: tezExchangeRate.toString() }]); }); app.get('/api/moonpay-sign', async (_req, res) => { diff --git a/src/utils/bitcoin.ts b/src/utils/bitcoin.ts deleted file mode 100644 index 9f9db3d..0000000 --- a/src/utils/bitcoin.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { AxiosError } from 'axios'; - -import { getMarketsBySymbols } from './coingecko'; -import { isDefined } from './helpers'; -import logger from './logger'; -import SingleQueryDataProvider from './SingleQueryDataProvider'; - -const getBtcExchangeRate = async () => { - try { - const [btcMarket] = await getMarketsBySymbols(['btc']); - - return btcMarket.current_price; - } catch (e) { - if (!(e instanceof AxiosError)) { - logger.error('Request for BTC exchange rate failed with unknown error'); - } else if (isDefined(e.response) && isDefined(e.response.data)) { - logger.error( - `Request for BTC exchange rate failed with status ${e.response.status} and message ${e.response.data}` - ); - } else if (isDefined(e.response) && isDefined(e.response.status)) { - logger.error(`Request for BTC exchange rate failed with status ${e.response.status}`); - } else { - logger.error('Request for BTC exchange rate failed without response'); - } - - throw e; - } -}; - -export const btcExchangeRateProvider = new SingleQueryDataProvider(60000, getBtcExchangeRate); diff --git a/src/utils/coingecko.ts b/src/utils/coingecko.ts index b4abf9c..f0f30bc 100644 --- a/src/utils/coingecko.ts +++ b/src/utils/coingecko.ts @@ -1,4 +1,7 @@ -import { range } from './helpers'; +import { AxiosError } from 'axios'; + +import { isDefined, range } from './helpers'; +import logger from './logger'; import { makeBuildQueryFn } from './makeBuildQueryFn'; import SingleQueryDataProvider from './SingleQueryDataProvider'; @@ -89,3 +92,32 @@ export const getMarketsBySymbols = async (symbols: string[]) => { return chunks.flat(); }; + +const createCoingeckoExchangeRateProvider = (tokenSymbol: string) => { + const getExchangeRate = async () => { + try { + const [market] = await getMarketsBySymbols([tokenSymbol]); + + return market.current_price; + } catch (e) { + if (!(e instanceof AxiosError)) { + logger.error(`Request for ${tokenSymbol} exchange rate failed with unknown error`); + } else if (isDefined(e.response) && isDefined(e.response.data)) { + logger.error( + `Request for ${tokenSymbol} exchange rate failed with status ${e.response.status} and message ${e.response.data}` + ); + } else if (isDefined(e.response) && isDefined(e.response.status)) { + logger.error(`Request for ${tokenSymbol} exchange rate failed with status ${e.response.status}`); + } else { + logger.error(`Request for ${tokenSymbol} exchange rate failed without response`); + } + + throw e; + } + }; + + return new SingleQueryDataProvider(60000, getExchangeRate); +}; + +export const tezExchangeRateProvider = createCoingeckoExchangeRateProvider('xtz'); +export const btcExchangeRateProvider = createCoingeckoExchangeRateProvider('btc'); diff --git a/src/utils/tezos.ts b/src/utils/tezos.ts index 2d098c6..5613fde 100644 --- a/src/utils/tezos.ts +++ b/src/utils/tezos.ts @@ -1,13 +1,8 @@ import { compose, MichelCodecPacker, Signer, TezosToolkit } from '@taquito/taquito'; import { tzip12 } from '@taquito/tzip12'; import { tzip16 } from '@taquito/tzip16'; -import { AxiosError } from 'axios'; import memoizee from 'memoizee'; -import { getMarketsBySymbols } from './coingecko'; -import { isDefined } from './helpers'; -import logger from './logger'; -import SingleQueryDataProvider from './SingleQueryDataProvider'; import { BcdTokenData } from './tzkt'; const RPC_URL = process.env.RPC_URL ?? 'https://mainnet-node.madfish.solutions'; @@ -54,30 +49,6 @@ export const getStorage = memoizee( { promise: true, maxAge: 30000 } ); -const getTezExchangeRate = async () => { - try { - const [xtzMarket] = await getMarketsBySymbols(['xtz']); - - return xtzMarket.current_price; - } catch (e) { - if (!(e instanceof AxiosError)) { - logger.error('Request for TEZ exchange rate failed with unknown error'); - } else if (isDefined(e.response) && isDefined(e.response.data)) { - logger.error( - `Request for TEZ exchange rate failed with status ${e.response.status} and message ${e.response.data}` - ); - } else if (isDefined(e.response) && isDefined(e.response.status)) { - logger.error(`Request for TEZ exchange rate failed with status ${e.response.status}`); - } else { - logger.error('Request for TEZ exchange rate failed without response'); - } - - throw e; - } -}; - -export const tezExchangeRateProvider = new SingleQueryDataProvider(60000, getTezExchangeRate); - export class MetadataParseError extends Error {} export const getTokenMetadata = memoizee( diff --git a/src/utils/tokens.ts b/src/utils/tokens.ts index c468e6d..64d63df 100644 --- a/src/utils/tokens.ts +++ b/src/utils/tokens.ts @@ -1,10 +1,10 @@ import { BigNumber } from 'bignumber.js'; import { redisClient } from '../redis'; +import { tezExchangeRateProvider } from './coingecko'; import { isDefined } from './helpers'; import logger from './logger'; import SingleQueryDataProvider, { SingleQueryDataProviderState } from './SingleQueryDataProvider'; -import { tezExchangeRateProvider } from './tezos'; import { getThreeRouteExchangeRates, getThreeRouteTokens, From d776eaffcd821001baf216a23c5a3949dc565aeb Mon Sep 17 00:00:00 2001 From: lendihop Date: Mon, 22 Jul 2024 14:42:26 +0200 Subject: [PATCH 3/3] refactor --- src/utils/coingecko.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/utils/coingecko.ts b/src/utils/coingecko.ts index f0f30bc..089a2da 100644 --- a/src/utils/coingecko.ts +++ b/src/utils/coingecko.ts @@ -93,8 +93,8 @@ export const getMarketsBySymbols = async (symbols: string[]) => { return chunks.flat(); }; -const createCoingeckoExchangeRateProvider = (tokenSymbol: string) => { - const getExchangeRate = async () => { +const createCoingeckoExchangeRateProvider = (tokenSymbol: string) => + new SingleQueryDataProvider(60000, async () => { try { const [market] = await getMarketsBySymbols([tokenSymbol]); @@ -114,10 +114,7 @@ const createCoingeckoExchangeRateProvider = (tokenSymbol: string) => { throw e; } - }; - - return new SingleQueryDataProvider(60000, getExchangeRate); -}; + }); export const tezExchangeRateProvider = createCoingeckoExchangeRateProvider('xtz'); export const btcExchangeRateProvider = createCoingeckoExchangeRateProvider('btc');