diff --git a/package.json b/package.json index 1bceed0..4b33caa 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@chakra-ui/react": "^2.10.3", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", + "@lukemorales/query-key-factory": "^1.3.4", "@shapeshiftoss/caip": "^8.15.0", "@shapeshiftoss/types": "^8.6.0", "@tanstack/react-query": "^5.65.1", diff --git a/src/queries/chainflip/assets.ts b/src/queries/chainflip/assets.ts index 91831ee..de6db1e 100644 --- a/src/queries/chainflip/assets.ts +++ b/src/queries/chainflip/assets.ts @@ -1,5 +1,4 @@ import { useQuery } from '@tanstack/react-query' -import axios from 'axios' import { arbitrumAssetId, btcAssetId, @@ -12,10 +11,9 @@ import { usdtAssetId, } from 'constants/caip' +import { reactQueries } from '../react-queries' import type { ChainflipAssetsResponse } from './types' -const CHAINFLIP_API_URL = import.meta.env.VITE_CHAINFLIP_API_URL - // Map Chainflip internal asset IDs to CAIPs const chainflipToAssetId: Record = { 'btc.btc': btcAssetId, @@ -35,11 +33,7 @@ export const transformChainflipAssets = (data: ChainflipAssetsResponse) => { export const useChainflipAssetsQuery = () => { return useQuery({ - queryKey: ['chainflip', 'assets'], - queryFn: async () => { - const { data } = await axios.get(`${CHAINFLIP_API_URL}/assets`) - return data - }, + ...reactQueries.chainflip.assets, select: transformChainflipAssets, }) } diff --git a/src/queries/chainflip/quote.ts b/src/queries/chainflip/quote.ts index 30ee499..5b76f92 100644 --- a/src/queries/chainflip/quote.ts +++ b/src/queries/chainflip/quote.ts @@ -1,29 +1,10 @@ import { useQuery } from '@tanstack/react-query' -import axios from 'axios' -import type { ChainflipQuote, ChainflipQuoteParams } from './types' - -const CHAINFLIP_API_URL = import.meta.env.VITE_CHAINFLIP_API_URL -const CHAINFLIP_API_KEY = import.meta.env.VITE_CHAINFLIP_API_KEY +import { reactQueries } from '../react-queries' +import type { ChainflipQuoteParams } from './types' export const useChainflipQuoteQuery = (params: ChainflipQuoteParams) => { - const { sourceAsset, destinationAsset, amount, commissionBps } = params - return useQuery({ - queryKey: ['chainflip', 'quote', params], - queryFn: async () => { - const { data } = await axios.get(`${CHAINFLIP_API_URL}/quotes-native`, { - params: { - apiKey: CHAINFLIP_API_KEY, - sourceAsset, - destinationAsset, - amount, - ...(commissionBps && { commissionBps }), - }, - }) - - // TODO(gomes): select best quote based on output amount, since o.g doesn't support multiple quotes - return data[0] - }, + ...reactQueries.chainflip.quote(params), }) } diff --git a/src/queries/chainflip/status.ts b/src/queries/chainflip/status.ts index 7339898..f2b5271 100644 --- a/src/queries/chainflip/status.ts +++ b/src/queries/chainflip/status.ts @@ -1,10 +1,6 @@ import { useQuery } from '@tanstack/react-query' -import axios from 'axios' -import type { ChainflipStatusResponse } from './types' - -const CHAINFLIP_API_URL = import.meta.env.VITE_CHAINFLIP_API_URL -const CHAINFLIP_API_KEY = import.meta.env.VITE_CHAINFLIP_API_KEY +import { reactQueries } from '../react-queries' type ChainflipStatusQueryParams = { swapId: number @@ -13,19 +9,7 @@ type ChainflipStatusQueryParams = { export const useChainflipStatusQuery = ({ swapId, enabled = true }: ChainflipStatusQueryParams) => { return useQuery({ - queryKey: ['chainflip', 'status', swapId], - queryFn: async () => { - const { data } = await axios.get( - `${CHAINFLIP_API_URL}/status-by-id`, - { - params: { - apiKey: CHAINFLIP_API_KEY, - swapId, - }, - }, - ) - return data - }, + ...reactQueries.chainflip.status(swapId), refetchInterval: 15000, enabled, }) diff --git a/src/queries/chainflip/swap.ts b/src/queries/chainflip/swap.ts index 6c05c00..cae8ab1 100644 --- a/src/queries/chainflip/swap.ts +++ b/src/queries/chainflip/swap.ts @@ -1,24 +1,10 @@ import { useQuery } from '@tanstack/react-query' -import axios from 'axios' -import type { ChainflipSwapParams, ChainflipSwapResponse } from './types' - -const CHAINFLIP_API_URL = import.meta.env.VITE_CHAINFLIP_API_URL -const CHAINFLIP_API_KEY = import.meta.env.VITE_CHAINFLIP_API_KEY +import { reactQueries } from '../react-queries' +import type { ChainflipSwapParams } from './types' export const useChainflipSwapQuery = (params: ChainflipSwapParams) => { return useQuery({ - queryKey: ['chainflip', 'swap', params], - queryFn: async () => { - const { data } = await axios.get(`${CHAINFLIP_API_URL}/swap`, { - params: { - apiKey: CHAINFLIP_API_KEY, - ...params, - boostFee: params.maxBoostFee ?? 0, - retryDurationInBlocks: params.retryDurationInBlocks ?? 150, - }, - }) - return data - }, + ...reactQueries.chainflip.swap(params), }) } diff --git a/src/queries/marketData/index.ts b/src/queries/marketData/index.ts index 39ba3fe..57b900c 100644 --- a/src/queries/marketData/index.ts +++ b/src/queries/marketData/index.ts @@ -12,6 +12,7 @@ import { usdtAssetId, } from 'constants/caip' +import { reactQueries } from '../react-queries' import type { CoinGeckoAssetData, MarketData } from './types' const COINGECKO_BASE_URL = 'https://api.proxy.shapeshift.com/api/v1/markets' @@ -56,8 +57,7 @@ export const findByAssetId = async (assetId: string): Promise } export const useMarketDataByAssetIdQuery = (assetId: string) => { - return useQuery({ - queryKey: ['marketData', assetId], - queryFn: () => findByAssetId(assetId), + return useQuery({ + ...reactQueries.marketData.byAssetId(assetId), }) } diff --git a/src/queries/queryKeys.ts b/src/queries/queryKeys.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/queries/react-queries.ts b/src/queries/react-queries.ts new file mode 100644 index 0000000..715792b --- /dev/null +++ b/src/queries/react-queries.ts @@ -0,0 +1,80 @@ +import type { inferQueryKeyStore } from '@lukemorales/query-key-factory' +import { createQueryKeyStore } from '@lukemorales/query-key-factory' +import axios from 'axios' + +import type { + ChainflipAssetsResponse, + ChainflipQuote, + ChainflipQuoteParams, + ChainflipStatusResponse, + ChainflipSwapParams, + ChainflipSwapResponse, +} from './chainflip/types' +import { findByAssetId } from './marketData' + +const CHAINFLIP_API_URL = import.meta.env.VITE_CHAINFLIP_API_URL +const CHAINFLIP_API_KEY = import.meta.env.VITE_CHAINFLIP_API_KEY + +export const reactQueries = createQueryKeyStore({ + chainflip: { + assets: { + queryKey: null, + queryFn: async () => { + const { data } = await axios.get(`${CHAINFLIP_API_URL}/assets`) + return data + }, + }, + quote: (params: ChainflipQuoteParams) => ({ + queryKey: [params], + queryFn: async () => { + const { data } = await axios.get(`${CHAINFLIP_API_URL}/quotes-native`, { + params: { + apiKey: CHAINFLIP_API_KEY, + sourceAsset: params.sourceAsset, + destinationAsset: params.destinationAsset, + amount: params.amount, + ...(params.commissionBps && { commissionBps: params.commissionBps }), + }, + }) + return data[0] + }, + }), + swap: (params: ChainflipSwapParams) => ({ + queryKey: [params], + queryFn: async () => { + const { data } = await axios.get(`${CHAINFLIP_API_URL}/swap`, { + params: { + apiKey: CHAINFLIP_API_KEY, + ...params, + boostFee: params.maxBoostFee ?? 0, + retryDurationInBlocks: params.retryDurationInBlocks ?? 150, + }, + }) + return data + }, + }), + status: (swapId: number) => ({ + queryKey: [swapId], + queryFn: async () => { + const { data } = await axios.get( + `${CHAINFLIP_API_URL}/status-by-id`, + { + params: { + apiKey: CHAINFLIP_API_KEY, + swapId, + }, + }, + ) + return data + }, + }), + }, + marketData: { + byAssetId: (assetId: string) => ({ + queryKey: [assetId], + queryFn: () => findByAssetId(assetId), + }), + }, +}) + +export type QueryKeys = inferQueryKeyStore diff --git a/yarn.lock b/yarn.lock index e761864..714353f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2365,6 +2365,16 @@ __metadata: languageName: node linkType: hard +"@lukemorales/query-key-factory@npm:^1.3.4": + version: 1.3.4 + resolution: "@lukemorales/query-key-factory@npm:1.3.4" + peerDependencies: + "@tanstack/query-core": ">= 4.0.0" + "@tanstack/react-query": ">= 4.0.0" + checksum: 10c0/d4e829aad970c159e3e3d6545f4f1e47d1a02621cd692bc0e13b7cc36861541e205f801d7ab8081ed8b1c8c3fd365483e1656537ef1ab165cb14743b4b1f1d6c + languageName: node + linkType: hard + "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1": version: 5.1.1-v1 resolution: "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1" @@ -7329,6 +7339,7 @@ __metadata: "@chakra-ui/react": "npm:^2.10.3" "@emotion/react": "npm:^11.11.3" "@emotion/styled": "npm:^11.11.0" + "@lukemorales/query-key-factory": "npm:^1.3.4" "@shapeshiftoss/caip": "npm:^8.15.0" "@shapeshiftoss/types": "npm:^8.6.0" "@tanstack/react-query": "npm:^5.65.1"