From 9d98dd56fe7defdbdc217dafc3058af093d98d33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Peter=20Slan=C3=BD?=
<47864599+peterslany@users.noreply.github.com>
Date: Wed, 22 Nov 2023 15:44:55 +0100
Subject: [PATCH] Peter/fix dex volumes query (#1608)
* chore: update monetary to latest 0.7.3
* fix(pools): update hook to return data on per pool basis
---
src/components/PoolsTable/PoolsTable.tsx | 6 +-
src/hooks/api/use-get-dex-volume.tsx | 167 ++++++------------
src/hooks/api/use-get-pools-trading-apr.tsx | 69 +-------
.../SwapLiquidity/SwapLiquidity.tsx | 4 +-
src/services/queries/pools.ts | 61 +++++++
5 files changed, 126 insertions(+), 181 deletions(-)
create mode 100644 src/services/queries/pools.ts
diff --git a/src/components/PoolsTable/PoolsTable.tsx b/src/components/PoolsTable/PoolsTable.tsx
index 01bc23d149..d35b6c5390 100644
--- a/src/components/PoolsTable/PoolsTable.tsx
+++ b/src/components/PoolsTable/PoolsTable.tsx
@@ -41,7 +41,7 @@ const PoolsTable = ({ variant, pools, onRowAction, title }: PoolsTableProps): JS
const { t } = useTranslation();
const prices = useGetPrices();
const titleId = useId();
- const { getDexTotalVolumeUSD } = useGetDexVolumes(DateRangeVolume.D7);
+ const { getDexVolumeByPool } = useGetDexVolumes(DateRangeVolume.D7);
const isAccountPools = variant === 'account-pools';
@@ -82,7 +82,7 @@ const PoolsTable = ({ variant, pools, onRowAction, title }: PoolsTableProps): JS
// TODO: revert alignItems prop when `sevenDayVolume` is adressed
const totalLiquidity = | ;
- const total7DayVolumeUSD = getDexTotalVolumeUSD(pooledCurrencies.map((pooled) => pooled.currency.ticker));
+ const total7DayVolumeUSD = getDexVolumeByPool(data);
const total7DayVolumeLabel = formatUSD(total7DayVolumeUSD, { compact: true });
const sevenDayVolume = (
|
@@ -107,7 +107,7 @@ const PoolsTable = ({ variant, pools, onRowAction, title }: PoolsTableProps): JS
accountLiquidity
};
}),
- [getDexTotalVolumeUSD, isAccountPools, onRowAction, pools, prices, variant]
+ [getDexVolumeByPool, isAccountPools, onRowAction, pools, prices, variant]
);
return (
diff --git a/src/hooks/api/use-get-dex-volume.tsx b/src/hooks/api/use-get-dex-volume.tsx
index 4d494d20f3..ef70121559 100644
--- a/src/hooks/api/use-get-dex-volume.tsx
+++ b/src/hooks/api/use-get-dex-volume.tsx
@@ -1,13 +1,16 @@
-import { CurrencyExt, newMonetaryAmount } from '@interlay/interbtc-api';
+import { CurrencyExt, LiquidityPool, newMonetaryAmount } from '@interlay/interbtc-api';
import { MonetaryAmount } from '@interlay/monetary-js';
+import Big from 'big.js';
import { subDays } from 'date-fns';
-import { gql, GraphQLClient } from 'graphql-request';
+import { GraphQLClient } from 'graphql-request';
import { useCallback } from 'react';
import { useErrorHandler } from 'react-error-boundary';
import { useQuery, UseQueryResult } from 'react-query';
-import { convertMonetaryAmountToValueInUSD } from '@/common/utils/utils';
+import { convertMonetaryAmountToBigUSD } from '@/common/utils/utils';
import { SQUID_URL } from '@/constants';
+import { getPoolDataId, getPoolsVolumesQuery } from '@/services/queries/pools';
+import { CurrencySquidFormat } from '@/types/currency';
import { REFETCH_INTERVAL } from '@/utils/constants/api';
import { getTokenPrice } from '@/utils/helpers/prices';
@@ -21,133 +24,78 @@ const graphQLClient = new GraphQLClient(SQUID_URL, {
}
});
-// TODO: add this to a dedicated schemas folder
-const AMOUNT_FIELDS = gql`
- fragment AmountFields on PooledAmount {
- amount
- amountHuman
- token {
- ... on NativeToken {
- __typename
- token
- }
- ... on ForeignAsset {
- __typename
- asset
- }
- ... on StableLpToken {
- __typename
- poolId
- }
- }
- }
-`;
-
-// TODO: add this to a dedicated schemas folder
-const GET_DEX_VOLUMES = gql`
- ${AMOUNT_FIELDS}
- query poolVolumes($start: DateTime, $end: DateTime) {
- startVolumes: cumulativeDexTradingVolumes(
- limit: 1
- orderBy: tillTimestamp_ASC
- where: { tillTimestamp_gte: $start }
- ) {
- tillTimestamp
- amounts {
- ...AmountFields
- }
- }
- endVolumes: cumulativeDexTradingVolumes(
- limit: 1
- orderBy: tillTimestamp_DESC
- where: { tillTimestamp_lte: $end, tillTimestamp_gte: $start }
- ) {
- tillTimestamp
- amounts {
- ...AmountFields
- }
- }
- }
-`;
-
enum DateRangeVolume {
H24,
D7
}
-type DexCurrencyVolume = {
- amount: MonetaryAmount;
- usd: number;
+type DexVolumesData = Record;
+
+type UseGetCurrenciesResult = UseQueryResult & {
+ getDexVolumeByPool: (pool: LiquidityPool | undefined) => number;
};
-type DexVolumesData = Record;
+const getVolumes = (
+ volumes: any,
+ dataId: string,
+ getCurrencyFromSquidFormat: (currencySquid: CurrencySquidFormat) => CurrencyExt
+): Array> => {
+ const startVolumes = volumes[`${dataId}__startVolumes`];
+ const endVolumes = volumes[`${dataId}__endVolumes`];
+ if (startVolumes.length === 0 || endVolumes.length === 0) {
+ return [];
+ }
-type UseGetCurrenciesResult = UseQueryResult & {
- getDexVolumeByTicker: (ticker: string) => DexCurrencyVolume | undefined;
- getDexTotalVolumeUSD: (tickers: string[]) => number;
+ return startVolumes[0].amounts.map((amount: any, index: number) => {
+ const currency = getCurrencyFromSquidFormat(amount.token);
+ const endAmount = Big(endVolumes[0].amounts[index].amount);
+ const amountDelta = endAmount.sub(Big(amount.amount));
+
+ return newMonetaryAmount(amountDelta, currency);
+ });
};
const useGetDexVolumes = (range: DateRangeVolume): UseGetCurrenciesResult => {
- const { getCurrencyFromTicker, getForeignCurrencyFromId } = useGetCurrencies(true);
- const { getStableLiquidityPoolById } = useGetLiquidityPools();
+ const { getCurrencyFromSquidFormat } = useGetCurrencies(true);
+ const { data: pools } = useGetLiquidityPools();
const prices = useGetPrices();
const getDexVolumes = useCallback(
async (range: DateRangeVolume): Promise => {
+ if (!pools) {
+ return {};
+ }
+
const start = subDays(new Date(), range === DateRangeVolume.D7 ? 7 : 1);
const end = new Date();
- const data = await graphQLClient.request(GET_DEX_VOLUMES, { start, end });
+ const query = getPoolsVolumesQuery(pools);
- if (!data.startVolumes.length || !data.endVolumes.length) {
- return {};
- }
+ const data = await graphQLClient.request(query, { start, end });
- const [startVolumes] = data.startVolumes;
- const [endVolumes] = data.endVolumes;
-
- return startVolumes.amounts.reduce((acc: DexVolumesData, item: any) => {
- let currency: CurrencyExt;
- let endVolume;
-
- switch (item.token.__typename) {
- case 'NativeToken': {
- const { token } = item.token;
- currency = getCurrencyFromTicker(token);
- endVolume = endVolumes.amounts.find((endAmount: any) => endAmount.token.token === token);
- break;
- }
- case 'ForeignAsset': {
- const { asset } = item.token;
- currency = getForeignCurrencyFromId(asset);
- endVolume = endVolumes.amounts.find((endAmount: any) => endAmount.token.asset === asset);
- break;
- }
- case 'StableLpToken': {
- const { poolId } = item.token;
- currency = getStableLiquidityPoolById(poolId).lpToken;
- endVolume = endVolumes.amounts.find((endAmount: any) => endAmount.token.poolId === poolId);
- break;
- }
- default:
- return acc;
- }
+ const result = pools.map((pool: LiquidityPool) => {
+ const dataId = getPoolDataId(pool);
- if (!endVolume) {
- return acc;
+ const volumes = getVolumes(data, dataId, getCurrencyFromSquidFormat);
+ if (volumes.length === 0) {
+ return { [dataId]: Big(0) };
}
- const volumeAmount = newMonetaryAmount(endVolume.amount - item.amount, currency);
+ const totalVolumeInUSD = volumes
+ .reduce(
+ (total, amount) =>
+ total.add(convertMonetaryAmountToBigUSD(amount, getTokenPrice(prices, amount.currency.ticker)?.usd)),
+ Big(0)
+ )
+ // Divide by amount of pooled currencies.
+ .div(pool.pooledCurrencies.length);
- const volume: DexCurrencyVolume = {
- amount: volumeAmount,
- usd: convertMonetaryAmountToValueInUSD(volumeAmount, getTokenPrice(prices, currency.ticker)?.usd) || 0
- };
+ return { [dataId]: totalVolumeInUSD };
+ });
- return { ...acc, [currency.ticker]: volume };
- }, {});
+ return result.reduce((result, pool) => ({ ...result, ...pool }));
},
- [getCurrencyFromTicker, getForeignCurrencyFromId, getStableLiquidityPoolById, prices]
+ [pools, getCurrencyFromSquidFormat, prices]
);
const queryResult = useQuery({
@@ -156,16 +104,15 @@ const useGetDexVolumes = (range: DateRangeVolume): UseGetCurrenciesResult => {
refetchInterval: REFETCH_INTERVAL.MINUTE
});
- const getDexVolumeByTicker = useCallback((ticker: string) => queryResult.data?.[ticker], [queryResult.data]);
-
- const getDexTotalVolumeUSD = useCallback(
- (tickers: string[]) => tickers.reduce((sum, ticker) => sum + (getDexVolumeByTicker(ticker)?.usd || 0), 0),
- [getDexVolumeByTicker]
+ const getDexVolumeByPool = useCallback(
+ (pool: LiquidityPool | undefined) =>
+ queryResult.data && pool ? queryResult.data[getPoolDataId(pool)].toNumber() : 0,
+ [queryResult]
);
useErrorHandler(queryResult.error);
- return { ...queryResult, getDexTotalVolumeUSD, getDexVolumeByTicker };
+ return { ...queryResult, getDexVolumeByPool };
};
export { DateRangeVolume, useGetDexVolumes };
diff --git a/src/hooks/api/use-get-pools-trading-apr.tsx b/src/hooks/api/use-get-pools-trading-apr.tsx
index ba73ace329..80486652c8 100644
--- a/src/hooks/api/use-get-pools-trading-apr.tsx
+++ b/src/hooks/api/use-get-pools-trading-apr.tsx
@@ -1,19 +1,13 @@
-import {
- CurrencyExt,
- isForeignAsset,
- LiquidityPool,
- newMonetaryAmount,
- PooledCurrencies,
- TickerToData
-} from '@interlay/interbtc-api';
+import { CurrencyExt, LiquidityPool, newMonetaryAmount, TickerToData } from '@interlay/interbtc-api';
import { MonetaryAmount } from '@interlay/monetary-js';
import Big from 'big.js';
-import { gql, GraphQLClient } from 'graphql-request';
+import { GraphQLClient } from 'graphql-request';
import { useCallback } from 'react';
import { useQuery } from 'react-query';
import { convertMonetaryAmountToBigUSD } from '@/common/utils/utils';
import { SQUID_URL } from '@/constants';
+import { getPoolDataId, getPoolsVolumesQuery } from '@/services/queries/pools';
import { CurrencySquidFormat } from '@/types/currency';
import { MILLISECONDS_PER_DAY } from '@/utils/constants/date-time';
import { calculateTotalLiquidityUSD } from '@/utils/helpers/pool';
@@ -29,63 +23,6 @@ const graphQLClient = new GraphQLClient(SQUID_URL, {
}
});
-const getPoolDataId = (pool: LiquidityPool): string =>
- `${pool.type}_${pool.pooledCurrencies.map(({ currency }) => currency.ticker).join('_')}`;
-
-const getPooledCurrenciesCondition = (pooledCurrencies: PooledCurrencies) =>
- `${pooledCurrencies
- .map(({ currency }) => {
- const currencyId = isForeignAsset(currency) ? currency.foreignAsset.id.toString() : currency.ticker;
- return `AND: {poolId_contains: "${currencyId}"`;
- })
- .join()}${pooledCurrencies.map((_) => '}').join('')}`;
-
-const getPoolsVolumesQuery = (pools: Array): string => gql`
- fragment AmountFields on PooledAmount {
- amount
- amountHuman
- token {
- ... on NativeToken {
- __typename
- token
- }
- ... on ForeignAsset {
- __typename
- asset
- }
- ... on StableLpToken {
- __typename
- poolId
- }
- }
- }
-
- fragment PoolVolumeFields on CumulativeDexTradingVolumePerPool {
- poolId
- poolType
- tillTimestamp
- amounts {
- ...AmountFields
- }
- }
-
- query poolVolumes($start: DateTime, $end: DateTime) {
- ${pools
- .map((pool: LiquidityPool) => {
- const poolDataId = getPoolDataId(pool);
- const pooledCurrenciesCondition = getPooledCurrenciesCondition(pool.pooledCurrencies);
- return `${poolDataId}__startVolumes: cumulativeDexTradingVolumePerPools(limit: 1, orderBy: tillTimestamp_ASC, where: {tillTimestamp_gte: $start, ${pooledCurrenciesCondition}}) {
- ...PoolVolumeFields
- }
- ${poolDataId}__endVolumes:cumulativeDexTradingVolumePerPools(limit: 1, orderBy: tillTimestamp_DESC, where: {tillTimestamp_lte: $end, ${pooledCurrenciesCondition}}) {
- ...PoolVolumeFields
- }
- `;
- })
- .join('\n')}
- }
-`;
-
const getYearlyVolume = (
volumes: any,
dataId: string,
diff --git a/src/pages/Swap/components/SwapLiquidity/SwapLiquidity.tsx b/src/pages/Swap/components/SwapLiquidity/SwapLiquidity.tsx
index c34b6fab91..eac147c7f6 100644
--- a/src/pages/Swap/components/SwapLiquidity/SwapLiquidity.tsx
+++ b/src/pages/Swap/components/SwapLiquidity/SwapLiquidity.tsx
@@ -18,9 +18,9 @@ type SwapLiquidityProps = Props & InheritAttrs;
const SwapLiquidity = ({ input, output, liquidityPool, ...props }: SwapLiquidityProps): JSX.Element | null => {
const prices = useGetPrices();
- const { getDexTotalVolumeUSD } = useGetDexVolumes(DateRangeVolume.H24);
+ const { getDexVolumeByPool } = useGetDexVolumes(DateRangeVolume.H24);
- const h24Volume = getDexTotalVolumeUSD([input.ticker, output.ticker]);
+ const h24Volume = getDexVolumeByPool(liquidityPool);
const h24VolumeLabel = formatUSD(h24Volume, { compact: true });
const liquidity = liquidityPool && calculateTotalLiquidityUSD(liquidityPool.pooledCurrencies, prices);
diff --git a/src/services/queries/pools.ts b/src/services/queries/pools.ts
new file mode 100644
index 0000000000..fbff466b23
--- /dev/null
+++ b/src/services/queries/pools.ts
@@ -0,0 +1,61 @@
+import { isForeignAsset, LiquidityPool, PooledCurrencies } from '@interlay/interbtc-api';
+import { gql } from 'graphql-request';
+
+const getPoolDataId = (pool: LiquidityPool): string =>
+ `${pool.type}_${pool.pooledCurrencies.map(({ currency }) => currency.ticker).join('_')}`;
+
+const getPooledCurrenciesCondition = (pooledCurrencies: PooledCurrencies) =>
+ `${pooledCurrencies
+ .map(({ currency }) => {
+ const currencyId = isForeignAsset(currency) ? currency.foreignAsset.id.toString() : currency.ticker;
+ return `AND: {poolId_contains: "${currencyId}"`;
+ })
+ .join()}${pooledCurrencies.map((_) => '}').join('')}`;
+
+const getPoolsVolumesQuery = (pools: Array): string => gql`
+ fragment AmountFields on PooledAmount {
+ amount
+ amountHuman
+ token {
+ ... on NativeToken {
+ __typename
+ token
+ }
+ ... on ForeignAsset {
+ __typename
+ asset
+ }
+ ... on StableLpToken {
+ __typename
+ poolId
+ }
+ }
+ }
+
+ fragment PoolVolumeFields on CumulativeDexTradingVolumePerPool {
+ poolId
+ poolType
+ tillTimestamp
+ amounts {
+ ...AmountFields
+ }
+ }
+
+ query poolVolumes($start: DateTime, $end: DateTime) {
+ ${pools
+ .map((pool: LiquidityPool) => {
+ const poolDataId = getPoolDataId(pool);
+ const pooledCurrenciesCondition = getPooledCurrenciesCondition(pool.pooledCurrencies);
+ return `${poolDataId}__startVolumes: cumulativeDexTradingVolumePerPools(limit: 1, orderBy: tillTimestamp_ASC, where: {tillTimestamp_gte: $start, ${pooledCurrenciesCondition}}) {
+ ...PoolVolumeFields
+ }
+ ${poolDataId}__endVolumes:cumulativeDexTradingVolumePerPools(limit: 1, orderBy: tillTimestamp_DESC, where: {tillTimestamp_lte: $end, ${pooledCurrenciesCondition}}) {
+ ...PoolVolumeFields
+ }
+ `;
+ })
+ .join('\n')}
+ }
+`;
+
+export { getPoolDataId, getPoolsVolumesQuery };