Skip to content

Commit

Permalink
Peter/fix dex volumes query (#1608)
Browse files Browse the repository at this point in the history
* chore: update monetary to latest 0.7.3

* fix(pools): update hook to return data on per pool basis
  • Loading branch information
peterslany authored Nov 22, 2023
1 parent d8af913 commit 9d98dd5
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 181 deletions.
6 changes: 3 additions & 3 deletions src/components/PoolsTable/PoolsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -82,7 +82,7 @@ const PoolsTable = ({ variant, pools, onRowAction, title }: PoolsTableProps): JS
// TODO: revert alignItems prop when `sevenDayVolume` is adressed
const totalLiquidity = <Cell label={formatUSD(totalLiquidityUSD, { compact: true })} alignItems='flex-start' />;

const total7DayVolumeUSD = getDexTotalVolumeUSD(pooledCurrencies.map((pooled) => pooled.currency.ticker));
const total7DayVolumeUSD = getDexVolumeByPool(data);
const total7DayVolumeLabel = formatUSD(total7DayVolumeUSD, { compact: true });
const sevenDayVolume = (
<Cell label={total7DayVolumeLabel} alignItems={isAccountPools ? 'flex-start' : 'flex-end'} />
Expand All @@ -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 (
Expand Down
167 changes: 57 additions & 110 deletions src/hooks/api/use-get-dex-volume.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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<CurrencyExt>;
usd: number;
type DexVolumesData = Record<string, Big>;

type UseGetCurrenciesResult = UseQueryResult<DexVolumesData> & {
getDexVolumeByPool: (pool: LiquidityPool | undefined) => number;
};

type DexVolumesData = Record<string, DexCurrencyVolume>;
const getVolumes = (
volumes: any,
dataId: string,
getCurrencyFromSquidFormat: (currencySquid: CurrencySquidFormat) => CurrencyExt
): Array<MonetaryAmount<CurrencyExt>> => {
const startVolumes = volumes[`${dataId}__startVolumes`];
const endVolumes = volumes[`${dataId}__endVolumes`];
if (startVolumes.length === 0 || endVolumes.length === 0) {
return [];
}

type UseGetCurrenciesResult = UseQueryResult<DexVolumesData> & {
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<DexVolumesData> => {
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({
Expand All @@ -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 };
69 changes: 3 additions & 66 deletions src/hooks/api/use-get-pools-trading-apr.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<LiquidityPool>): 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,
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Swap/components/SwapLiquidity/SwapLiquidity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

2 comments on commit 9d98dd5

@vercel
Copy link

@vercel vercel bot commented on 9d98dd5 Nov 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 9d98dd5 Nov 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.